307 lines
9.9 KiB
C++
307 lines
9.9 KiB
C++
|
#ifndef _C4_LANGUAGE_HPP_
|
||
|
#define _C4_LANGUAGE_HPP_
|
||
|
|
||
|
/** @file language.hpp Provides language standard information macros and
|
||
|
* compiler agnostic utility macros: namespace facilities, function attributes,
|
||
|
* variable attributes, etc.
|
||
|
* @ingroup basic_headers */
|
||
|
|
||
|
#include "c4/preprocessor.hpp"
|
||
|
#include "c4/compiler.hpp"
|
||
|
|
||
|
/* Detect C++ standard.
|
||
|
* @see http://stackoverflow.com/a/7132549/5875572 */
|
||
|
#ifndef C4_CPP
|
||
|
# if defined(_MSC_VER) && !defined(__clang__)
|
||
|
# if _MSC_VER >= 1910 // >VS2015: VS2017, VS2019
|
||
|
# if (!defined(_MSVC_LANG))
|
||
|
# error _MSVC not defined
|
||
|
# endif
|
||
|
# if _MSVC_LANG >= 201705L
|
||
|
# define C4_CPP 20
|
||
|
# define C4_CPP20
|
||
|
# elif _MSVC_LANG == 201703L
|
||
|
# define C4_CPP 17
|
||
|
# define C4_CPP17
|
||
|
# elif _MSVC_LANG >= 201402L
|
||
|
# define C4_CPP 14
|
||
|
# define C4_CPP14
|
||
|
# elif _MSVC_LANG >= 201103L
|
||
|
# define C4_CPP 11
|
||
|
# define C4_CPP11
|
||
|
# else
|
||
|
# error C++ lesser than C++11 not supported
|
||
|
# endif
|
||
|
# else
|
||
|
# if _MSC_VER == 1900
|
||
|
# define C4_CPP 14 // VS2015 is c++14 https://devblogs.microsoft.com/cppblog/c111417-features-in-vs-2015-rtm/
|
||
|
# define C4_CPP14
|
||
|
# elif _MSC_VER == 1800 // VS2013
|
||
|
# define C4_CPP 11
|
||
|
# define C4_CPP11
|
||
|
# else
|
||
|
# error C++ lesser than C++11 not supported
|
||
|
# endif
|
||
|
# endif
|
||
|
# elif defined(__INTEL_COMPILER) // https://software.intel.com/en-us/node/524490
|
||
|
# ifdef __INTEL_CXX20_MODE__ // not sure about this
|
||
|
# define C4_CPP 20
|
||
|
# define C4_CPP20
|
||
|
# elif defined __INTEL_CXX17_MODE__ // not sure about this
|
||
|
# define C4_CPP 17
|
||
|
# define C4_CPP17
|
||
|
# elif defined __INTEL_CXX14_MODE__ // not sure about this
|
||
|
# define C4_CPP 14
|
||
|
# define C4_CPP14
|
||
|
# elif defined __INTEL_CXX11_MODE__
|
||
|
# define C4_CPP 11
|
||
|
# define C4_CPP11
|
||
|
# else
|
||
|
# error C++ lesser than C++11 not supported
|
||
|
# endif
|
||
|
# else
|
||
|
# ifndef __cplusplus
|
||
|
# error __cplusplus is not defined?
|
||
|
# endif
|
||
|
# if __cplusplus == 1
|
||
|
# error cannot handle __cplusplus==1
|
||
|
# elif __cplusplus >= 201709L
|
||
|
# define C4_CPP 20
|
||
|
# define C4_CPP20
|
||
|
# elif __cplusplus >= 201703L
|
||
|
# define C4_CPP 17
|
||
|
# define C4_CPP17
|
||
|
# elif __cplusplus >= 201402L
|
||
|
# define C4_CPP 14
|
||
|
# define C4_CPP14
|
||
|
# elif __cplusplus >= 201103L
|
||
|
# define C4_CPP 11
|
||
|
# define C4_CPP11
|
||
|
# elif __cplusplus >= 199711L
|
||
|
# error C++ lesser than C++11 not supported
|
||
|
# endif
|
||
|
# endif
|
||
|
#else
|
||
|
# ifdef C4_CPP == 20
|
||
|
# define C4_CPP20
|
||
|
# elif C4_CPP == 17
|
||
|
# define C4_CPP17
|
||
|
# elif C4_CPP == 14
|
||
|
# define C4_CPP14
|
||
|
# elif C4_CPP == 11
|
||
|
# define C4_CPP11
|
||
|
# elif C4_CPP == 98
|
||
|
# define C4_CPP98
|
||
|
# error C++ lesser than C++11 not supported
|
||
|
# else
|
||
|
# error C4_CPP must be one of 20, 17, 14, 11, 98
|
||
|
# endif
|
||
|
#endif
|
||
|
|
||
|
#ifdef C4_CPP20
|
||
|
# define C4_CPP17
|
||
|
# define C4_CPP14
|
||
|
# define C4_CPP11
|
||
|
#elif defined(C4_CPP17)
|
||
|
# define C4_CPP14
|
||
|
# define C4_CPP11
|
||
|
#elif defined(C4_CPP14)
|
||
|
# define C4_CPP11
|
||
|
#endif
|
||
|
|
||
|
/** lifted from this answer: http://stackoverflow.com/a/20170989/5875572 */
|
||
|
#if defined(_MSC_VER) && !defined(__clang__)
|
||
|
# if _MSC_VER < 1900
|
||
|
# define C4_CONSTEXPR11
|
||
|
# define C4_CONSTEXPR14
|
||
|
# elif _MSC_VER < 2000
|
||
|
# define C4_CONSTEXPR11 constexpr
|
||
|
# define C4_CONSTEXPR14
|
||
|
# else
|
||
|
# define C4_CONSTEXPR11 constexpr
|
||
|
# define C4_CONSTEXPR14 constexpr
|
||
|
# endif
|
||
|
#else
|
||
|
# if __cplusplus < 201103
|
||
|
# define C4_CONSTEXPR11
|
||
|
# define C4_CONSTEXPR14
|
||
|
# elif __cplusplus == 201103
|
||
|
# define C4_CONSTEXPR11 constexpr
|
||
|
# define C4_CONSTEXPR14
|
||
|
# else
|
||
|
# define C4_CONSTEXPR11 constexpr
|
||
|
# define C4_CONSTEXPR14 constexpr
|
||
|
# endif
|
||
|
#endif // _MSC_VER
|
||
|
|
||
|
|
||
|
#if C4_CPP < 17
|
||
|
#define C4_IF_CONSTEXPR
|
||
|
#define C4_INLINE_CONSTEXPR constexpr
|
||
|
#else
|
||
|
#define C4_IF_CONSTEXPR constexpr
|
||
|
#define C4_INLINE_CONSTEXPR inline constexpr
|
||
|
#endif
|
||
|
|
||
|
#if defined(_MSC_VER) && !defined(__clang__)
|
||
|
# if (defined(_CPPUNWIND) && (_CPPUNWIND == 1))
|
||
|
# define C4_EXCEPTIONS
|
||
|
# endif
|
||
|
#else
|
||
|
# if defined(__EXCEPTIONS) || defined(__cpp_exceptions)
|
||
|
# define C4_EXCEPTIONS
|
||
|
# endif
|
||
|
#endif
|
||
|
|
||
|
#ifdef C4_EXCEPTIONS
|
||
|
# define C4_IF_EXCEPTIONS_(exc_code, setjmp_code) exc_code
|
||
|
# define C4_IF_EXCEPTIONS(exc_code, setjmp_code) do { exc_code } while(0)
|
||
|
#else
|
||
|
# define C4_IF_EXCEPTIONS_(exc_code, setjmp_code) setjmp_code
|
||
|
# define C4_IF_EXCEPTIONS(exc_code, setjmp_code) do { setjmp_code } while(0)
|
||
|
#endif
|
||
|
|
||
|
#if defined(_MSC_VER) && !defined(__clang__)
|
||
|
# if defined(_CPPRTTI)
|
||
|
# define C4_RTTI
|
||
|
# endif
|
||
|
#else
|
||
|
# if defined(__GXX_RTTI)
|
||
|
# define C4_RTTI
|
||
|
# endif
|
||
|
#endif
|
||
|
|
||
|
#ifdef C4_RTTI
|
||
|
# define C4_IF_RTTI_(code_rtti, code_no_rtti) code_rtti
|
||
|
# define C4_IF_RTTI(code_rtti, code_no_rtti) do { code_rtti } while(0)
|
||
|
#else
|
||
|
# define C4_IF_RTTI_(code_rtti, code_no_rtti) code_no_rtti
|
||
|
# define C4_IF_RTTI(code_rtti, code_no_rtti) do { code_no_rtti } while(0)
|
||
|
#endif
|
||
|
|
||
|
|
||
|
//------------------------------------------------------------
|
||
|
|
||
|
#define _C4_BEGIN_NAMESPACE(ns) namespace ns {
|
||
|
#define _C4_END_NAMESPACE(ns) }
|
||
|
|
||
|
// MSVC cant handle the C4_FOR_EACH macro... need to fix this
|
||
|
//#define C4_BEGIN_NAMESPACE(...) C4_FOR_EACH_SEP(_C4_BEGIN_NAMESPACE, , __VA_ARGS__)
|
||
|
//#define C4_END_NAMESPACE(...) C4_FOR_EACH_SEP(_C4_END_NAMESPACE, , __VA_ARGS__)
|
||
|
#define C4_BEGIN_NAMESPACE(ns) namespace ns {
|
||
|
#define C4_END_NAMESPACE(ns) }
|
||
|
|
||
|
#define C4_BEGIN_HIDDEN_NAMESPACE namespace /*hidden*/ {
|
||
|
#define C4_END_HIDDEN_NAMESPACE } /* namespace hidden */
|
||
|
|
||
|
//------------------------------------------------------------
|
||
|
|
||
|
#ifndef C4_API
|
||
|
# if defined(_MSC_VER) && !defined(__clang__)
|
||
|
# if defined(C4_EXPORT)
|
||
|
# define C4_API __declspec(dllexport)
|
||
|
# elif defined(C4_IMPORT)
|
||
|
# define C4_API __declspec(dllimport)
|
||
|
# else
|
||
|
# define C4_API
|
||
|
# endif
|
||
|
# else
|
||
|
# define C4_API
|
||
|
# endif
|
||
|
#endif
|
||
|
|
||
|
#if defined(_MSC_VER) && !defined(__clang__)
|
||
|
# define C4_RESTRICT __restrict
|
||
|
# define C4_RESTRICT_FN __declspec(restrict)
|
||
|
# define C4_NO_INLINE __declspec(noinline)
|
||
|
# define C4_ALWAYS_INLINE inline __forceinline
|
||
|
/** these are not available in VS AFAIK */
|
||
|
# define C4_CONST
|
||
|
# define C4_PURE
|
||
|
# define C4_FLATTEN
|
||
|
# define C4_HOT /** @todo */
|
||
|
# define C4_COLD /** @todo */
|
||
|
# define C4_EXPECT(x, y) x /** @todo */
|
||
|
# define C4_LIKELY(x) x /** @todo */
|
||
|
# define C4_UNLIKELY(x) x /** @todo */
|
||
|
# define C4_UNREACHABLE() /** @todo */
|
||
|
# define C4_ATTR_FORMAT(...) /** */
|
||
|
# define C4_NORETURN /** @todo */
|
||
|
#else
|
||
|
///< @todo assuming gcc-like compiler. check it is actually so.
|
||
|
/** for function attributes in GCC,
|
||
|
* @see https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#Common-Function-Attributes */
|
||
|
/** for __builtin functions in GCC,
|
||
|
* @see https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html */
|
||
|
# define C4_RESTRICT __restrict__
|
||
|
# define C4_RESTRICT_FN __attribute__((restrict))
|
||
|
# define C4_NO_INLINE __attribute__((noinline))
|
||
|
# define C4_ALWAYS_INLINE inline __attribute__((always_inline))
|
||
|
# define C4_CONST __attribute__((const))
|
||
|
# define C4_PURE __attribute__((pure))
|
||
|
/** force inlining of every callee function */
|
||
|
# define C4_FLATTEN __atribute__((flatten))
|
||
|
/** mark a function as hot, ie as having a visible impact in CPU time
|
||
|
* thus making it more likely to inline, etc
|
||
|
* @see http://stackoverflow.com/questions/15028990/semantics-of-gcc-hot-attribute */
|
||
|
# define C4_HOT __attribute__((hot))
|
||
|
/** mark a function as cold, ie as NOT having a visible impact in CPU time
|
||
|
* @see http://stackoverflow.com/questions/15028990/semantics-of-gcc-hot-attribute */
|
||
|
# define C4_COLD __attribute__((cold))
|
||
|
# define C4_EXPECT(x, y) __builtin_expect(x, y) ///< @see https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html
|
||
|
# define C4_LIKELY(x) __builtin_expect(x, 1)
|
||
|
# define C4_UNLIKELY(x) __builtin_expect(x, 0)
|
||
|
# define C4_UNREACHABLE() __builtin_unreachable()
|
||
|
# define C4_ATTR_FORMAT(...) //__attribute__((format (__VA_ARGS__))) ///< @see https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#Common-Function-Attributes
|
||
|
# define C4_NORETURN __attribute__((noreturn))
|
||
|
#endif
|
||
|
|
||
|
#ifdef _MSC_VER
|
||
|
# define C4_FUNC __FUNCTION__
|
||
|
# define C4_PRETTY_FUNC __FUNCSIG__
|
||
|
#else /// @todo assuming gcc-like compiler. check it is actually so.
|
||
|
# define C4_FUNC __FUNCTION__
|
||
|
# define C4_PRETTY_FUNC __PRETTY_FUNCTION__
|
||
|
#endif
|
||
|
|
||
|
/** prevent compiler warnings about a specific var being unused */
|
||
|
#define C4_UNUSED(var) (void)var
|
||
|
|
||
|
#if C4_CPP >= 17
|
||
|
#define C4_STATIC_ASSERT(cond) static_assert(cond)
|
||
|
#else
|
||
|
#define C4_STATIC_ASSERT(cond) static_assert((cond), #cond)
|
||
|
#endif
|
||
|
#define C4_STATIC_ASSERT_MSG(cond, msg) static_assert((cond), #cond ": " msg)
|
||
|
|
||
|
/** @def C4_DONT_OPTIMIZE idea lifted from GoogleBenchmark.
|
||
|
* @see https://github.com/google/benchmark/blob/master/include/benchmark/benchmark_api.h */
|
||
|
namespace c4 {
|
||
|
namespace detail {
|
||
|
#ifdef __GNUC__
|
||
|
# define C4_DONT_OPTIMIZE(var) c4::detail::dont_optimize(var)
|
||
|
template< class T >
|
||
|
C4_ALWAYS_INLINE void dont_optimize(T const& value) { asm volatile("" : : "g"(value) : "memory"); }
|
||
|
#else
|
||
|
# define C4_DONT_OPTIMIZE(var) c4::detail::use_char_pointer(reinterpret_cast< const char* >(&var))
|
||
|
void use_char_pointer(char const volatile*);
|
||
|
#endif
|
||
|
} // namespace detail
|
||
|
} // namespace c4
|
||
|
|
||
|
/** @def C4_KEEP_EMPTY_LOOP prevent an empty loop from being optimized out.
|
||
|
* @see http://stackoverflow.com/a/7084193/5875572 */
|
||
|
#if defined(_MSC_VER) && !defined(__clang__)
|
||
|
# define C4_KEEP_EMPTY_LOOP { char c; C4_DONT_OPTIMIZE(c); }
|
||
|
#else
|
||
|
# define C4_KEEP_EMPTY_LOOP { asm(""); }
|
||
|
#endif
|
||
|
|
||
|
/** @def C4_VA_LIST_REUSE_MUST_COPY
|
||
|
* @todo <jpmag> I strongly suspect that this is actually only in UNIX platforms. revisit this. */
|
||
|
#ifdef __GNUC__
|
||
|
# define C4_VA_LIST_REUSE_MUST_COPY
|
||
|
#endif
|
||
|
|
||
|
#endif /* _C4_LANGUAGE_HPP_ */
|