]>
Commit | Line | Data |
---|---|---|
b32b8144 FG |
1 | // |
2 | // Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com) | |
3 | // | |
4 | // Distributed under the Boost Software License, Version 1.0. (See accompanying | |
5 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |
6 | // | |
7 | // Official repository: https://github.com/boostorg/beast | |
8 | // | |
9 | ||
10 | #ifndef BOOST_BEAST_DETAIL_VARIANT_HPP | |
11 | #define BOOST_BEAST_DETAIL_VARIANT_HPP | |
12 | ||
13 | #include <boost/beast/core/detail/type_traits.hpp> | |
14 | #include <boost/assert.hpp> | |
15 | #include <cstddef> | |
16 | #include <tuple> | |
17 | #include <type_traits> | |
18 | ||
19 | namespace boost { | |
20 | namespace beast { | |
21 | namespace detail { | |
22 | ||
23 | // This simple variant gets the job done without | |
24 | // causing too much trouble with template depth: | |
25 | // | |
26 | // * Always allows an empty state I==0 | |
27 | // * emplace() and get() support 1-based indexes only | |
28 | // * Basic exception guarantee | |
29 | // * Max 255 types | |
30 | // | |
31 | template<class... TN> | |
32 | class variant | |
33 | { | |
11fdf7f2 | 34 | detail::aligned_union_t<1, TN...> buf_; |
b32b8144 FG |
35 | unsigned char i_ = 0; |
36 | ||
37 | template<std::size_t I> | |
38 | using type = typename std::tuple_element< | |
11fdf7f2 | 39 | I, std::tuple<TN...>>::type; |
b32b8144 FG |
40 | |
41 | template<std::size_t I> | |
42 | using C = std::integral_constant<std::size_t, I>; | |
43 | ||
44 | public: | |
45 | variant() = default; | |
46 | ||
47 | ~variant() | |
48 | { | |
11fdf7f2 TL |
49 | destroy(C<0>{}); |
50 | } | |
51 | ||
52 | bool | |
53 | operator==(variant const& other) const | |
54 | { | |
55 | if(i_ != other.i_) | |
56 | return false; | |
57 | return equal(other, C<0>{}); | |
b32b8144 FG |
58 | } |
59 | ||
60 | // 0 = empty | |
61 | unsigned char | |
62 | index() const | |
63 | { | |
64 | return i_; | |
65 | } | |
66 | ||
67 | // moved-from object becomes empty | |
68 | variant(variant&& other) | |
69 | { | |
70 | i_ = other.move(&buf_, C<0>{}); | |
11fdf7f2 | 71 | other.i_ = 0; |
b32b8144 FG |
72 | } |
73 | ||
74 | variant(variant const& other) | |
75 | { | |
76 | i_ = other.copy(&buf_, C<0>{}); | |
77 | } | |
78 | ||
79 | // moved-from object becomes empty | |
80 | variant& operator=(variant&& other) | |
81 | { | |
11fdf7f2 TL |
82 | if(this != &other) |
83 | { | |
b32b8144 | 84 | destroy(C<0>{}); |
11fdf7f2 TL |
85 | i_ = other.move(&buf_, C<0>{}); |
86 | other.i_ = 0; | |
87 | } | |
b32b8144 FG |
88 | return *this; |
89 | } | |
90 | ||
91 | variant& operator=(variant const& other) | |
92 | { | |
11fdf7f2 TL |
93 | if(this != &other) |
94 | { | |
b32b8144 | 95 | destroy(C<0>{}); |
11fdf7f2 TL |
96 | i_ = other.copy(&buf_, C<0>{}); |
97 | } | |
b32b8144 FG |
98 | return *this; |
99 | } | |
100 | ||
101 | template<std::size_t I, class... Args> | |
102 | void | |
103 | emplace(Args&&... args) | |
104 | { | |
11fdf7f2 | 105 | destroy(C<0>{}); |
b32b8144 FG |
106 | new(&buf_) type<I-1>( |
107 | std::forward<Args>(args)...); | |
108 | i_ = I; | |
109 | } | |
110 | ||
111 | template<std::size_t I> | |
112 | type<I-1>& | |
113 | get() | |
114 | { | |
115 | BOOST_ASSERT(i_ == I); | |
116 | return *reinterpret_cast< | |
117 | type<I-1>*>(&buf_); | |
118 | } | |
119 | ||
120 | template<std::size_t I> | |
121 | type<I-1> const& | |
122 | get() const | |
123 | { | |
124 | BOOST_ASSERT(i_ == I); | |
125 | return *reinterpret_cast< | |
126 | type<I-1> const*>(&buf_); | |
127 | } | |
128 | ||
129 | void | |
130 | reset() | |
131 | { | |
b32b8144 FG |
132 | destroy(C<0>{}); |
133 | } | |
134 | ||
135 | private: | |
136 | void | |
11fdf7f2 | 137 | destroy(C<0>) |
b32b8144 | 138 | { |
11fdf7f2 TL |
139 | auto const I = 0; |
140 | if(i_ == I) | |
141 | return; | |
142 | destroy(C<I+1>{}); | |
143 | i_ = 0; | |
b32b8144 FG |
144 | } |
145 | ||
146 | template<std::size_t I> | |
147 | void | |
148 | destroy(C<I>) | |
149 | { | |
11fdf7f2 | 150 | if(i_ == I) |
b32b8144 | 151 | { |
11fdf7f2 TL |
152 | using T = type<I-1>; |
153 | get<I>().~T(); | |
b32b8144 FG |
154 | return; |
155 | } | |
156 | destroy(C<I+1>{}); | |
157 | } | |
158 | ||
11fdf7f2 TL |
159 | void |
160 | destroy(C<sizeof...(TN)>) | |
161 | { | |
162 | auto const I = sizeof...(TN); | |
163 | BOOST_ASSERT(i_ == I); | |
164 | using T = type<I-1>; | |
165 | get<I>().~T(); | |
166 | } | |
167 | ||
b32b8144 | 168 | unsigned char |
11fdf7f2 | 169 | move(void* dest, C<0>) |
b32b8144 | 170 | { |
11fdf7f2 TL |
171 | auto const I = 0; |
172 | if(i_ == I) | |
173 | return I; | |
174 | return move(dest, C<I+1>{}); | |
b32b8144 FG |
175 | } |
176 | ||
177 | template<std::size_t I> | |
178 | unsigned char | |
179 | move(void* dest, C<I>) | |
180 | { | |
11fdf7f2 | 181 | if(i_ == I) |
b32b8144 | 182 | { |
11fdf7f2 TL |
183 | using T = type<I-1>; |
184 | new(dest) T(std::move(get<I>())); | |
185 | get<I>().~T(); | |
186 | return I; | |
b32b8144 FG |
187 | } |
188 | return move(dest, C<I+1>{}); | |
189 | } | |
190 | ||
191 | unsigned char | |
11fdf7f2 TL |
192 | move(void* dest, C<sizeof...(TN)>) |
193 | { | |
194 | auto const I = sizeof...(TN); | |
195 | BOOST_ASSERT(i_ == I); | |
196 | using T = type<I-1>; | |
197 | new(dest) T(std::move(get<I>())); | |
198 | get<I>().~T(); | |
199 | return I; | |
200 | } | |
201 | ||
202 | unsigned char | |
203 | copy(void* dest, C<0>) const | |
b32b8144 | 204 | { |
11fdf7f2 TL |
205 | auto const I = 0; |
206 | if(i_ == I) | |
207 | return I; | |
208 | return copy(dest, C<I+1>{}); | |
b32b8144 FG |
209 | } |
210 | ||
211 | template<std::size_t I> | |
212 | unsigned char | |
213 | copy(void* dest, C<I>) const | |
214 | { | |
11fdf7f2 | 215 | if(i_ == I) |
b32b8144 | 216 | { |
11fdf7f2 TL |
217 | using T = type<I-1>; |
218 | auto const& t = get<I>(); | |
219 | new(dest) T(t); | |
220 | return I; | |
b32b8144 FG |
221 | } |
222 | return copy(dest, C<I+1>{}); | |
223 | } | |
11fdf7f2 TL |
224 | |
225 | unsigned char | |
226 | copy(void* dest, C<sizeof...(TN)>) const | |
227 | { | |
228 | auto const I = sizeof...(TN); | |
229 | BOOST_ASSERT(i_ == I); | |
230 | using T = type<I-1>; | |
231 | auto const& t = get<I>(); | |
232 | new(dest) T(t); | |
233 | return I; | |
234 | } | |
235 | ||
236 | bool | |
237 | equal(variant const& other, C<0>) const | |
238 | { | |
239 | auto constexpr I = 0; | |
240 | if(i_ == I) | |
241 | return true; | |
242 | return equal(other, C<I+1>{}); | |
243 | } | |
244 | ||
245 | template<std::size_t I> | |
246 | bool | |
247 | equal(variant const& other, C<I>) const | |
248 | { | |
249 | if(i_ == I) | |
250 | return get<I>() == other.get<I>(); | |
251 | return equal(other, C<I+1>{}); | |
252 | } | |
253 | ||
254 | bool | |
255 | equal(variant const& other, C<sizeof...(TN)>) const | |
256 | { | |
257 | auto constexpr I = sizeof...(TN); | |
258 | BOOST_ASSERT(i_ == I); | |
259 | return get<I>() == other.get<I>(); | |
260 | } | |
b32b8144 FG |
261 | }; |
262 | ||
263 | } // detail | |
264 | } // beast | |
265 | } // boost | |
266 | ||
267 | #endif |