neoGFX
Cross-platform C++ app/game engine
Loading...
Searching...
No Matches
i_plugin_variant.hpp
Go to the documentation of this file.
1// i_plugin_variant.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>
43
44namespace neolib
45{
46 namespace detail
47 {
49 {
50 template <typename Visitor, typename Variant>
51 using funky_visit_t = std::function<void(const Visitor&, Variant&)>;
52 template <typename Visitor, typename Variant>
53 using funky_visit_list_t = std::vector<funky_visit_t<Visitor, Variant>>;
54 template <typename Visitor, typename Variant>
56 {
57 return aList.size();
58 }
59 template <typename Visitor, typename Variant, typename T, typename... Types>
61 {
62 aList.push_back(
63 [](const Visitor& aVisitor, Variant& aThis)
64 {
65 typedef std::decay_t<T> type;
66 aVisitor(aThis.template get<type>());
67 });
68 return funky_gen_visit<Visitor, Variant, Types...>(aList);
69 }
70 }
71 }
72
73 struct bad_variant_access : std::invalid_argument { bad_variant_access() : std::invalid_argument{ "neolib::bad_variant_access" } {} };
74 struct variant_type_not_equality_comparable : std::invalid_argument { variant_type_not_equality_comparable() : std::invalid_argument{ "neolib::variant_type_not_equality_comparable" } {} };
75 struct variant_type_not_less_than_comparable : std::invalid_argument { variant_type_not_less_than_comparable() : std::invalid_argument{ "neolib::variant_type_not_less_than_comparable" } {} };
76 struct variant_type_not_convertible : std::invalid_argument { variant_type_not_convertible() : std::invalid_argument{ "neolib::variant_type_not_convertible" } {} };
77
78 template <typename Id, typename... Types>
80 {
81 typedef i_plugin_variant<Id, Types...> self_type;
82 template <typename, typename...>
83 friend class plugin_variant;
84 // exceptions
85 public:
86 // types
87 public:
88 typedef self_type abstract_type;
89 typedef Id id_t;
90 typedef std::size_t index_type;
91 // construction/assignment
92 public:
94 {
95 return do_clone();
96 }
97 self_type& operator=(const self_type& aOther)
98 {
99 if (!aOther.empty())
100 return do_assign(aOther.which(), aOther.data());
101 clear();
102 return *this;
103 }
104 self_type& operator=(self_type&& aOther)
105 {
106 if (!aOther.empty())
107 {
108 auto& result = do_move_assign(aOther.which(), aOther.data());
109 aOther.clear();
110 return result;
111 }
112 clear();
113 return *this;
114 }
115 template <typename T>
116 std::enable_if_t<!std::is_base_of_v<self_type, T>, self_type>& operator=(const T& aArgument)
117 {
118 return do_assign(static_cast<id_t>(variadic::index_v<T, Types...>), &aArgument);
119 }
120 template <typename T>
121 std::enable_if_t<!std::is_base_of_v<self_type, std::remove_reference_t<T>>, self_type>& operator=(T&& aArgument)
122 {
123 return do_move_assign(static_cast<id_t>(variadic::no_reference_index_v<T, Types...>), &aArgument);
124 }
125 self_type& operator=(const none_t)
126 {
127 clear();
128 return *this;
129 }
130 // comparison
131 public:
132 virtual bool operator==(const self_type& that) const = 0;
133 virtual bool operator<(const self_type& that) const = 0;
134 std::partial_ordering operator<=>(const self_type& that) const
135 {
136 if (*this == that)
137 return std::partial_ordering::equivalent;
138 else if (*this < that)
139 return std::partial_ordering::less;
140 else
141 return std::partial_ordering::greater;
142 }
143 bool operator==(const none_t) const
144 {
145 return empty();
146 }
147 bool operator!=(const none_t) const
148 {
149 return !empty();
150 }
151 // state
152 public:
153 virtual void clear() = 0;
154 virtual id_t which() const = 0;
155 virtual bool empty() const = 0;
156 template <typename T>
157 const T& get() const
158 {
159 if (which() == static_cast<id_t>(variadic::index_v<T, Types...>))
160 return *static_cast<const T*>(data());
161 throw bad_variant_access();
162 }
163 template <typename T>
164 T& get()
165 {
166 if (which() == static_cast<id_t>(variadic::index_v<T, Types...>))
167 return *static_cast<T*>(data());
168 throw bad_variant_access();
169 }
170 // meta
171 public:
172 virtual const typename i_enum_t<Id>::enumerators_t& ids() const = 0;
173 // implementation
174 private:
175 virtual std::size_t index() const = 0;
176 virtual const void* data() const = 0;
177 virtual void* data() = 0;
178 virtual self_type* do_clone() const = 0;
179 virtual self_type& do_assign(id_t aType, const void* aData) = 0;
180 virtual self_type& do_move_assign(id_t aType, void* aData) = 0;
181 };
182
183 namespace variant_visitors
184 {
185 template <typename Visitor, typename Id, typename... Types>
186 inline void visit(Visitor aVisitor, const i_plugin_variant<Id, Types...>& aVariant)
187 {
188 typedef const i_plugin_variant<Id, Types...> variant_type;
190 static auto const n = detail::i_plugin_variant::funky_gen_visit<Visitor, variant_type, Types...>(funks);
191 auto const which = aVariant.which();
192 auto const index = static_cast<std::size_t>(which);
193 if (index < n)
194 funks[index](aVisitor, aVariant);
195 else
196 throw std::bad_variant_access();
197 }
198
199 template <typename Visitor, typename Id, typename... Types>
200 inline void visit(Visitor aVisitor, i_plugin_variant<Id, Types...>& aVariant)
201 {
202 typedef i_plugin_variant<Id, Types...> variant_type;
204 static auto const n = detail::i_plugin_variant::funky_gen_visit<Visitor, variant_type, Types...>(funks);
205 auto const which = aVariant.which();
206 auto const index = static_cast<std::size_t>(which);
207 if (index < n)
208 funks[index](aVisitor, aVariant);
209 else
210 throw std::bad_variant_access();
211 }
212 }
213
214 template <typename T, typename Id, typename... Types>
215 inline T get_as(const i_plugin_variant<Id, Types...>& aVariant)
216 {
217 T result;
218 variant_visitors::visit([&result](auto&& v)
219 {
220 if constexpr (std::is_convertible_v<decltype(v), T>)
221 result = static_cast<T>(v);
222 else
224 }, aVariant);
225 return result;
226 }
227}
228
229namespace std
230{
231 using neolib::variant_visitors::visit;
232}
233
self_type & operator=(const none_t)
virtual bool empty() const =0
virtual const i_enum_t< Id >::enumerators_t & ids() const =0
std::enable_if_t<!std::is_base_of_v< self_type, std::remove_reference_t< T > >, self_type > & operator=(T &&aArgument)
ref_ptr< self_type > clone() const
std::enable_if_t<!std::is_base_of_v< self_type, T >, self_type > & operator=(const T &aArgument)
virtual void clear()=0
std::partial_ordering operator<=>(const self_type &that) const
bool operator==(const none_t) const
self_type & operator=(const self_type &aOther)
virtual bool operator<(const self_type &that) const =0
virtual bool operator==(const self_type &that) const =0
virtual id_t which() const =0
self_type & operator=(self_type &&aOther)
bool operator!=(const none_t) const
std::function< void(const Visitor &, Variant &)> funky_visit_t
std::vector< funky_visit_t< Visitor, Variant > > funky_visit_list_t
std::size_t funky_gen_visit(funky_visit_list_t< Visitor, Variant > &aList)
T get_as(const i_plugin_variant< Id, Types... > &aVariant)
i_basic_enum< std::underlying_type_t< T > > i_enum_t
Definition i_enum.hpp:211
std::monostate none_t
Definition variant.hpp:110
Definition plf_hive.h:79