Browse Source

add macros.h

master
Niklas Rosenstein 3 years ago
commit
417a432ae0
Signed by: NiklasRosenstein GPG Key ID: 06D269B33D25F6C6
1 changed files with 243 additions and 0 deletions
  1. + 243
    - 0
      include/NiklasRosenstein/macros.h

+ 243
- 0
include/NiklasRosenstein/macros.h

@ -0,0 +1,243 @@
/* Copyright (c) 2018 Niklas Rosenstien
* MIT licensed
*
* @description This header provides some useful macros for compiler
* and platform detection, generating compiler-based inline pragmas,
* control-flow and classes.
*/
#pragma once
#include <utility> // std::move
#if !defined(HAVE_TYPE_TRAITS) || HAVE_TYPE_TRAITS
#define NR_MACROS_HAVE_TYPE_TRAITS 1
#include <type_traits>
#else
#define NR_MACROS_HAVE_TYPE_TRAITS 0
#endif
/**
* This macro allows you to create an enclosed scope that can be
* exited with a `break` or `continue` statement.
*
* NR_SCOPE {
* // ...
* if (some_condition()) {
* break;
* }
* // ...
* }
*/
#define NR_SCOPE \
for (bool __nr_break=false; !__nr_break; __nr_break=true)
/**
* This macro allows you to create an enclosed scope that can be
* exited with a `break` or `continue` statement and that will
* only be entered if the #condition evaluates to true.
*
* NR_IF (some_condition()) {
* // do stuff
* if (!some_other_condition()) break;
* // do stuff
* }
*
* Note that you can not use else-if or else-clauses with this macro.
*/
#define NR_IF(condition) \
for (bool __nr_break=false; !__nr_break && (condition); __nr_break=true)
/**
* Use this macro to define a global variable or a static class
* member in a compilation unit instead of writing the actual type
* of the member again.
*
* extern int x;
* NR_DECL(x) = 42;
*
* class Foo { static int y; };
* NR_DECL(Foo::y) = 0;
*/
#define NR_DECL(member) decltype(member) member
/**
* This macro can be used to disallow the copy constructor and copy
* assignment operator of a class. It must be used in the `private:`
* section of a class.
*
* class NonCopiableClass {
* NR_DISALLOW_COPY_AND_ASSIGN(NonCopiableClass);
* public:
* // ...
* };
*/
#define NR_DISALLOW_COPY_AND_ASSIGN(type) \
type(type const&); \
type& operator = (type const&)
/**
* This macro creates a copy assignment operator from an existing copy
* constructor. This is useful to avoid code duplication for copiable
* types.
*
* class CopiableClass {
* public:
* CopiableClass(CopiableClass const& other) { ... }
* NR_OPERATOR_COPY_ASSIGNMENT(CopiableClass)
* };
*/
#define NR_OPERATOR_COPY_ASSIGNMENT(type) \
type& operator = (type const& src) \
{ \
if (this != &src) \
{ \
this->~type(); \
new (this) type(src); \
} \
return *this; \
}
/**
* This macro creates a move assignment operator from an existing move
* constructor. This is useful to avoid code duplication for movable
* types.
*
* class MovableClass {
* public:
* MovableClass(MovableClass&& other) { ... }
* NR_OPERATOR_MOVE_ASSIGNMENT(MovableClass)
* };
*/
#define NR_OPERATOR_MOVE_ASSIGNMENT(type) \
type& operator = (type&& src) \
{ \
if (this != &src) \
{ \
this->~type(); \
new (this) type(std::move(src)); \
} \
return *this; \
}
/**
* Allows you to use template parametrized classes and functions as arguments
* to macros, as otherwise the comma in the template arguments would be treated
* as separators to the macro arguments. Note that this is only needed for
* templates with more than one template argument.
*
* #define SOME_MACRO(type)
* SOME_MACRO(std::vector<int, std::allocator<int>>) // error: macro "SOME_MACRO" passed 2 arguments, but takes just 1
* SOME_MACRO(NR_TYPE_IDENTITY(std::vector<int, std::allocator<int>>))
*/
#define NR_TYPE_IDENTITY(...) niklasrosenstein::detail::__type_identity_helper<void(__VA_ARGS__)>::type
namespace niklasrosenstein {
namespace detail {
template <typename T> struct __type_identity_helper;
template <typename T, typename P> struct __type_identity_helper<T(P)> { typedef P type; };
}
}
#if NR_MACROS_HAVE_TYPE_TRAITS
/**
* Converts a pointer like `T*`, converts the pointer to `T const*`.
* This is useful when implementing non-const/const versions of a
* getter function.
*
* struct foo {
* int const* find_something() const { ...; } // Imagine a long and complex method
* int* find_something() { return const_cast<int*>(NR_MAKE_CONST(this)->get_member()); }
* };
*/
#define NR_MAKE_CONST(ptr) \
static_cast<std::add_const<std::remove_pointer<decltype(ptr)>::type>::type*>(ptr)
#endif
/**
* @macro NR_INLINE_PRAGMA(...)
* @macro NR_INLINE_PRAGMA_CLANG(...)
* @macro NR_INLINE_PRAGMA_GCC(...)
* @macro NR_INLINE_PRAGMA_MSVC(...)
*
* Generate an inline pragma expression that can be used inside macro
* definitions. The macros with the respective compiler name will only
* evaluate to the pragma instruction if the source is compiled with the
* respective compiler.
*/
#if defined(__llvm__) || defined(__clang__) || defined(__GNUC__)
#define NR_INLINE_PRAGMA(...) _Pragma(#__VA_ARGS__)
#if defined(__llvm__) || defined(__clang__)
#define NR_INLINE_PRAGMA_CLANG(...) NR_INLINE_PRAGMA(__VA_ARGS__)
#elif defined(__GNUC__)
#define NR_INLINE_PRAGMA_GCC(...) NR_INLINE_PRAGMA(__VA_ARGS__)
#else
#error "unexpected error"
#endif
#elif defined(_MSC_VER)
#define NR_INLINE_PRAGMA(...) __pragma(__VA_ARGS__)
#define NR_INLINE_PRAGMA_MSVC(...) NR_INLINE_PRAGMA(__VA_ARGS__)
#else
#error "compiler could not be detected"
#endif
#ifndef NR_INLINE_PRAGMA_CLANG
#define NR_INLINE_PRAGMA_CLANG(...)
#endif
#ifndef NR_INLINE_PRAGMA_GCC
#define NR_INLINE_PRAGMA_GCC(...)
#endif
#ifndef NR_INLINE_PRAGMA_MSVC
#define NR_INLINE_PRAGMA_MSVC(...)
#endif
/**
* @macro NR_PLATFORM
* @macro NR_PLATFORM_WINDOWS
* @macro NR_PLATFORM_WINDOWS_64
* @macro NR_PLATFORM_MACOS
* @macro NR_PLATFORM_MACOS_IPHONE
* @macro NR_PLATFORM_MACOS_IPHONE_SIMULATOR
* @macro NR_PLATFORM_LINUX
* @macro NR_PLATFORM_UNIX
* @macro NR_PLATFORM_POSIX
*
* One of these macros is defined depending on the platform that is currently
* compiled for. Some of these macros can be defined both at the same time.
* The only exception is #NR_PLATFORM which is a string identifying the generic
* platorm name.
*/
#if defined(_WIN32)
#define NR_PLATFORM_WINDOWS
#if defined(_WIN64)
#define NR_PLATFORM "windows-x64"
#define NR_PLATFORM_WINDOWS_64
#else
#define NR_PLATFORM "windows-x86"
#endif
#elif defined(__APPLE__)
#define NR_PLATFORM_UNIX
#define NR_PLATFORM_MACOS
#include "TargetConditionals.h"
#if TARGET_IPHONE_SIMULATOR
#define NR_PLATFORM "macos-iphone-simulator"
#define NR_PLATFORM_MACOS_IPHONE
#define NR_PLATFORM_MACOS_IPHONE_SIMULATOR
#elif TARGET_OS_IPHONE
#define NR_PLATFORM "macos-iphone"
#define NR_PLATFORM_MACOS_IPHONE
#elif TARGET_OS_MAC
// Some other kind of Mac OS
#define NR_PLATFORM "macos"
#endif
#elif defined(__linux__) && __linux__
#define NR_PLATFORM "linux"
#define NR_PLATFORM_UNIX
#define NR_PLATFORM_LINUX
#elif defined(__unix__) && __unix__
#define NR_PLATFORM "unix"
#define NR_PLATFORM_UNIX
#elif defined(_POSIX_VERSION)
#define NR_PLATFORM "posix"
#define NR_PLATFORM_POSIX
#elif !defined(NR_PLATFORM)
#warning "Unable to identify this platform, macro NR_PLATFORM stays undefined."
#endif

Loading…
Cancel
Save