You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

122 lines
3.5 KiB

/**
* 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)()