/**
|
|
* Copyright (c) 2018 Niklas Rosenstein
|
|
* 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
|
|
|
|
#include "macros.h"
|
|
|
|
|
|
/**
|
|
* 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
|
|
|
|
|
|
/**
|
|
* This macro puts the specified *expr* as the body of a lambda function
|
|
* and calls that function immediately. This allows you to create a new
|
|
* scope from which you can return and assign the result to a variable.
|
|
*/
|
|
#define NR_EXPR(expr) ([&]() expr)()
|