You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

318 lines
11KB

  1. /// \file
  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. #ifndef RANGES_V3_UTILITY_SEMIREGULAR_BOX_HPP
  14. #define RANGES_V3_UTILITY_SEMIREGULAR_BOX_HPP
  15. #include <utility>
  16. #include <meta/meta.hpp>
  17. #include <concepts/concepts.hpp>
  18. #include <range/v3/range_fwd.hpp>
  19. #include <range/v3/utility/get.hpp>
  20. #include <range/v3/utility/in_place.hpp>
  21. namespace ranges
  22. {
  23. /// \cond
  24. template<typename T>
  25. struct semiregular_box;
  26. namespace detail
  27. {
  28. struct semiregular_get
  29. {
  30. // clang-format off
  31. template<typename T>
  32. friend auto CPP_auto_fun(get)(meta::id_t<semiregular_box<T>> &t)
  33. (
  34. return t.get()
  35. )
  36. template<typename T>
  37. friend auto CPP_auto_fun(get)(meta::id_t<semiregular_box<T>> const &t)
  38. (
  39. return t.get()
  40. )
  41. template<typename T>
  42. friend auto CPP_auto_fun(get)(meta::id_t<semiregular_box<T>> &&t)
  43. (
  44. return detail::move(t).get()
  45. )
  46. // clang-format on
  47. };
  48. } // namespace detail
  49. /// \endcond
  50. /// \addtogroup group-utility
  51. /// @{
  52. template<typename T>
  53. struct semiregular_box : private detail::semiregular_get
  54. {
  55. private:
  56. struct tag
  57. {};
  58. template<typename... Args>
  59. void construct_from(Args &&... args)
  60. {
  61. new((void *)std::addressof(data_)) T(static_cast<Args &&>(args)...);
  62. engaged_ = true;
  63. }
  64. void move_assign(T && t, std::true_type)
  65. {
  66. data_ = detail::move(t);
  67. }
  68. void move_assign(T && t, std::false_type)
  69. {
  70. reset();
  71. construct_from(detail::move(t));
  72. }
  73. void copy_assign(T const & t, std::true_type)
  74. {
  75. data_ = t;
  76. }
  77. void copy_assign(T && t, std::false_type)
  78. {
  79. reset();
  80. construct_from(t);
  81. }
  82. constexpr semiregular_box(tag, std::false_type) noexcept
  83. {}
  84. constexpr semiregular_box(tag, std::true_type) noexcept(
  85. std::is_nothrow_default_constructible<T>::value)
  86. : data_{}
  87. , engaged_(true)
  88. {}
  89. void reset()
  90. {
  91. if(engaged_)
  92. {
  93. data_.~T();
  94. engaged_ = false;
  95. }
  96. }
  97. union
  98. {
  99. char ch_{};
  100. T data_;
  101. };
  102. bool engaged_{false};
  103. public:
  104. constexpr semiregular_box() noexcept(
  105. std::is_nothrow_default_constructible<T>::value ||
  106. !std::is_default_constructible<T>::value)
  107. : semiregular_box(tag{}, std::is_default_constructible<T>{})
  108. {}
  109. semiregular_box(semiregular_box && that) noexcept(
  110. std::is_nothrow_move_constructible<T>::value)
  111. {
  112. if(that.engaged_)
  113. this->construct_from(detail::move(that.data_));
  114. }
  115. semiregular_box(semiregular_box const & that) noexcept(
  116. std::is_nothrow_copy_constructible<T>::value)
  117. {
  118. if(that.engaged_)
  119. this->construct_from(that.data_);
  120. }
  121. #if defined(__cpp_conditional_explicit) && 0 < __cpp_conditional_explicit
  122. template<typename U>
  123. explicit(!convertible_to<U, T>) constexpr CPP_ctor(semiregular_box)(U && u)( //
  124. noexcept(std::is_nothrow_constructible<T, U>::value) //
  125. requires(!defer::same_as<uncvref_t<U>, semiregular_box>) &&
  126. defer::constructible_from<T, U>)
  127. : semiregular_box(in_place, static_cast<U &&>(u))
  128. {}
  129. #else
  130. template<typename U>
  131. explicit constexpr CPP_ctor(semiregular_box)(U && u)( //
  132. noexcept(std::is_nothrow_constructible<T, U>::value) //
  133. requires(!defer::same_as<uncvref_t<U>, semiregular_box>) &&
  134. defer::constructible_from<T, U> && (!defer::convertible_to<U, T>))
  135. : semiregular_box(in_place, static_cast<U &&>(u))
  136. {}
  137. template<typename U>
  138. constexpr CPP_ctor(semiregular_box)(U && u)( //
  139. noexcept(std::is_nothrow_constructible<T, U>::value) //
  140. requires(!defer::same_as<uncvref_t<U>, semiregular_box>) &&
  141. defer::constructible_from<T, U> && defer::convertible_to<U, T>)
  142. : semiregular_box(in_place, static_cast<U &&>(u))
  143. {}
  144. #endif
  145. CPP_template(typename... Args)( //
  146. requires constructible_from<T, Args...>) //
  147. constexpr semiregular_box(in_place_t, Args &&... args) //
  148. noexcept(std::is_nothrow_constructible<T, Args...>::value)
  149. : data_(static_cast<Args &&>(args)...)
  150. , engaged_(true)
  151. {}
  152. ~semiregular_box()
  153. {
  154. reset();
  155. }
  156. semiregular_box & operator=(semiregular_box && that) noexcept(
  157. std::is_nothrow_move_constructible<T>::value &&
  158. (!std::is_move_assignable<T>::value ||
  159. std::is_nothrow_move_assignable<T>::value))
  160. {
  161. if(engaged_ && that.engaged_)
  162. this->move_assign(detail::move(that.data_), std::is_move_assignable<T>());
  163. else if(that.engaged_)
  164. this->construct_from(detail::move(that.data_));
  165. else if(engaged_)
  166. this->reset();
  167. return *this;
  168. }
  169. semiregular_box & operator=(semiregular_box const & that) noexcept(
  170. std::is_nothrow_copy_constructible<T>::value &&
  171. (!std::is_copy_assignable<T>::value ||
  172. std::is_nothrow_copy_assignable<T>::value))
  173. {
  174. if(engaged_ && that.engaged_)
  175. this->copy_assign(that.data_, std::is_copy_assignable<T>());
  176. else if(that.engaged_)
  177. this->construct_from(that.data_);
  178. else if(engaged_)
  179. this->reset();
  180. return *this;
  181. }
  182. semiregular_box & operator=(T t) noexcept(
  183. std::is_nothrow_move_constructible<T>::value &&
  184. (!std::is_move_assignable<T>::value ||
  185. std::is_nothrow_move_assignable<T>::value))
  186. {
  187. if(engaged_)
  188. this->move_assign(detail::move(t), std::is_move_assignable<T>());
  189. else
  190. this->construct_from(detail::move(t));
  191. return *this;
  192. }
  193. constexpr T & get() & noexcept
  194. {
  195. return RANGES_ENSURE(engaged_), data_;
  196. }
  197. constexpr T const & get() const & noexcept
  198. {
  199. return RANGES_ENSURE(engaged_), data_;
  200. }
  201. constexpr T && get() && noexcept
  202. {
  203. return RANGES_ENSURE(engaged_), detail::move(data_);
  204. }
  205. T const && get() const && = delete;
  206. constexpr operator T &() & noexcept
  207. {
  208. return get();
  209. }
  210. constexpr operator T const &() const & noexcept
  211. {
  212. return get();
  213. }
  214. constexpr operator T &&() && noexcept
  215. {
  216. return detail::move(get());
  217. }
  218. operator T const &&() const && = delete;
  219. // clang-format off
  220. template<typename... Args>
  221. constexpr auto CPP_auto_fun(operator())(Args &&... args)(mutable &)
  222. (
  223. return data_(static_cast<Args &&>(args)...)
  224. )
  225. template<typename... Args>
  226. constexpr auto CPP_auto_fun(operator())(Args &&... args)(const &)
  227. (
  228. return data_(static_cast<Args &&>(args)...)
  229. )
  230. #ifdef RANGES_WORKAROUND_MSVC_786376
  231. template<typename... Args, typename U = T>
  232. constexpr auto CPP_auto_fun(operator())(Args &&... args)(mutable &&)
  233. (
  234. return ((U &&) data_)(static_cast<Args &&>(args)...)
  235. )
  236. #else // ^^^ workaround / no workaround vvv
  237. template<typename... Args>
  238. constexpr auto CPP_auto_fun(operator())(Args &&... args)(mutable &&)
  239. (
  240. return ((T &&) data_)(static_cast<Args &&>(args)...)
  241. )
  242. #endif // RANGES_WORKAROUND_MSVC_786376
  243. // clang-format on
  244. template<typename... Args>
  245. void operator()(Args &&...) const && = delete;
  246. };
  247. template<typename T>
  248. struct semiregular_box<T &>
  249. : private ranges::reference_wrapper<T &>
  250. , private detail::semiregular_get
  251. {
  252. semiregular_box() = default;
  253. template<typename Arg>
  254. CPP_ctor(semiregular_box)(in_place_t, Arg & arg)( //
  255. noexcept(true) //
  256. requires constructible_from<ranges::reference_wrapper<T &>, Arg &>)
  257. : ranges::reference_wrapper<T &>(arg)
  258. {}
  259. using ranges::reference_wrapper<T &>::reference_wrapper;
  260. using ranges::reference_wrapper<T &>::get;
  261. using ranges::reference_wrapper<T &>::operator T &;
  262. using ranges::reference_wrapper<T &>::operator();
  263. };
  264. template<typename T>
  265. struct semiregular_box<T &&>
  266. : private ranges::reference_wrapper<T &&>
  267. , private detail::semiregular_get
  268. {
  269. semiregular_box() = default;
  270. template<typename Arg>
  271. CPP_ctor(semiregular_box)(in_place_t, Arg && arg)( //
  272. noexcept(true) //
  273. requires constructible_from<ranges::reference_wrapper<T &&>, Arg>)
  274. : ranges::reference_wrapper<T &&>(static_cast<Arg &&>(arg))
  275. {}
  276. using ranges::reference_wrapper<T &&>::reference_wrapper;
  277. using ranges::reference_wrapper<T &&>::get;
  278. using ranges::reference_wrapper<T &&>::operator T &&;
  279. using ranges::reference_wrapper<T &&>::operator();
  280. };
  281. template<typename T>
  282. using semiregular_box_t = meta::if_c<(bool)semiregular<T>, T, semiregular_box<T>>;
  283. template<typename T, bool IsConst = false>
  284. using semiregular_box_ref_or_val_t =
  285. meta::if_c<(bool)semiregular<T>, meta::if_c<IsConst, T, reference_wrapper<T>>,
  286. reference_wrapper<meta::if_c<IsConst, semiregular_box<T> const,
  287. semiregular_box<T>>>>;
  288. /// @}
  289. /// \cond
  290. template<typename T>
  291. using semiregular_t RANGES_DEPRECATED("Please use semiregular_box_t instead.") =
  292. semiregular_box_t<T>;
  293. template<typename T, bool IsConst = false>
  294. using semiregular_ref_or_val_t RANGES_DEPRECATED(
  295. "Please use semiregular_box_t instead.") =
  296. semiregular_box_ref_or_val_t<T, IsConst>;
  297. /// \endcond
  298. } // namespace ranges
  299. #endif