Horizon
Loading...
Searching...
No Matches
semiregular_box.hpp
Go to the documentation of this file.
1
2// Range v3 library
3//
4// Copyright Eric Niebler 2013-present
5//
6// Use, modification and distribution is subject to the
7// Boost Software License, Version 1.0. (See accompanying
8// file LICENSE_1_0.txt or copy at
9// http://www.boost.org/LICENSE_1_0.txt)
10//
11// Project home: https://github.com/ericniebler/range-v3
12//
13
14#ifndef RANGES_V3_UTILITY_SEMIREGULAR_BOX_HPP
15#define RANGES_V3_UTILITY_SEMIREGULAR_BOX_HPP
16
17#include <type_traits>
18#include <utility>
19
20#include <meta/meta.hpp>
21
22#include <concepts/concepts.hpp>
23
25
31
32#include <range/v3/detail/prologue.hpp>
33
34namespace ranges
35{
37 template<typename T>
38 struct semiregular_box;
39
40 namespace detail
41 {
42 struct semiregular_get
43 {
44 // clang-format off
45 template<typename T>
46 friend auto CPP_auto_fun(get)(meta::id_t<semiregular_box<T>> &t)
47 (
48 return t.get()
49 )
50 template<typename T>
51 friend auto CPP_auto_fun(get)(meta::id_t<semiregular_box<T>> const &t)
52 (
53 return t.get()
54 )
55 template<typename T>
56 friend auto CPP_auto_fun(get)(meta::id_t<semiregular_box<T>> &&t)
57 (
58 return detail::move(t).get()
59 )
60 // clang-format on
61 };
62 } // namespace detail
64
67 template<typename T>
68 struct semiregular_box : private detail::semiregular_get
69 {
70 private:
71 struct tag
72 {};
73 template<typename... Args>
74 void construct_from(Args &&... args)
75 {
76 new((void *)std::addressof(data_)) T(static_cast<Args &&>(args)...);
77 engaged_ = true;
78 }
79 void move_assign(T && t, std::true_type)
80 {
81 data_ = detail::move(t);
82 }
83 void move_assign(T && t, std::false_type)
84 {
85 reset();
86 construct_from(detail::move(t));
87 }
88 void copy_assign(T const & t, std::true_type)
89 {
90 data_ = t;
91 }
92 void copy_assign(T && t, std::false_type)
93 {
94 reset();
95 construct_from(t);
96 }
97 constexpr semiregular_box(tag, std::false_type) noexcept
98 {}
99 constexpr semiregular_box(tag, std::true_type) noexcept(
100 std::is_nothrow_default_constructible<T>::value)
101 : data_{}
102 , engaged_(true)
103 {}
104 void reset()
105 {
106 if(engaged_)
107 {
108 data_.~T();
109 engaged_ = false;
110 }
111 }
112 union
113 {
114 char ch_{};
115 T data_;
116 };
117 bool engaged_{false};
118
119 public:
120 constexpr semiregular_box() noexcept(
121 std::is_nothrow_default_constructible<T>::value ||
122 !std::is_default_constructible<T>::value)
123 : semiregular_box(tag{}, std::is_default_constructible<T>{})
124 {}
125 semiregular_box(semiregular_box && that) noexcept(
126 std::is_nothrow_move_constructible<T>::value)
127 {
128 if(that.engaged_)
129 this->construct_from(detail::move(that.data_));
130 }
131 semiregular_box(semiregular_box const & that) noexcept(
132 std::is_nothrow_copy_constructible<T>::value)
133 {
134 if(that.engaged_)
135 this->construct_from(that.data_);
136 }
137#if defined(__cpp_conditional_explicit) && 0 < __cpp_conditional_explicit
138 template(typename U)(
139 requires (!same_as<uncvref_t<U>, semiregular_box>) AND
140 constructible_from<T, U>)
141 explicit(!convertible_to<U, T>) constexpr semiregular_box(U && u)
142 noexcept(std::is_nothrow_constructible<T, U>::value)
143 : semiregular_box(in_place, static_cast<U &&>(u))
144 {}
145#else
146 template(typename U)(
147 requires (!same_as<uncvref_t<U>, semiregular_box>) AND
148 constructible_from<T, U> AND (!convertible_to<U, T>)) //
149 constexpr explicit semiregular_box(U && u)
150 noexcept(std::is_nothrow_constructible<T, U>::value)
151 : semiregular_box(in_place, static_cast<U &&>(u))
152 {}
153 template(typename U)(
154 requires (!same_as<uncvref_t<U>, semiregular_box>) AND
155 constructible_from<T, U> AND convertible_to<U, T>)
156 constexpr semiregular_box(U && u)
157 noexcept(std::is_nothrow_constructible<T, U>::value)
158 : semiregular_box(in_place, static_cast<U &&>(u))
159 {}
160#endif
161 template(typename... Args)(
162 requires constructible_from<T, Args...>)
163 constexpr semiregular_box(in_place_t, Args &&... args) //
164 noexcept(std::is_nothrow_constructible<T, Args...>::value)
165 : data_(static_cast<Args &&>(args)...)
166 , engaged_(true)
167 {}
169 {
170 reset();
171 }
172 semiregular_box & operator=(semiregular_box && that) noexcept(
173 std::is_nothrow_move_constructible<T>::value &&
174 (!std::is_move_assignable<T>::value ||
175 std::is_nothrow_move_assignable<T>::value))
176 {
177 if(engaged_ && that.engaged_)
178 this->move_assign(detail::move(that.data_), std::is_move_assignable<T>());
179 else if(that.engaged_)
180 this->construct_from(detail::move(that.data_));
181 else if(engaged_)
182 this->reset();
183 return *this;
184 }
185 semiregular_box & operator=(semiregular_box const & that) noexcept(
186 std::is_nothrow_copy_constructible<T>::value &&
187 (!std::is_copy_assignable<T>::value ||
188 std::is_nothrow_copy_assignable<T>::value))
189 {
190 if(engaged_ && that.engaged_)
191 this->copy_assign(that.data_, std::is_copy_assignable<T>());
192 else if(that.engaged_)
193 this->construct_from(that.data_);
194 else if(engaged_)
195 this->reset();
196 return *this;
197 }
198 constexpr T & get() & noexcept
199 {
200 return RANGES_ENSURE(engaged_), data_;
201 }
202 constexpr T const & get() const & noexcept
203 {
204 return RANGES_ENSURE(engaged_), data_;
205 }
206 constexpr T && get() && noexcept
207 {
208 return RANGES_ENSURE(engaged_), detail::move(data_);
209 }
210 T const && get() const && = delete;
211 constexpr operator T &() & noexcept
212 {
213 return get();
214 }
215 constexpr operator T const &() const & noexcept
216 {
217 return get();
218 }
219 constexpr operator T &&() && noexcept
220 {
221 return detail::move(get());
222 }
223 operator T const &&() const && = delete;
224 // clang-format off
225 template(typename... Args)(
227 constexpr decltype(auto) operator()(Args &&... args) &
228 noexcept(is_nothrow_invocable_v<T &, Args...>)
229 {
230 return invoke(data_, static_cast<Args &&>(args)...);
231 }
232 template(typename... Args)(
234 constexpr decltype(auto) operator()(Args &&... args) const &
235 noexcept(is_nothrow_invocable_v<T const &, Args...>)
236 {
237 return invoke(data_, static_cast<Args &&>(args)...);
238 }
239 template(typename... Args)(
240 requires invocable<T, Args...>)
241 constexpr decltype(auto) operator()(Args &&... args) &&
242 noexcept(is_nothrow_invocable_v<T, Args...>)
243 {
244 return invoke(static_cast<T &&>(data_), static_cast<Args &&>(args)...);
245 }
246 template<typename... Args>
247 void operator()(Args &&...) const && = delete;
248 // clang-format on
249 };
250
251 template<typename T>
252 struct semiregular_box<T &>
254 , private detail::semiregular_get
255 {
256 semiregular_box() = default;
257 template(typename Arg)(
258 requires constructible_from<ranges::reference_wrapper<T &>, Arg &>)
259 semiregular_box(in_place_t, Arg & arg) noexcept //
261 {}
262 using ranges::reference_wrapper<T &>::get;
263 using ranges::reference_wrapper<T &>::operator T &;
264 using ranges::reference_wrapper<T &>::operator();
265
266#if defined(_MSC_VER)
267 template(typename U)(
268 requires (!same_as<uncvref_t<U>, semiregular_box>) AND
269 constructible_from<ranges::reference_wrapper<T &>, U>)
270 constexpr semiregular_box(U && u) noexcept(
271 std::is_nothrow_constructible<ranges::reference_wrapper<T &>, U>::value)
272 : ranges::reference_wrapper<T &>{static_cast<U &&>(u)}
273 {}
274#else
275 using ranges::reference_wrapper<T &>::reference_wrapper;
276#endif
277 };
278
279 template<typename T>
280 struct semiregular_box<T &&>
282 , private detail::semiregular_get
283 {
284 semiregular_box() = default;
285 template(typename Arg)(
286 requires constructible_from<ranges::reference_wrapper<T &&>, Arg>)
287 semiregular_box(in_place_t, Arg && arg) noexcept //
288 : ranges::reference_wrapper<T &&>(static_cast<Arg &&>(arg))
289 {}
290 using ranges::reference_wrapper<T &&>::get;
291 using ranges::reference_wrapper<T &&>::operator T &&;
292 using ranges::reference_wrapper<T &&>::operator();
293
294#if defined(_MSC_VER)
295 template(typename U)(
296 requires (!same_as<uncvref_t<U>, semiregular_box>) AND
297 constructible_from<ranges::reference_wrapper<T &&>, U>)
298 constexpr semiregular_box(U && u) noexcept(
299 std::is_nothrow_constructible<ranges::reference_wrapper<T &&>, U>::value)
300 : ranges::reference_wrapper<T &&>{static_cast<U &&>(u)}
301 {}
302#else
303 using ranges::reference_wrapper<T &&>::reference_wrapper;
304#endif
305 };
306
307 template<typename T>
308 using semiregular_box_t = meta::if_c<(bool)semiregular<T>, T, semiregular_box<T>>;
309
310 template<typename T, bool IsConst = false>
311 using semiregular_box_ref_or_val_t = meta::if_c<
312 (bool)semiregular<T>,
313 meta::if_c<IsConst || std::is_empty<T>::value, T, reference_wrapper<T>>,
315 meta::if_c<IsConst, semiregular_box<T> const, semiregular_box<T>>>>;
317
319 template<typename T>
320 using semiregular_t RANGES_DEPRECATED("Please use semiregular_box_t instead.") =
321 semiregular_box_t<T>;
322
323 template<typename T, bool IsConst = false>
324 using semiregular_ref_or_val_t RANGES_DEPRECATED(
325 "Please use semiregular_box_ref_or_val_t instead.") =
326 semiregular_box_ref_or_val_t<T, IsConst>;
328
329} // namespace ranges
330
331#include <range/v3/detail/epilogue.hpp>
332
333#endif
The invocable concept.
_t< id< T > > id_t
An alias for type T.
Definition meta.hpp:577
Tiny meta-programming library.
Definition in_place.hpp:27
Definition reference_wrapper.hpp:76
Definition semiregular_box.hpp:69