Anton Bachin 14bc834f7d Made to_string conversion constexpr and removed the last of the weak symbols.
The interface is now uniformly constexpr, including to_string and the _names
iterable. Without the weak symbol, the remaining code is also entirely standard
C++.

The compile-time string trimming code in this commit has a negative impact on
performance. The performance test is now twice as slow as including <iostream>,
whereas before it was faster. That test declares an excessive number of enums,
though, so perhaps in typical usage, and with some future optimizations, the
impact will not be so significant.

There may be other ways to solve this, such as providing a version of the macro
that does not trim strings at compile time, but only checks if they need
trimming. If some string does need trimming, that macro would fail a
static_assert and ask the user to use the slow macro.
2015-05-17 21:29:26 -05:00
doc Updated documentation with new front page. 2015-05-15 10:15:31 -05:00
example Made to_string conversion constexpr and removed the last of the weak symbols. 2015-05-17 21:29:26 -05:00
test Initial release. 2015-05-11 17:38:41 -04:00
.gitattributes Initial release. 2015-05-11 17:38:41 -04:00
.gitignore Removed most weak symbols. Iterators should now be random access. 2015-05-17 18:47:51 -05:00
enum.h Made to_string conversion constexpr and removed the last of the weak symbols. 2015-05-17 21:29:26 -05:00
LICENSE Initial release. 2015-05-11 17:38:41 -04:00
pp_map_gen.py Made to_string conversion constexpr and removed the last of the weak symbols. 2015-05-17 21:29:26 -05:00
README.md Updated documentation with new front page. 2015-05-15 10:15:31 -05:00

Better Enums

Reflective compile-time C++11 enum library with clean syntax. For example:

ENUM(Channel, int, Red = 1, Green, Blue);

defines a type Channel. You can then do natural things like:

Channel channel = Channel::Green;

channel.to_string();            // Results in the string "Green"
channel.to_integral();          // Results in the int 2

Channel::_from_string("Red");   // Results in Channel::Red
Channel::_from_integral(3);     // Results in Channel::Blue

constexpr auto channel = Channel::_from_integral(3);
                                // Do it at compile time
constexpr auto channel = Channel::_max;
                                // Channel::Blue

for (Channel channel : Channel::_values) {
    // Iterate over all channels
}

...and more. See the project page and examples for a tutorial.

Installation

Simply add enum.h and enum_preprocessor_map.h to your project. The current version can be found at https://github.com/aantron/better-enums/releases.

enum_preprocessor_map.h can handle enums with up to 256 constants. If you have more, re-generate it by running something like:

./pp_map_gen.py enum_preprocessor_map.h 512

This only needs to be done once when the constant limit is exceeded. You don't need to do this on every build. I hope to remove the need for this completely in a future version.

Features

  • Generated at compile time by constexpr functions and the preprocessor. pp_map_gen.py is only needed if you have an enum with more than 256 constants.
  • Safe conversions between enums and integers and strings. 1-basic.cc
  • Iterable collections of constants and names. 2-iterate.cc
  • Range information, such as the number of constants defined and the maximum constant. 2-iterate.cc
  • Switch case checking. 3-switch.cc
  • Almost all operations are constexpr and can be used at compile time in your own constexpr code. 4-constexpr.cc
  • Constant values can be set (Red = 1) and aliased (Favorite = Green), just like with built-in enums.
  • Generating a large number of enums is faster than including a typical standard header like iostream performance test included.
  • Explicit choice of underlying representation type.
  • Header-only.
  • No dependencies besides the standard library.
  • Tested on gcc 4.9 and clang 3.6.

The library compiles only with gcc and clang due to use of weak symbols and due to lagging C++11 support in msvc. It should ultimately be portable to msvc, since msvc has its own version of weak symbols. Everything else in the library is standard C++.

Contact

Don't hesitate to contact me about features (or bugs!): antonbachin@yahoo.com

Explanation

The ENUM macro specializes a template based around a regular enum declaration, though it is more similar to enum class in the degree of type safety. The following are spiritually equivalent:

ENUM(Channel, int, Red = 1, Green, Blue);
enum class Channel : int {Red = 1, Green, Blue};

ENUM(Depth, char, Indexed8Bit, HighColor, TrueColor);
enum class Depth : char {Indexed8Bit, HighColor, TrueColor};

See the full documentation.

Development plan

There are several areas that still need improvement.

  • I will try to eliminate the need for pp_map_gen.py. The library will then consist of one file, enum.h.
  • to_string can be made constexpr, like most of the rest of the code.
  • Iterators over defined constants should be made random-access. This would allow constexpr functions to use them by adding 1 the only way to advance them now is by mutating increment.
  • Some enum types might have a sensible choice for a default constructor. The library should allow it to be customized.
  • All safety checks are currently done by linear scans. This may be a performance problem for enum types with many constants.
  • Better diagnostics for empty enums or too many constants.
  • Conversions from integers and strings that don't throw exceptions, but indicate failure by some other means.

License

Better Enums is released under the BSD 2-clause license. See LICENSE.

History

The library was originally developed by the author in the winter of 2012-2013 at Hudson River Trading, as a replacement for an older generator called BETTER_ENUM.