neoGFX
Cross-platform C++ app/game engine
Loading...
Searching...
No Matches
variant.hpp
Go to the documentation of this file.
1// variant.hpp
2/*
3 * Copyright (c) 2007, 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 <type_traits>
40#include <optional>
41#include <variant>
44
45namespace neolib
46{
47 template <typename... Types>
48 class variant;
49}
50
51namespace std
52{
53 template <typename Type>
54 struct variant_size<neolib::variant<Type>> : variant_size<std::variant<std::monostate, Type>> {};
55
56 template <typename... Types>
57 struct variant_size<neolib::variant<Types...>> : variant_size<std::variant<std::monostate, Types...>> {};
58
59 template <typename Visitor, typename... Types>
60 inline constexpr decltype(auto) visit(Visitor&& vis, neolib::variant<Types...>&& var)
61 {
62 return visit(std::forward<Visitor>(vis), static_cast<std::variant<std::monostate, Types...>&&>(std::move(var)));
63 }
64
65 template <typename Visitor, typename... Types>
66 inline constexpr decltype(auto) visit(Visitor&& vis, neolib::variant<Types...> const& var)
67 {
68 return visit(std::forward<Visitor>(vis), static_cast<std::variant<std::monostate, Types...> const&>(var));
69 }
70
71 template <typename Visitor, typename... Types>
72 inline constexpr decltype(auto) visit(Visitor&& vis, neolib::variant<Types...>& var)
73 {
74 return visit(std::forward<Visitor>(vis), static_cast<std::variant<std::monostate, Types...>&>(var));
75 }
76
77 template <typename T, typename... Types>
78 inline constexpr bool holds_alternative(neolib::variant<Types...> const& var) noexcept
79 {
80 return holds_alternative<T>(static_cast<std::variant<std::monostate, Types...> const&>(var));
81 }
82
83 template<typename T, typename... Types>
84 inline constexpr T& get(neolib::variant<Types...>& var)
85 {
86 return get<T>(static_cast<std::variant<std::monostate, Types...>&>(var));
87 }
88
89 template<typename T, typename... Types>
90 inline constexpr T&& get(neolib::variant<Types...>&& var)
91 {
92 return get<T>(static_cast<std::variant<std::monostate, Types...> &&>(std::move(var)));
93 }
94
95 template<typename T, typename... Types>
96 inline constexpr const T& get(const neolib::variant<Types...>& var)
97 {
98 return get<T>(static_cast<std::variant<std::monostate, Types...> const&>(var));
99 }
100
101 template<typename T, typename... Types>
102 inline constexpr const T&& get(const neolib::variant<Types...>&& var)
103 {
104 return get<T>(static_cast<const std::variant<std::monostate, Types...>&&>(std::move(var)));
105 }
106}
107
108namespace neolib
109{
110 using none_t = std::monostate;
112
113 template <typename AbstractT, typename Type>
114 constexpr bool is_variant_convertible_v = std::is_base_of_v<AbstractT, Type> && std::is_abstract_v<AbstractT>;
115 template <bool, typename AbstractT, typename... Rest>
117 template <typename AbstractT, typename... Types>
119 template <typename AbstractT, typename Type>
120 struct from_abstract_next<AbstractT, Type> { typedef typename from_abstract<is_variant_convertible_v<AbstractT, Type>, AbstractT, Type>::result_type result_type; };
121 template <typename AbstractT, typename Type, typename Rest>
122 struct from_abstract_next<AbstractT, Type, Rest> { typedef typename from_abstract<is_variant_convertible_v<AbstractT, Type>, AbstractT, Type, Rest>::result_type result_type; };
123 template <typename AbstractT, typename Type, typename... Rest>
124 struct from_abstract_next<AbstractT, Type, Rest...> { typedef typename from_abstract<is_variant_convertible_v<AbstractT, Type>, AbstractT, Type, Rest...>::result_type result_type; };
125 template <typename AbstractT, typename Type>
126 struct from_abstract<true, AbstractT, Type> { typedef Type result_type; };
127 template <typename AbstractT, typename Type, typename... Rest>
128 struct from_abstract<true, AbstractT, Type, Rest...> { typedef Type result_type; };
129 template <typename AbstractT, typename Type>
130 struct from_abstract<false, AbstractT, Type> {};
131 template <typename AbstractT, typename Type, typename... Rest>
132 struct from_abstract<false, AbstractT, Type, Rest...> { typedef typename from_abstract_next<AbstractT, Rest...>::result_type result_type; };
133 template <typename AbstractT, typename... Type>
134 using from_abstract_t = typename from_abstract_next<AbstractT, Type...>::result_type;
135
136 template <typename... Types>
137 class variant : public reference_counted<i_variant<abstract_t<Types>...>>, public std::variant<std::monostate, Types...>
138 {
139 using self_type = variant<Types...>;
140 // types
141 public:
143 using std_type = std::variant<std::monostate, Types...>;
144 static constexpr bool is_copy_constructible_v = (std::is_copy_constructible_v<Types> && ...);
145 static constexpr bool is_move_constructible_v = (std::is_move_constructible_v<Types> && ...);
146 static constexpr bool is_copy_assignable_v = (std::is_copy_assignable_v<Types> && ...);
147 static constexpr bool is_move_assignable_v = (std::is_move_assignable_v<Types> && ...);
148 public:
149 template <typename T>
150 static constexpr bool is_alternative_v = (std::is_same_v<std::decay_t<T>, Types> || ...) || (std::is_same_v<std::decay_t<T>, abstract_t<Types>> || ...);
151 // construction
152 public:
154 std_type{}
155 {
156 }
157 template <typename T, std::enable_if_t<std::is_base_of_v<self_type, T> && is_copy_constructible_v, int> = 0>
158 variant(T const& aOther) :
159 std_type{ aOther }
160 {
161 }
162 template <typename T, std::enable_if_t<std::is_base_of_v<self_type, T> && is_move_constructible_v, int> = 0>
163 variant(T&& aOther) :
164 std_type{ std::move(aOther) }
165 {
166 }
167 template <typename T, std::enable_if_t<std::is_same_v<T, abstract_type> && is_copy_constructible_v, int> = 0>
168 variant(T const& aOther) :
169 std_type{ static_cast<self_type const&>(aOther) } // todo: not plugin-safe
170 {
171 }
172 template <typename T, std::enable_if_t<std::is_same_v<T, abstract_type> && is_move_constructible_v, int> = 0>
174 std_type{ static_cast<self_type&&>(aOther) } // todo: not plugin-safe
175 {
176 }
177 template <typename T, std::enable_if_t<!std::is_base_of_v<self_type, T> && !std::is_abstract_v<T>, int> = 0>
178 variant(T const& aValue) :
179 std_type{ aValue }
180 {
181 }
182 template <typename T, std::enable_if_t<!std::is_base_of_v<self_type, T> && !std::is_abstract_v<T>, int> = 0>
183 variant(T&& aValue) :
184 std_type{ std::move(aValue) }
185 {
186 }
187 template <typename T, std::enable_if_t<!std::is_same_v<T, abstract_type> && std::is_abstract_v<T>, int> = 0>
188 variant(T const& aValue) :
189 std_type{ static_cast<from_abstract_t<T, Types...> const&>(aValue) } // todo: not plugin-safe
190 {
191 }
192 template <typename T, std::enable_if_t<!std::is_same_v<T, abstract_type> && std::is_abstract_v<T>, int> = 0>
193 variant(T&& aValue) :
194 std_type{ static_cast<from_abstract_t<T, Types...>&&>(aValue) } // todo: not plugin-safe
195 {
196 }
197 // assignment
198 public:
199 template <typename T, std::enable_if_t<std::is_base_of_v<self_type, T> && is_copy_assignable_v, int> = 0>
200 self_type& operator=(T const& aOther)
201 {
202 std_type::operator=(aOther);
203 return *this;
204 }
205 template <typename T, std::enable_if_t<std::is_base_of_v<self_type, T> && is_move_assignable_v, int> = 0>
206 self_type& operator=(T&& aOther)
207 {
208 std_type::operator=(std::move(aOther));
209 return *this;
210 }
211 template <typename T, std::enable_if_t<std::is_same_v<T, abstract_type> && is_copy_assignable_v, int> = 0>
212 self_type& operator=(T const& aOther)
213 {
214 std_type::operator=(static_cast<self_type const&>(aOther)); // todo: not plugin-safe
215 return *this;
216 }
217 template <typename T, std::enable_if_t<std::is_same_v<T, abstract_type> && is_move_assignable_v, int> = 0>
218 self_type& operator=(T&& aOther)
219 {
220 std_type::operator=(static_cast<self_type&&>(aOther)); // todo: not plugin-safe
221 return *this;
222 }
223 template <typename T, std::enable_if_t<!std::is_base_of_v<self_type, T> && !std::is_abstract_v<T>, int> = 0>
224 self_type& operator=(T const& aValue)
225 {
226 std_type::operator=(aValue);
227 return *this;
228 }
229 template <typename T, std::enable_if_t<!std::is_base_of_v<self_type, T> && !std::is_abstract_v<T>, int> = 0>
230 self_type& operator=(T&& aValue)
231 {
232 std_type::operator=(std::move(aValue));
233 return *this;
234 }
235 template <typename T, std::enable_if_t<!std::is_same_v<T, abstract_type> && std::is_abstract_v<T>, int> = 0>
236 self_type& operator=(T const& aValue)
237 {
238 std_type::operator=(static_cast<from_abstract_t<T, Types...> const&>(aValue)); // todo: not plugin-safe
239 return *this;
240 }
241 template <typename T, std::enable_if_t<!std::is_same_v<T, abstract_type> && std::is_abstract_v<T>, int> = 0>
242 self_type& operator=(T&& aValue)
243 {
244 std_type::operator=(static_cast<from_abstract_t<T, Types...>&&>(aValue)); // todo: not plugin-safe
245 return *this;
246 }
247 // meta
248 public:
249 std::size_t index() const override
250 {
251 return std_type::index();
252 }
253 // impl
254 private:
255 void const* ptr() const override
256 {
257 void const* result = nullptr;
258 std::visit([&](auto&& arg)
259 {
260 result = &arg;
261 }, *this);
262 return result;
263 }
264 void* ptr() override
265 {
266 return const_cast<void*>(to_const(*this).ptr());
267 }
268 };
269
270 template <typename... Types>
271 inline bool operator==(none_t const&, variant<Types...> const& rhs) noexcept
272 {
273 return std::holds_alternative<std::monostate>(rhs);
274 }
275
276 template <typename... Types>
277 inline bool operator==(variant<Types...> const& lhs, none_t const&) noexcept
278 {
279 return std::holds_alternative<std::monostate>(lhs);
280 }
281
282 template <typename... Types>
283 inline bool operator!=(none_t const&, variant<Types...> const& rhs) noexcept
284 {
285 return !std::holds_alternative<std::monostate>(rhs);
286 }
287
288 template <typename... Types>
289 inline bool operator!=(variant<Types...> const& lhs, none_t const&) noexcept
290 {
291 return !std::holds_alternative<std::monostate>(lhs);
292 }
293
294 template <typename... Types>
295 inline bool operator==(variant<Types...> const& lhs, variant<Types...> const& rhs) noexcept
296 {
297 return static_cast<std::variant<std::monostate, Types...> const&>(lhs) == static_cast<std::variant<std::monostate, Types...> const&>(rhs);
298 }
299
300 template <typename... Types>
301 inline bool operator!=(variant<Types...> const& lhs, variant<Types...> const& rhs) noexcept
302 {
303 return static_cast<std::variant<std::monostate, Types...> const&>(lhs) != static_cast<std::variant<std::monostate, Types...> const&>(rhs);
304 }
305
306 template <typename... Types>
307 inline bool operator<(variant<Types...> const& lhs, variant<Types...> const& rhs) noexcept
308 {
309 return static_cast<std::variant<std::monostate, Types...> const&>(lhs) < static_cast<std::variant<std::monostate, Types...> const&>(rhs);
310 }
311
312 template <typename... Types>
313 inline bool operator<=(variant<Types...> const& lhs, variant<Types...> const& rhs) noexcept
314 {
315 return static_cast<std::variant<std::monostate, Types...> const&>(lhs) <= static_cast<std::variant<std::monostate, Types...> const&>(rhs);
316 }
317
318 template <typename... Types>
319 inline bool operator>(variant<Types...> const& lhs, variant<Types...> const& rhs) noexcept
320 {
321 return static_cast<std::variant<std::monostate, Types...> const&>(lhs) > static_cast<std::variant<std::monostate, Types...> const&>(rhs);
322 }
323
324 template <typename... Types>
325 inline bool operator>=(variant<Types...> const& lhs, variant<Types...> const& rhs) noexcept
326 {
327 return static_cast<std::variant<std::monostate, Types...> const&>(lhs) >= static_cast<std::variant<std::monostate, Types...> const&>(rhs);
328 }
329
330 template <typename... Types>
331 inline auto operator<=>(variant<Types...> const& lhs, variant<Types...> const& rhs) noexcept
332 {
333 return static_cast<std::variant<std::monostate, Types...> const&>(lhs) <=> static_cast<std::variant<std::monostate, Types...> const&>(rhs);
334 }
335
336 // Deprecated, use std::get.
337 template <typename T, typename Variant>
338 inline auto& static_variant_cast(const Variant& var)
339 {
340 return std::get<std::decay_t<T>>(var);
341 }
342
343 // Deprecated, use std::get.
344 template <typename T, typename Variant>
345 inline auto& static_variant_cast(Variant& var)
346 {
347 return std::get<std::decay_t<T>>(var);
348 }
349
350 struct bad_numeric_variant_cast : std::logic_error { bad_numeric_variant_cast() : std::logic_error{ "neolib::bad_numeric_variant_cast" } {} };
351
352 template <typename T, typename Variant>
353 inline T static_numeric_variant_cast(const Variant& var)
354 {
355 typedef T result_type;
356 std::optional<result_type> result;
357 visit([&result](auto&& source)
358 {
359 typedef std::remove_cv_t<std::remove_reference_t<decltype(source)>> source_type;
360 if constexpr (std::is_arithmetic_v<source_type>)
361 result = static_cast<result_type>(source);
362 }, var);
363 if (result != std::nullopt)
364 return *result;
366 }
367
368 template <typename T, typename Variant>
369 inline T static_numeric_variant_cast(Variant& var)
370 {
371 typedef T result_type;
372 typedef std::remove_cv_t<std::remove_reference_t<result_type>> alternative_type;
373 visit([&var](auto&& source)
374 {
375 typedef std::remove_cv_t<std::remove_reference_t<decltype(source)>> source_type;
376 if constexpr (std::is_arithmetic_v<source_type> && !std::is_same_v<alternative_type, source_type>)
377 var = static_cast<alternative_type>(source);
378 }, var);
379 return static_variant_cast<T>(var);
380 }
381
382 template<typename T, typename Variant, std::size_t index = 0>
383 constexpr std::size_t variant_index_of()
384 {
385 if constexpr (index == std::variant_size_v<Variant>)
386 return index - 1;
387 else if constexpr (std::is_same_v<std::variant_alternative_t<index, Variant>, T>)
388 return index - 1;
389 else
390 return variant_index_of<T, Variant, index + 1>();
391 }
392}
393
394// Deprecated, use std::get.
static constexpr bool is_copy_assignable_v
Definition variant.hpp:146
static constexpr bool is_copy_constructible_v
Definition variant.hpp:144
std::size_t index() const override
Definition variant.hpp:249
self_type & operator=(T const &aOther)
Definition variant.hpp:200
static constexpr bool is_move_assignable_v
Definition variant.hpp:147
variant(T &&aValue)
Definition variant.hpp:183
self_type & operator=(T &&aValue)
Definition variant.hpp:230
variant(T const &aValue)
Definition variant.hpp:178
variant(abstract_type &&aOther)
Definition variant.hpp:173
static constexpr bool is_alternative_v
Definition variant.hpp:150
static constexpr bool is_move_constructible_v
Definition variant.hpp:145
self_type & operator=(T const &aValue)
Definition variant.hpp:224
std::variant< std::monostate, Types... > std_type
Definition variant.hpp:143
self_type & operator=(T &&aOther)
Definition variant.hpp:206
variant(T const &aOther)
Definition variant.hpp:158
variant(T &&aOther)
Definition variant.hpp:163
typename detail::abstract_type< T >::type abstract_t
Definition neolib.hpp:178
T static_numeric_variant_cast(const Variant &var)
Definition variant.hpp:353
bool operator>=(variant< Types... > const &lhs, variant< Types... > const &rhs) noexcept
Definition variant.hpp:325
std::partial_ordering operator<=>(const i_container< T, ConstIteratorType, IteratorType > &lhs, const i_container< T, ConstIteratorType, IteratorType > &rhs)
bool operator>(variant< Types... > const &lhs, variant< Types... > const &rhs) noexcept
Definition variant.hpp:319
to_const_reference_t< T > to_const(T &&object)
Definition neolib.hpp:113
constexpr std::size_t variant_index_of()
Definition variant.hpp:383
std::monostate none_t
Definition variant.hpp:110
const none_t none
Definition variant.hpp:111
typename from_abstract_next< AbstractT, Type... >::result_type from_abstract_t
Definition variant.hpp:134
constexpr bool is_variant_convertible_v
Definition variant.hpp:114
auto & static_variant_cast(const Variant &var)
Definition variant.hpp:338
Definition plf_hive.h:79
constexpr decltype(auto) visit(Visitor &&vis, neolib::variant< Types... > &&var)
Definition variant.hpp:60
constexpr bool holds_alternative(neolib::variant< Types... > const &var) noexcept
Definition variant.hpp:78
constexpr T & get(neolib::variant< Types... > &var)
Definition variant.hpp:84
from_abstract_next< AbstractT, Rest... >::result_type result_type
Definition variant.hpp:132
from_abstract< is_variant_convertible_v< AbstractT, Type >, AbstractT, Type, Rest >::result_type result_type
Definition variant.hpp:122
from_abstract< is_variant_convertible_v< AbstractT, Type >, AbstractT, Type, Rest... >::result_type result_type
Definition variant.hpp:124
from_abstract< is_variant_convertible_v< AbstractT, Type >, AbstractT, Type >::result_type result_type
Definition variant.hpp:120