mirror of
				https://github.com/RetroDECK/Duckstation.git
				synced 2025-04-10 19:15:14 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			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_ */
 | 
