Commit | Line | Data |
---|---|---|
8ae5c2b2 SM |
1 | #pragma once |
2 | ||
3 | #include "wise_enum_detail.h" | |
4 | #include "wise_enum_generated.h" | |
5 | ||
6 | #include <algorithm> | |
7 | #include <array> | |
8 | #include <type_traits> | |
9 | #include <utility> | |
10 | ||
11 | /* | |
12 | Macro interface | |
13 | ||
14 | The first argument to any macro enum is either the name of the enum, or a | |
15 | parenthesized pair, (name, storage). The first form results in unfixed | |
16 | underlying type for the enum, while the second form defines it explicitly. | |
17 | After that, the macros take a variadic enumerator list. Each entry in the list | |
18 | can be either a legal identifier name, or it can be a parenthesized pair where | |
19 | the first entry is the identifier and the second entry is the initializer. | |
20 | ||
21 | Usage notes: | |
22 | - A semi-colon after the macro invocation is not necessary, and your | |
23 | compiler may warn for it | |
24 | */ | |
25 | ||
26 | // Declare an enum at namespace scope | |
27 | #define WISE_ENUM(name, ...) WISE_ENUM_IMPL(enum, name, , __VA_ARGS__) | |
28 | ||
29 | // Declare an enum class at namespace scope | |
30 | #define WISE_ENUM_CLASS(name, ...) \ | |
31 | WISE_ENUM_IMPL(enum class, name, , __VA_ARGS__) | |
32 | ||
33 | // Declare an enum at class scope | |
34 | #define WISE_ENUM_MEMBER(name, ...) \ | |
35 | WISE_ENUM_IMPL(enum, name, friend, __VA_ARGS__) | |
36 | ||
37 | // Declare an enum class at class scope | |
38 | #define WISE_ENUM_CLASS_MEMBER(name, ...) \ | |
39 | WISE_ENUM_IMPL(enum class, name, friend, __VA_ARGS__) | |
40 | ||
41 | /* | |
42 | Adapt an existing enum into the wise enum API. This macro must be used at | |
43 | global scope. The first argument must be the name of the enum (qualified), | |
44 | followed by all the enumerators of the enum. | |
45 | */ | |
46 | #define WISE_ENUM_ADAPT(name, ...) WISE_ENUM_IMPL_ADAPT(name, __VA_ARGS__) | |
47 | ||
48 | namespace wise_enum { | |
49 | ||
50 | // Returns the string representation of an enumerator | |
51 | template <class T> | |
52 | constexpr string_type to_string(T t) { | |
53 | return wise_enum_detail_to_string(t, detail::Tag<T>{}); | |
54 | } | |
55 | ||
56 | // Enumerators trait class. Each value is also available as a template variable | |
57 | // for C++14 and on | |
58 | template <class T> | |
59 | struct enumerators { | |
60 | // For a given wise enum type, this variable allows iteration over enumerators | |
61 | // and their string names in the declared order. Each iterated object is a | |
62 | // struct with members { T value; string_type name; } | |
63 | static constexpr decltype(wise_enum_detail_array(detail::Tag<T>{})) range = | |
64 | wise_enum_detail_array(detail::Tag<T>{}); | |
65 | ||
66 | // This variable is equal to the number of enumerators for the wise enum type. | |
67 | static constexpr std::size_t size = range.size(); | |
68 | }; | |
69 | ||
70 | template <class T> | |
71 | constexpr decltype( | |
72 | wise_enum_detail_array(detail::Tag<T>{})) enumerators<T>::range; | |
73 | ||
74 | template <class T> | |
75 | constexpr std::size_t enumerators<T>::size; | |
76 | ||
77 | #if __cplusplus >= 201402 | |
78 | template <class T> | |
79 | constexpr auto &range = enumerators<T>::range; | |
80 | ||
81 | template <class T> | |
82 | constexpr std::size_t size = enumerators<T>::size; | |
83 | #endif | |
84 | ||
85 | // A type trait; this allows checking if a type is a wise_enum in generic code | |
86 | template <class T> | |
87 | using is_wise_enum = detail::is_wise_enum<T>; | |
88 | ||
89 | #if __cplusplus >= 201402 | |
90 | template <class T> | |
91 | static constexpr bool is_wise_enum_v = is_wise_enum<T>::value; | |
92 | #endif | |
93 | ||
94 | // Converts a string literal into a wise enum. Returns an optional<T>; if no | |
95 | // enumerator has name matching the string, the optional is returned empty. | |
96 | template <class T> | |
97 | WISE_ENUM_CONSTEXPR_14 optional_type<T> from_string(string_type s) { | |
98 | auto it = | |
99 | std::find_if(enumerators<T>::range.begin(), enumerators<T>::range.end(), | |
100 | [=](const detail::value_and_name<T> &x) { | |
101 | return ::wise_enum::detail::compare(x.name, s); | |
102 | }); | |
103 | if (it == enumerators<T>::range.end()) | |
104 | return {}; | |
105 | ||
106 | return it->value; | |
107 | } | |
108 | } // namespace wise_enum |