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.

334 lines
11KB

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