Last active
March 20, 2017 21:06
-
-
Save onqtam/2d07dac989eee2fd5ecc68ca37b14f03 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#ifdef __GNUC__ | |
#pragma GCC system_header // to silence "ISO C++11 requires at least one argument for the "..." in a variadic macro" | |
#endif // __GNUC__ | |
#include <utility> // std::forward | |
#include <memory> // placement new | |
#ifdef __clang__ | |
#pragma clang diagnostic push | |
#pragma clang diagnostic ignored "-Wpadded" | |
#endif // __clang__ | |
namespace fast_static { | |
template<typename T> | |
struct storage { | |
typedef T type; | |
alignas(T) char buffer[sizeof(T)]; | |
T* ptr = nullptr; | |
template<typename... Args> | |
void construct(Args&&... args) { ptr = new (buffer) type(std::forward<Args>(args)...); } | |
~storage() { if(ptr) ptr->~T(); } | |
}; | |
} | |
#ifdef __clang__ | |
#pragma clang diagnostic pop | |
#endif // __clang__ | |
#ifdef __GNUC__ | |
#define FAST_STATIC_UNLIKELY(x) __builtin_expect((x), 0) | |
#else // __GNUC__ | |
#define FAST_STATIC_UNLIKELY(x) x | |
#endif // __GNUC__ | |
#ifdef __clang__ | |
#define FAST_STATIC_GLOBAL_NO_WARNINGS _Pragma("clang diagnostic push") \ | |
_Pragma("clang diagnostic ignored \"-Wglobal-constructors\"") \ | |
_Pragma("clang diagnostic ignored \"-Wexit-time-destructors\"") | |
#define FAST_STATIC_GLOBAL_NO_WARNINGS_END _Pragma("clang diagnostic pop") | |
#define FAST_STATIC_VA_ARGS_NO_WARNINGS _Pragma("clang diagnostic push") \ | |
_Pragma("clang diagnostic ignored \"-Wgnu-zero-variadic-macro-arguments\"") | |
#define FAST_STATIC_VA_ARGS_NO_WARNINGS_END _Pragma("clang diagnostic pop") | |
#else // __clang__ | |
#define FAST_STATIC_GLOBAL_NO_WARNINGS | |
#define FAST_STATIC_GLOBAL_NO_WARNINGS_END | |
#define FAST_STATIC_VA_ARGS_NO_WARNINGS | |
#define FAST_STATIC_VA_ARGS_NO_WARNINGS_END | |
#endif // __clang__ | |
#define FAST_STATIC_CAT_IMPL(s1, s2) s1##s2 | |
#define FAST_STATIC_CAT(s1, s2) FAST_STATIC_CAT_IMPL(s1, s2) | |
#define FAST_STATIC_STORAGE(name, ...) \ | |
FAST_STATIC_GLOBAL_NO_WARNINGS \ | |
namespace FAST_STATIC_CAT(fast_static, name) { \ | |
static ::fast_static::storage<__VA_ARGS__> name; \ | |
} \ | |
FAST_STATIC_GLOBAL_NO_WARNINGS_END \ | |
extern ::fast_static::storage<__VA_ARGS__> FAST_STATIC_CAT(fast_static, name)::name // to require a comma after the macro | |
#define FAST_STATIC_IMPL(name, ...) \ | |
if(FAST_STATIC_UNLIKELY(!FAST_STATIC_CAT(fast_static, name)::name.ptr)) \ | |
FAST_STATIC_CAT(fast_static, name)::name.construct(__VA_ARGS__); \ | |
decltype(FAST_STATIC_CAT(fast_static, name)::name)::type& name = *FAST_STATIC_CAT(fast_static, name)::name.ptr | |
#define FAST_STATIC_EXPAND(x) x // workaround for MSVC | |
// indirection because this was the only way to silence a clang warning when there are no variable arguments for initialization | |
#define FAST_STATIC(...) \ | |
FAST_STATIC_VA_ARGS_NO_WARNINGS \ | |
FAST_STATIC_EXPAND(FAST_STATIC_IMPL(__VA_ARGS__)) \ | |
FAST_STATIC_VA_ARGS_NO_WARNINGS_END | |
// ================================================================== | |
// C++11 changed the semantics of local static variables - their initialization is thread-safe. | |
// This may have a significant performance impact on code that uses statics in the hot path of the program. | |
// The synchronization can be disabled globally with -fno-threadsafe-statics for GCC if it is not required. | |
// The fast_static.h header can help if lazy initialization is required without disabling the thread safety globally. | |
// The only difference with real static objects in functions is that the destructor runs a bit | |
// later - with the globals and not with the other local statics and std::atexit() handlers. | |
// USAGE: | |
// FAST_STATIC_STORAGE(var, int); // outside of a function | |
// FAST_STATIC(var, 42); // inside a function - should be in the same namespace as the storage | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment