box.hpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370
  1. /// \file
  2. // Range v3 library
  3. //
  4. // Copyright Eric Niebler 2013-present
  5. // Copyright Casey Carter 2016
  6. //
  7. // Use, modification and distribution is subject to the
  8. // Boost Software License, Version 1.0. (See accompanying
  9. // file LICENSE_1_0.txt or copy at
  10. // http://www.boost.org/LICENSE_1_0.txt)
  11. //
  12. // Project home: https://github.com/ericniebler/range-v3
  13. //
  14. #ifndef RANGES_V3_UTILITY_BOX_HPP
  15. #define RANGES_V3_UTILITY_BOX_HPP
  16. #include <cstdlib>
  17. #include <type_traits>
  18. #include <utility>
  19. #include <meta/meta.hpp>
  20. #include <concepts/concepts.hpp>
  21. #include <range/v3/range_fwd.hpp>
  22. #include <range/v3/utility/get.hpp>
  23. #include <range/v3/detail/prologue.hpp>
  24. RANGES_DIAGNOSTIC_PUSH
  25. RANGES_DIAGNOSTIC_IGNORE_DEPRECATED_DECLARATIONS
  26. namespace ranges
  27. {
  28. /// \addtogroup group-utility Utility
  29. /// @{
  30. ///
  31. /// \cond
  32. template<typename T>
  33. struct RANGES_DEPRECATED("The ranges::mutable_ class template is deprecated") mutable_
  34. {
  35. mutable T value;
  36. CPP_member
  37. constexpr CPP_ctor(mutable_)()(
  38. requires std::is_default_constructible<T>::value)
  39. : value{}
  40. {}
  41. constexpr explicit mutable_(T const & t)
  42. : value(t)
  43. {}
  44. constexpr explicit mutable_(T && t)
  45. : value(detail::move(t))
  46. {}
  47. mutable_ const & operator=(T const & t) const
  48. {
  49. value = t;
  50. return *this;
  51. }
  52. mutable_ const & operator=(T && t) const
  53. {
  54. value = detail::move(t);
  55. return *this;
  56. }
  57. constexpr operator T &() const &
  58. {
  59. return value;
  60. }
  61. };
  62. template<typename T, T v>
  63. struct RANGES_DEPRECATED("The ranges::constant class template is deprecated") constant
  64. {
  65. constant() = default;
  66. constexpr explicit constant(T const &)
  67. {}
  68. constant & operator=(T const &)
  69. {
  70. return *this;
  71. }
  72. constant const & operator=(T const &) const
  73. {
  74. return *this;
  75. }
  76. constexpr operator T() const
  77. {
  78. return v;
  79. }
  80. constexpr T exchange(T const &) const
  81. {
  82. return v;
  83. }
  84. };
  85. /// \endcond
  86. /// \cond
  87. namespace detail
  88. {
  89. // "box" has three different implementations that store a T differently:
  90. enum class box_compress
  91. {
  92. none, // Nothing special: get() returns a reference to a T member subobject
  93. ebo, // Apply Empty Base Optimization: get() returns a reference to a T base
  94. // subobject
  95. coalesce // Coalesce all Ts into one T: get() returns a reference to a static
  96. // T singleton
  97. };
  98. // Per N4582, lambda closures are *not*:
  99. // - aggregates ([expr.prim.lambda]/4)
  100. // - default constructible_from ([expr.prim.lambda]/p21)
  101. // - copy assignable ([expr.prim.lambda]/p21)
  102. template<typename Fn>
  103. using could_be_lambda = meta::bool_<!std::is_default_constructible<Fn>::value &&
  104. !std::is_copy_assignable<Fn>::value>;
  105. template<typename>
  106. constexpr box_compress box_compression_(...)
  107. {
  108. return box_compress::none;
  109. }
  110. template<typename T, typename = meta::if_<meta::strict_and<
  111. std::is_empty<T>,
  112. meta::bool_<!detail::is_final_v<T>>
  113. #if defined(__GNUC__) && !defined(__clang__) && __GNUC__ == 6 && __GNUC_MINOR__ < 2
  114. // GCC 6.0 & 6.1 find empty lambdas' implicit conversion
  115. // to function pointer when doing overload resolution
  116. // for function calls. That causes hard errors.
  117. // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=71117
  118. ,
  119. meta::not_<could_be_lambda<T>>
  120. #endif
  121. >>>
  122. constexpr box_compress box_compression_(long)
  123. {
  124. return box_compress::ebo;
  125. }
  126. #ifndef RANGES_WORKAROUND_MSVC_249830
  127. // MSVC pukes passing non-constant-expression objects to constexpr
  128. // functions, so do not coalesce.
  129. template<typename T,
  130. typename =
  131. meta::if_<meta::strict_and<std::is_empty<T>, detail::is_trivial<T>>>>
  132. constexpr box_compress box_compression_(int)
  133. {
  134. return box_compress::coalesce;
  135. }
  136. #endif
  137. template<typename T>
  138. constexpr box_compress box_compression()
  139. {
  140. return box_compression_<T>(0);
  141. }
  142. } // namespace detail
  143. /// \endcond
  144. template<typename Element, typename Tag = void,
  145. detail::box_compress = detail::box_compression<Element>()>
  146. class box
  147. {
  148. Element value;
  149. public:
  150. CPP_member
  151. constexpr CPP_ctor(box)()( //
  152. noexcept(std::is_nothrow_default_constructible<Element>::value) //
  153. requires std::is_default_constructible<Element>::value)
  154. : value{}
  155. {}
  156. #if defined(__cpp_conditional_explicit) && __cpp_conditional_explicit > 0
  157. template(typename E)(
  158. requires (!same_as<box, detail::decay_t<E>>) AND
  159. constructible_from<Element, E>)
  160. constexpr explicit(!convertible_to<E, Element>) box(E && e)
  161. noexcept(std::is_nothrow_constructible<Element, E>::value) //
  162. : value(static_cast<E &&>(e))
  163. {}
  164. #else
  165. template(typename E)(
  166. requires (!same_as<box, detail::decay_t<E>>) AND
  167. constructible_from<Element, E> AND
  168. convertible_to<E, Element>)
  169. constexpr box(E && e)
  170. noexcept(std::is_nothrow_constructible<Element, E>::value)
  171. : value(static_cast<E &&>(e))
  172. {}
  173. template(typename E)(
  174. requires (!same_as<box, detail::decay_t<E>>) AND
  175. constructible_from<Element, E> AND
  176. (!convertible_to<E, Element>))
  177. constexpr explicit box(E && e)
  178. noexcept(std::is_nothrow_constructible<Element, E>::value) //
  179. : value(static_cast<E &&>(e))
  180. {}
  181. #endif
  182. constexpr Element & get() & noexcept
  183. {
  184. return value;
  185. }
  186. constexpr Element const & get() const & noexcept
  187. {
  188. return value;
  189. }
  190. constexpr Element && get() && noexcept
  191. {
  192. return detail::move(value);
  193. }
  194. constexpr Element const && get() const && noexcept
  195. {
  196. return detail::move(value);
  197. }
  198. };
  199. template<typename Element, typename Tag>
  200. class box<Element, Tag, detail::box_compress::ebo> : Element
  201. {
  202. public:
  203. CPP_member
  204. constexpr CPP_ctor(box)()( //
  205. noexcept(std::is_nothrow_default_constructible<Element>::value) //
  206. requires std::is_default_constructible<Element>::value)
  207. : Element{}
  208. {}
  209. #if defined(__cpp_conditional_explicit) && __cpp_conditional_explicit > 0
  210. template(typename E)(
  211. requires (!same_as<box, detail::decay_t<E>>) AND
  212. constructible_from<Element, E>)
  213. constexpr explicit(!convertible_to<E, Element>) box(E && e)
  214. noexcept(std::is_nothrow_constructible<Element, E>::value) //
  215. : Element(static_cast<E &&>(e))
  216. {}
  217. #else
  218. template(typename E)(
  219. requires (!same_as<box, detail::decay_t<E>>) AND
  220. constructible_from<Element, E> AND
  221. convertible_to<E, Element>)
  222. constexpr box(E && e)
  223. noexcept(std::is_nothrow_constructible<Element, E>::value) //
  224. : Element(static_cast<E &&>(e))
  225. {}
  226. template(typename E)(
  227. requires (!same_as<box, detail::decay_t<E>>) AND
  228. constructible_from<Element, E> AND
  229. (!convertible_to<E, Element>))
  230. constexpr explicit box(E && e)
  231. noexcept(std::is_nothrow_constructible<Element, E>::value) //
  232. : Element(static_cast<E &&>(e))
  233. {}
  234. #endif
  235. constexpr Element & get() & noexcept
  236. {
  237. return *this;
  238. }
  239. constexpr Element const & get() const & noexcept
  240. {
  241. return *this;
  242. }
  243. constexpr Element && get() && noexcept
  244. {
  245. return detail::move(*this);
  246. }
  247. constexpr Element const && get() const && noexcept
  248. {
  249. return detail::move(*this);
  250. }
  251. };
  252. template<typename Element, typename Tag>
  253. class box<Element, Tag, detail::box_compress::coalesce>
  254. {
  255. static Element value;
  256. public:
  257. constexpr box() noexcept = default;
  258. #if defined(__cpp_conditional_explicit) && __cpp_conditional_explicit > 0
  259. template(typename E)(
  260. requires (!same_as<box, detail::decay_t<E>>) AND
  261. constructible_from<Element, E>)
  262. constexpr explicit(!convertible_to<E, Element>) box(E &&) noexcept
  263. {}
  264. #else
  265. template(typename E)(
  266. requires (!same_as<box, detail::decay_t<E>>) AND
  267. constructible_from<Element, E> AND
  268. convertible_to<E, Element>)
  269. constexpr box(E &&) noexcept
  270. {}
  271. template(typename E)(
  272. requires (!same_as<box, detail::decay_t<E>>) AND
  273. constructible_from<Element, E> AND
  274. (!convertible_to<E, Element>))
  275. constexpr explicit box(E &&) noexcept
  276. {}
  277. #endif
  278. constexpr Element & get() & noexcept
  279. {
  280. return value;
  281. }
  282. constexpr Element const & get() const & noexcept
  283. {
  284. return value;
  285. }
  286. constexpr Element && get() && noexcept
  287. {
  288. return detail::move(value);
  289. }
  290. constexpr Element const && get() const && noexcept
  291. {
  292. return detail::move(value);
  293. }
  294. };
  295. template<typename Element, typename Tag>
  296. Element box<Element, Tag, detail::box_compress::coalesce>::value{};
  297. /// \cond
  298. namespace _get_
  299. {
  300. /// \endcond
  301. // Get by tag type
  302. template<typename Tag, typename Element, detail::box_compress BC>
  303. constexpr Element & get(box<Element, Tag, BC> & b) noexcept
  304. {
  305. return b.get();
  306. }
  307. template<typename Tag, typename Element, detail::box_compress BC>
  308. constexpr Element const & get(box<Element, Tag, BC> const & b) noexcept
  309. {
  310. return b.get();
  311. }
  312. template<typename Tag, typename Element, detail::box_compress BC>
  313. constexpr Element && get(box<Element, Tag, BC> && b) noexcept
  314. {
  315. return detail::move(b).get();
  316. }
  317. // Get by index
  318. template<std::size_t I, typename Element, detail::box_compress BC>
  319. constexpr Element & get(box<Element, meta::size_t<I>, BC> & b) noexcept
  320. {
  321. return b.get();
  322. }
  323. template<std::size_t I, typename Element, detail::box_compress BC>
  324. constexpr Element const & get(
  325. box<Element, meta::size_t<I>, BC> const & b) noexcept
  326. {
  327. return b.get();
  328. }
  329. template<std::size_t I, typename Element, detail::box_compress BC>
  330. constexpr Element && get(box<Element, meta::size_t<I>, BC> && b) noexcept
  331. {
  332. return detail::move(b).get();
  333. }
  334. /// \cond
  335. } // namespace _get_
  336. /// \endcond
  337. /// @}
  338. } // namespace ranges
  339. RANGES_DIAGNOSTIC_POP
  340. #include <range/v3/detail/epilogue.hpp>
  341. #endif