neoGFX
Cross-platform C++ app/game engine
Loading...
Searching...
No Matches
i_enum.hpp
Go to the documentation of this file.
1// i_enum.hpp
2/*
3 * Copyright (c) 2019, 2020 Leigh Johnston.
4 *
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are
9 * met:
10 *
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 *
14 * * Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 *
18 * * Neither the name of Leigh Johnston nor the names of any
19 * other contributors to this software may be used to endorse or
20 * promote products derived from this software without specific prior
21 * written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
24 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
25 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
26 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
27 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
28 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
29 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34*/
35
36#pragma once
37
38#include <neolib/neolib.hpp>
39#include <iostream>
42#include <neolib/core/map.hpp>
43
44namespace neolib
45{
46 template <typename Enum>
48 template <typename Enum>
50
51 // todo: rewrite and/or get rid of this guff when C++ finally gets static reflection
52 #define begin_declare_enum( enumName ) \
53 template <> \
54 inline neolib::enum_enumerators_t<enumName> const& neolib::enum_enumerators<enumName>() \
55 { \
56 static neolib::enum_enumerators_t<enumName> const sEnumerators = \
57 {
58
59 #define declare_enum_string( enumName, enumEnumerator ) { static_cast<std::underlying_type_t<enumName>>(enumName::enumEnumerator), neolib::string{ #enumEnumerator } },
60 #define declare_enum_string_explicit( enumName, enumEnumerator, enumString ) { static_cast<std::underlying_type_t<enumName>>(enumName::enumEnumerator), neolib::string{ #enumString } },
61
62 #define end_declare_enum( enumName ) \
63 }; \
64 return sEnumerators; \
65 }
66
67 struct bad_enum_value : std::runtime_error { bad_enum_value(const std::string& aString) : std::runtime_error{ "neolib: bad enum value '" + aString + "'" } {} };
68
69 template <typename Enum>
70 inline std::string enum_to_hex(Enum aEnumValue)
71 {
72 std::ostringstream oss;
73 oss << "0x" << std::uppercase << std::hex << std::setfill('0') << std::setw(sizeof(Enum) * 2u) << static_cast<std::underlying_type_t<Enum>>(aEnumValue) << "u";
74 return oss.str();
75 }
76
77 template <typename Enum, typename StringT = string>
78 inline StringT enum_to_string(Enum aEnumerator, bool aMustEnumerate = false)
79 {
80 auto const e = enum_enumerators<Enum>().find(static_cast<std::underlying_type_t<Enum>>(aEnumerator));
81 if (e != enum_enumerators<Enum>().end())
82 {
83 if constexpr (std::is_same_v<StringT, std::string>)
84 return e->second().to_std_string();
85 else
86 return e->second();
87 }
88 else if (!aMustEnumerate)
89 return enum_to_hex(aEnumerator);
90 else
91 throw bad_enum_value(enum_to_hex(aEnumerator));
92 }
93
94 struct bad_enum_string : std::runtime_error { bad_enum_string(const std::string& aString) : std::runtime_error{ "neolib: bad enum string '" + aString + "'" } {} };
95
96 template <typename Enum>
97 inline Enum string_to_enum(const i_string& aEnumerator)
98 {
99 // todo: use bimap.
100 for (auto const& e : enum_enumerators<Enum>())
101 if (e.second() == aEnumerator)
102 return static_cast<Enum>(e.first());
103 throw bad_enum_string(aEnumerator.to_std_string());
104 }
105 template <typename Enum>
106 inline Enum string_to_enum(const std::string& aEnumerator)
107 {
108 return string_to_enum<Enum>(neolib::string{ aEnumerator });
109 }
110
111 template <typename Enum>
112 inline std::optional<Enum> try_string_to_enum(const i_string& aEnumerator)
113 {
114 // todo: use bimap.
115 for (auto const& e : enum_enumerators<Enum>())
116 if (e.second() == aEnumerator)
117 return static_cast<Enum>(e.first());
118 return {};
119 }
120 template <typename Enum>
121 inline std::optional<Enum> try_string_to_enum(const std::string& aEnumerator)
122 {
123 return try_string_to_enum<Enum>(neolib::string{ aEnumerator });
124 }
125
126 template <typename Enum, typename Char, typename Traits, typename = std::enable_if_t<std::is_enum_v<Enum>, sfinae>>
127 inline std::basic_istream<Char, Traits>& operator>>(std::basic_istream<Char, Traits>& aInput, Enum& aEnum)
128 {
129 std::basic_string<Char, Traits> enumString;
130 aInput >> enumString;
131 aEnum = string_to_enum<Enum>(enumString);
132 return aInput;
133 }
134
135 template <typename Enum, typename Char, typename Traits, typename = std::enable_if_t<std::is_enum_v<Enum>, sfinae>>
136 inline std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& aOutput, const Enum& aEnum)
137 {
138 aOutput << enum_to_string<Enum, std::basic_string<Char, Traits>>(aEnum);
139 return aOutput;
140 }
141
142 template <typename UnderlyingType>
144 {
145 typedef i_basic_enum<UnderlyingType> self_type;
146 // exceptions
147 public:
148 struct bad_enum_string : std::logic_error { bad_enum_string() : std::logic_error("i_basic_enum::bad_enum_string") {} };
149 // types
150 public:
151 typedef self_type abstract_type;
152 typedef UnderlyingType underlying_type;
154 // construction/assignment
155 public:
157 {
158 return do_clone();
159 }
160 self_type& operator=(const self_type& aRhs)
161 {
162 return do_assign(aRhs);
163 }
164 // comparison
165 public:
166 bool operator==(const self_type& that) const
167 {
168 return value() == that.value();
169 }
170 std::strong_ordering operator<=>(const self_type& that) const
171 {
172 return value() <=> that.value();
173 }
174 // state
175 public:
176 virtual underlying_type value() const = 0;
177 virtual void set_value(underlying_type aValue) = 0;
178 virtual underlying_type set_value(const i_string& aValue) = 0;
179 virtual underlying_type const* data() const = 0;
180 virtual underlying_type* data() = 0;
181 // meta
182 public:
183 virtual void to_string(i_string& aString) const = 0;
184 string to_string() const { string s; to_string(s); return s; }
185 std::string to_std_string() const { return to_string().to_std_string(); }
186 virtual const enumerators_t& enumerators() const = 0;
187 // implementation
188 private:
189 virtual self_type* do_clone() const = 0;
190 virtual self_type& do_assign(const self_type& aRhs) = 0;
191 // helpers
192 public:
193 template <typename Enum>
194 Enum value() const
195 {
196 return static_cast<Enum>(value());
197 }
198 template <typename Enum>
199 void set_value(Enum aValue)
200 {
201 set_value(static_cast<underlying_type>(aValue));
202 }
203 template <typename Enum>
204 Enum set_value(const std::string& aValue)
205 {
206 return static_cast<Enum>(set_value(string{ aValue }));
207 }
208 };
209
210 template <typename T>
212
213 template <typename Enum, typename StringT = string>
214 inline StringT enum_to_string(const i_enum_t<Enum>& aEnumerator, bool aMustEnumerate = false)
215 {
216 return enum_to_string(aEnumerator.template value<Enum>(), aMustEnumerate);
217 }
218
219 template <typename Enum>
220 inline std::enable_if_t<std::is_enum_v<Enum>, bool> operator==(const i_basic_enum<std::underlying_type_t<Enum>>& lhs, Enum rhs)
221 {
222 return lhs.template value<Enum>() == rhs;
223 }
224
225 template <typename Enum>
226 inline std::enable_if_t<std::is_enum_v<Enum>, bool> operator==(Enum lhs, const i_basic_enum<std::underlying_type_t<Enum>>& rhs)
227 {
228 return lhs == rhs.template value<Enum>();
229 }
230
231 template <typename Enum>
232 inline std::enable_if_t<std::is_enum_v<Enum>, bool> operator!=(const i_basic_enum<std::underlying_type_t<Enum>>& lhs, Enum rhs)
233 {
234 return lhs.template value<Enum>() != rhs;
235 }
236
237 template <typename Enum>
238 inline std::enable_if_t<std::is_enum_v<Enum>, bool> operator!=(Enum lhs, const i_basic_enum<std::underlying_type_t<Enum>>& rhs)
239 {
240 return lhs != rhs.template value<Enum>();
241 }
242
243 template <typename Enum>
244 inline std::enable_if_t<std::is_enum_v<Enum>, bool> operator<(const i_basic_enum<std::underlying_type_t<Enum>>& lhs, Enum rhs)
245 {
246 return lhs.template value<Enum>() < rhs;
247 }
248
249 template <typename Enum>
250 inline std::enable_if_t<std::is_enum_v<Enum>, bool> operator<(Enum lhs, const i_basic_enum<std::underlying_type_t<Enum>>& rhs)
251 {
252 return lhs < rhs.template value<Enum>();
253 }
254
259
264
266}
virtual underlying_type set_value(const i_string &aValue)=0
virtual void to_string(i_string &aString) const =0
self_type abstract_type
Definition i_enum.hpp:151
virtual underlying_type const * data() const =0
std::strong_ordering operator<=>(const self_type &that) const
Definition i_enum.hpp:170
self_type & operator=(const self_type &aRhs)
Definition i_enum.hpp:160
virtual underlying_type value() const =0
std::string to_std_string() const
Definition i_enum.hpp:185
void set_value(Enum aValue)
Definition i_enum.hpp:199
virtual underlying_type * data()=0
i_multimap< underlying_type, i_string > enumerators_t
Definition i_enum.hpp:153
virtual void set_value(underlying_type aValue)=0
Enum value() const
Definition i_enum.hpp:194
virtual const enumerators_t & enumerators() const =0
ref_ptr< self_type > clone() const
Definition i_enum.hpp:156
Enum set_value(const std::string &aValue)
Definition i_enum.hpp:204
UnderlyingType underlying_type
Definition i_enum.hpp:152
bool operator==(const self_type &that) const
Definition i_enum.hpp:166
string to_string() const
Definition i_enum.hpp:184
std::string to_std_string() const
Definition i_string.hpp:75
std::string to_std_string() const
Definition string.hpp:85
bool operator<(const basic_rect< CoordinateType, CoordinateSystem > &left, const basic_rect< CoordinateType, CoordinateSystem > &right)
std::string enum_to_hex(Enum aEnumValue)
Definition i_enum.hpp:70
i_basic_enum< int64_t > i_enum_i64
Definition i_enum.hpp:263
i_basic_enum< int8_t > i_enum_i8
Definition i_enum.hpp:260
i_basic_enum< uint64_t > i_enum_u64
Definition i_enum.hpp:258
Enum string_to_enum(const i_string &aEnumerator)
Definition i_enum.hpp:97
i_basic_enum< int32_t > i_enum_i32
Definition i_enum.hpp:262
i_basic_enum< uint8_t > i_enum_u8
Definition i_enum.hpp:255
i_basic_enum< int16_t > i_enum_i16
Definition i_enum.hpp:261
std::optional< Enum > try_string_to_enum(const i_string &aEnumerator)
Definition i_enum.hpp:112
multimap< std::underlying_type_t< Enum >, string > enum_enumerators_t
Definition i_enum.hpp:47
i_enum_i32 i_enum
Definition i_enum.hpp:265
i_basic_enum< std::underlying_type_t< T > > i_enum_t
Definition i_enum.hpp:211
StringT enum_to_string(Enum aEnumerator, bool aMustEnumerate=false)
Definition i_enum.hpp:78
i_basic_enum< uint32_t > i_enum_u32
Definition i_enum.hpp:257
enum_enumerators_t< Enum > const & enum_enumerators()
i_basic_enum< uint16_t > i_enum_u16
Definition i_enum.hpp:256
bad_enum_string(const std::string &aString)
Definition i_enum.hpp:94
bad_enum_value(const std::string &aString)
Definition i_enum.hpp:67