Horizon
semiregular_box.hpp
Go to the documentation of this file.
1 // 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 
24 #include <range/v3/range_fwd.hpp>
25 
29 #include <range/v3/utility/get.hpp>
31 
32 #include <range/v3/detail/prologue.hpp>
33 
34 namespace 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  {}
168  ~semiregular_box()
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)(
226  requires invocable<T &, 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)(
233  requires invocable<T const &, 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  {}
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
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  {}
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
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
typename Fn::template invoke< Args... > invoke
Evaluate the invocable Fn with the arguments Args.
Definition: meta.hpp:541
_t< id< T > > id_t
An alias for type T.
Definition: meta.hpp:577
Tiny meta-programming library.
Definition: in_place.hpp:27
Definition: semiregular_box.hpp:69