Skip to content

gloinart/light_enum

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

22 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Note, consider this beta right now. Bugfixes and ideas for improvement are more than welcome.

Light-Enum

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.

Magic-Enum

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

Summary

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.

Interface

Introspecting enums

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

Adding enums to registry

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 

Usage example

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);
}

Features

Stable memory

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.

Example:

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

Run-time performance

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.

Installation

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.

Future improvements

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)

License

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 :)

Contact

I'm available at viktor dot sehr (at) gmail dot com

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages