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.
This commit is contained in:
Anton Bachin 2015-06-15 18:32:57 -05:00
parent fc609e58aa
commit a493e90ac4

20
enum.h
View File

@ -510,6 +510,14 @@ struct underlying_traits {
are_equal(const T& u, const T& v) { return u == v; }
};
// Eager initialization.
template <typename Enum>
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<Enum>; \
}; \
\
namespace better_enums { \
namespace _data_ ## Enum { \
\
static ::better_enums::_initialize_at_program_start<Enum> \
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__))