Note, consider this beta right now. Bugfixes and ideas for improvement are more than welcome.
Light-Enum is an "add-on" for Magic-Enum aiming to provide the same (almost) functionality with low compile time. The idea is to introspect enums (using Magic Enum) at application start and store them all in a global hash map. This means that the heavey Magic Enum introspection only needs to be compiled in a single translation unit/cpp file rather than every time an enum is introspected. See example below.
As mentioned, this just a simple add-on for Magic Enum. All the hard work for introspecting enums shall be credited to the creator of Magic Enum. Magic Enum
light_enum.hpp - Light header file used when accessing enums. Suitable for adding to precompiled headers. light_enum_register.hpp - Heavy header file only to be used in .cpp files where enums are registered.
All these functions are similar to the corresponding function in magic_enum, but a span is returned instead of a std::array. Trying to access an enum not registred throws an out_of_bounds exception.
template <typename E> auto enum_cast(const std::string_view& name) -> std::optional<E>;
template <typename E> auto enum_values() -> detail::span<E>;
template <typename E> auto enum_names() -> detail::span<std::string_view>;
template <typename E> auto enum_name(const E& e) -> std::string_view; // Returns an empty string_view if invalid enum
template <typename E> auto enum_count() -> size_t;
template <typename E> auto enum_index(const E& e) -> std::optional<size_t>;
template <typename E> auto enum_contains(const E& e) -> bool;
template <typename E> auto enum_next() -> E; // Returns the next enum
template <typename E> auto enum_prev() -> E; // Returns the previous enum
template <typename E> [[nodiscard]] auto is_registred() -> bool;
template <typename E> auto register_enum() -> void;
LIGHT_ENUM_REGISTER(E) // Convenience macro for putting in global namespace
Fruit.h
// Define enum as ususal
enum class Fruit{Apple, Orange, Banana};
Fruit.cpp
// Only include light_enum_register.hpp where you register enums
#include "Fruit.h"
#include "light_enum/light_enum_register.hpp"
LIGHT_ENUM_REGISTER(Fruit);
// ...or ...
LIGHT_ENUM_REGISTER_RANGE(Fruit, 0, 200);
// If you have a large enum you can define the range to search for values like this.
// Note that the range can be larger than the values of the enum
Application.cpp
#include "Fruit.h"
// Only light_enum.hpp is required for accessing enums
#include "light_enum/light_enum.hpp"
auto function() {
// Introspect enums just as Magic Enum
const auto apple = Fruit::Apple;
assert(light_enum::enum_count<Fruit>() == 3);
assert(light_enum::enum_name(apple) == "Apple");
const auto values = light_enum::enum_values<Fruit>();
assert(values[0] == Fruit::Apple);
assert(values[1] == Fruit::Orange);
assert(values[2] == Fruit::Banana);
}
All returned spans and string_views are guaranteed to be stable in memory, even if new enums are registered. Therefore, it's perfectly store them locally for faster access.
struct FruitInfo{
Fruit fruit;
std::string_view name;
};
auto fruit_info = FruitInfo {
EFruit::Apple,
light_enum::enum_name(EFruit::Apple);
};
// fruit_info.name will always be valid
struct FruitBasket{
span<std::string_view> names;
span<Fruit> fruits;
};
auto fruit_basket = FruitBasket{
light_enum::enum_names<Fruit>(),
light_enum::enum_values<Fruit>()
};
// fruit_basket.names and fruit_basket.fruits will always be valid
Every introspection * Constructs a std::type_index * Reads a static variable holding the database * Performs a std::unordered_map lookup RTTI is required to be enabled in order to use std::type_index. Future updates will be able to use boost::type_index which does not depend on RTTI.
Light enum is almost header-only for easy installation.
- Include light_enum_impl.ipp once in a .cpp file of your choice.
- Include light_enum.hpp wherever you want to access enums (I recommend you to put this in you precompiled header file)
- Include "light_enum_register.hpp" in the .cpp files where you register enums, as registering enums is slow from a compile time perspective.
These improvements are planned for the future
- Ability to change std::type_index to boost::typeindex in order to not require RTTI
- Ability to change the underlying std::unordered_map to a faster hash-map (tsl::hopscotch_map for example)
MIT License. Use however you like, if you're using it in something released I would be happy for a mail telling me about it :)
I'm available at viktor dot sehr (at) gmail dot com