From a493e90ac49d1c89277105d75b14ee85376d1894 Mon Sep 17 00:00:00 2001 From: Anton Bachin Date: Mon, 15 Jun 2015 18:32:57 -0500 Subject: [PATCH] Initialization now always completed before main. Before this change, in C++98 and C++11 "fast" mode, initializer trimming was done "lazily" the first time _to_string or _names was called. To make performance more "predictable", an object with static storage is now used to force initializaton during program start-up, when static object constructors are called. The benefit of this change is very debatable. I had to give the static object static linkage to avoid duplicate symbols, so there is a copy now in each translation unit. I hope this does not increase code size too much in realistic scenarios. Lazy initialization checks are still performed and cannot be removed, because other objects with static storage may try to use an enum from their constructors before the enum's initialization is forced. --- enum.h | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/enum.h b/enum.h index 3e0f619..848e27b 100644 --- a/enum.h +++ b/enum.h @@ -510,6 +510,14 @@ struct underlying_traits { are_equal(const T& u, const T& v) { return u == v; } }; + + +// Eager initialization. +template +struct _initialize_at_program_start { + _initialize_at_program_start() { Enum::initialize(); } +}; + } // namespace better_enums @@ -708,11 +716,16 @@ class Enum { \ _from_string_loop(const char *name, std::size_t index = 0); \ BETTER_ENUMS__CONSTEXPR static _optional_index \ _from_string_nocase_loop(const char *name, std::size_t index = 0); \ + \ + friend struct ::better_enums::_initialize_at_program_start; \ }; \ \ namespace better_enums { \ namespace _data_ ## Enum { \ \ +static ::better_enums::_initialize_at_program_start \ + force_initialization; \ + \ enum PutNamesInThisScopeAlso { __VA_ARGS__ }; \ \ BETTER_ENUMS__CONSTEXPR const Enum value_array[] = \ @@ -1015,7 +1028,8 @@ BETTER_ENUMS__CONSTEXPR inline bool operator !=(const Enum &a, const Enum &b) \ static int initialize(); // C++11 slow all-constexpr version -#define BETTER_ENUMS__DO_NOT_DECLARE_INITIALIZE +#define BETTER_ENUMS__DECLARE_EMPTY_INITIALIZE \ + static int initialize() { return 0; } // C++98, C++11 fast version #define BETTER_ENUMS__DO_DEFINE_INITIALIZE(Enum) \ @@ -1071,7 +1085,7 @@ BETTER_ENUMS__CONSTEXPR inline bool operator !=(const Enum &a, const Enum &b) \ # define BETTER_ENUMS__DEFAULT_TO_STRING_KEYWORD \ BETTER_ENUMS__CONSTEXPR_TO_STRING_KEYWORD # define BETTER_ENUMS__DEFAULT_DECLARE_INITIALIZE \ - BETTER_ENUMS__DO_NOT_DECLARE_INITIALIZE + BETTER_ENUMS__DECLARE_EMPTY_INITIALIZE # define BETTER_ENUMS__DEFAULT_DEFINE_INITIALIZE \ BETTER_ENUMS__DO_NOT_DEFINE_INITIALIZE # define BETTER_ENUMS__DEFAULT_CALL_INITIALIZE \ @@ -1112,7 +1126,7 @@ BETTER_ENUMS__CONSTEXPR inline bool operator !=(const Enum &a, const Enum &b) \ BETTER_ENUMS__DEFAULT_SWITCH_TYPE_GENERATE, \ BETTER_ENUMS__CXX11_FULL_CONSTEXPR_TRIM_STRINGS_ARRAYS, \ BETTER_ENUMS__CONSTEXPR_TO_STRING_KEYWORD, \ - BETTER_ENUMS__DO_NOT_DECLARE_INITIALIZE, \ + BETTER_ENUMS__DECLARE_EMPTY_INITIALIZE, \ BETTER_ENUMS__DO_NOT_DEFINE_INITIALIZE, \ BETTER_ENUMS__DO_NOT_CALL_INITIALIZE, \ Enum, Underlying, __VA_ARGS__))