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.

450 lines
17KB

  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_RANGE_CONVERSION_HPP
  14. #define RANGES_V3_RANGE_CONVERSION_HPP
  15. #include <meta/meta.hpp>
  16. #include <range/v3/range_fwd.hpp>
  17. #include <range/v3/action/concepts.hpp>
  18. #include <range/v3/functional/pipeable.hpp>
  19. #include <range/v3/iterator/common_iterator.hpp>
  20. #include <range/v3/range/concepts.hpp>
  21. #include <range/v3/range/traits.hpp>
  22. #include <range/v3/utility/static_const.hpp>
  23. #ifndef RANGES_NO_STD_FORWARD_DECLARATIONS
  24. // Non-portable forward declarations of standard containers
  25. RANGES_BEGIN_NAMESPACE_STD
  26. RANGES_BEGIN_NAMESPACE_CONTAINER
  27. template<typename Value, typename Alloc /*= allocator<Value>*/>
  28. class vector;
  29. RANGES_END_NAMESPACE_CONTAINER
  30. RANGES_END_NAMESPACE_STD
  31. #else
  32. #include <vector>
  33. #endif
  34. namespace ranges
  35. {
  36. /// \cond
  37. namespace detail
  38. {
  39. struct to_container
  40. {
  41. template<typename ToContainer>
  42. struct fn;
  43. template<typename ToContainer, typename Rng>
  44. using container_t = meta::invoke<ToContainer, Rng>;
  45. template<typename Rng, typename ToContainer>
  46. friend auto operator|(Rng && rng, fn<ToContainer> (*)(to_container))
  47. -> CPP_broken_friend_ret(container_t<ToContainer, Rng>)( //
  48. requires invocable<fn<ToContainer>, Rng>)
  49. {
  50. return fn<ToContainer>{}(static_cast<Rng &&>(rng));
  51. }
  52. };
  53. // A simple, light-weight transform iterator that applies ranges::to
  54. // to each element in the range. Used by ranges::to to convert a range
  55. // of ranges into a container of containers.
  56. template<typename Rng, typename Cont>
  57. struct to_container_iterator
  58. {
  59. private:
  60. using I = range_cpp17_iterator_t<Rng>;
  61. using ValueType = range_value_t<Cont>;
  62. I it_;
  63. public:
  64. using difference_type = typename std::iterator_traits<I>::difference_type;
  65. using value_type = ValueType;
  66. using reference = ValueType;
  67. using pointer = typename std::iterator_traits<I>::pointer;
  68. using iterator_category = typename std::iterator_traits<I>::iterator_category;
  69. to_container_iterator() = default;
  70. template<typename OtherIt>
  71. to_container_iterator(OtherIt it)
  72. : it_(std::move(it))
  73. {}
  74. friend bool operator==(to_container_iterator const & a,
  75. to_container_iterator const & b)
  76. {
  77. return a.it_ == b.it_;
  78. }
  79. friend bool operator!=(to_container_iterator const & a,
  80. to_container_iterator const & b)
  81. {
  82. return !(a == b);
  83. }
  84. reference operator*() const
  85. {
  86. return to_container::fn<meta::id<ValueType>>{}(*it_);
  87. }
  88. to_container_iterator & operator++()
  89. {
  90. ++it_;
  91. return *this;
  92. }
  93. to_container_iterator operator++(int)
  94. {
  95. auto tmp = *this;
  96. ++it_;
  97. return tmp;
  98. }
  99. CPP_member
  100. auto operator--() -> CPP_ret(to_container_iterator &)(
  101. requires derived_from<iterator_category, std::bidirectional_iterator_tag>)
  102. {
  103. --it_;
  104. return *this;
  105. }
  106. CPP_member
  107. auto operator--(int) -> CPP_ret(to_container_iterator &)(
  108. requires derived_from<iterator_category, std::bidirectional_iterator_tag>)
  109. {
  110. auto tmp = *this;
  111. ++it_;
  112. return tmp;
  113. }
  114. CPP_member
  115. auto operator+=(difference_type n) -> CPP_ret(to_container_iterator &)(
  116. requires derived_from<iterator_category, std::random_access_iterator_tag>)
  117. {
  118. it_ += n;
  119. return *this;
  120. }
  121. CPP_member
  122. auto operator-=(difference_type n) -> CPP_ret(to_container_iterator &)(
  123. requires derived_from<iterator_category, std::random_access_iterator_tag>)
  124. {
  125. it_ -= n;
  126. return *this;
  127. }
  128. CPP_broken_friend_member
  129. friend auto operator+(to_container_iterator i, difference_type n) //
  130. -> CPP_broken_friend_ret(to_container_iterator)(
  131. requires derived_from<iterator_category,
  132. std::random_access_iterator_tag>)
  133. {
  134. return i += n;
  135. }
  136. CPP_broken_friend_member
  137. friend auto operator-(to_container_iterator i, difference_type n) //
  138. -> CPP_broken_friend_ret(to_container_iterator)(
  139. requires derived_from<iterator_category,
  140. std::random_access_iterator_tag>)
  141. {
  142. return i -= n;
  143. }
  144. CPP_broken_friend_member
  145. friend auto operator-(difference_type n, to_container_iterator i) //
  146. -> CPP_broken_friend_ret(to_container_iterator)(
  147. requires derived_from<iterator_category,
  148. std::random_access_iterator_tag>)
  149. {
  150. return i -= n;
  151. }
  152. CPP_broken_friend_member
  153. friend auto operator-(to_container_iterator const & i,
  154. to_container_iterator const & j) //
  155. -> CPP_broken_friend_ret(difference_type)(
  156. requires derived_from<iterator_category,
  157. std::random_access_iterator_tag>)
  158. {
  159. return i.it_ - j.it_;
  160. }
  161. CPP_member
  162. auto operator[](difference_type n) const -> CPP_ret(reference)(
  163. requires derived_from<iterator_category, std::random_access_iterator_tag>)
  164. {
  165. return *(*this + n);
  166. }
  167. };
  168. template<typename Rng, typename Cont>
  169. using to_container_iterator_t =
  170. enable_if_t<(bool)range<Rng>, to_container_iterator<Rng, Cont>>;
  171. // clang-format off
  172. CPP_def
  173. (
  174. template(typename Cont)
  175. concept has_allocator_type,
  176. ranges::type<typename Cont::allocator_type>
  177. );
  178. CPP_def
  179. (
  180. template(typename Rng, typename Cont)
  181. concept convertible_to_container_impl_,
  182. range<Cont> && (!view_<Cont>) && move_constructible<Cont> &&
  183. constructible_from<range_value_t<Cont>, range_reference_t<Rng>> &&
  184. constructible_from<
  185. Cont,
  186. range_cpp17_iterator_t<Rng>,
  187. range_cpp17_iterator_t<Rng>>
  188. );
  189. CPP_def
  190. (
  191. template(typename Rng, typename Cont)
  192. concept convertible_to_container_container_impl_,
  193. range<Cont> && (!view_<Cont>) && move_constructible<Cont> &&
  194. (bool(ranges::defer::range<range_value_t<Cont>> &&
  195. !ranges::defer::view_<range_value_t<Cont>>)) &&
  196. // Test that each element of the input range can be ranges::to<>
  197. // to the output container.
  198. invocable<
  199. to_container::fn<meta::id<range_value_t<Cont>>>,
  200. range_reference_t<Rng>> &&
  201. constructible_from<
  202. Cont,
  203. to_container_iterator_t<Rng, Cont>,
  204. to_container_iterator_t<Rng, Cont>>
  205. );
  206. CPP_def
  207. (
  208. template(typename Rng, typename Cont)
  209. concept convertible_to_container,
  210. defer::has_allocator_type<Cont> && // HACKHACK
  211. defer::convertible_to_container_impl_<Rng, Cont>
  212. );
  213. CPP_def
  214. (
  215. template(typename Rng, typename Cont)
  216. concept convertible_to_container_container,
  217. defer::has_allocator_type<Cont> && // HACKHACK
  218. defer::convertible_to_container_container_impl_<Rng, Cont>
  219. );
  220. CPP_def
  221. (
  222. template(typename C, typename I, typename R)
  223. concept to_container_reserve,
  224. reservable_with_assign<C, I> &&
  225. sized_range<R>
  226. );
  227. // clang-format on
  228. template<typename ToContainer>
  229. struct to_container::fn : pipeable_base
  230. {
  231. private:
  232. template<typename Cont, typename I, typename Rng>
  233. static Cont impl(Rng && rng, std::false_type)
  234. {
  235. return Cont(I{ranges::begin(rng)}, I{ranges::end(rng)});
  236. }
  237. template<typename Cont, typename I, typename Rng>
  238. static auto impl(Rng && rng, std::true_type)
  239. {
  240. Cont c;
  241. auto const rng_size = ranges::size(rng);
  242. using size_type = decltype(c.max_size());
  243. using C = common_type_t<range_size_t<Rng>, size_type>;
  244. RANGES_EXPECT(static_cast<C>(rng_size) <= static_cast<C>(c.max_size()));
  245. c.reserve(static_cast<size_type>(rng_size));
  246. c.assign(I{ranges::begin(rng)}, I{ranges::end(rng)});
  247. return c;
  248. }
  249. template<typename Rng>
  250. using container_t = meta::invoke<ToContainer, Rng>;
  251. public:
  252. template<typename Rng>
  253. auto operator()(Rng && rng) const -> CPP_ret(container_t<Rng>)( //
  254. requires input_range<Rng> && //
  255. (bool(!defer::convertible_to_container_container<Rng, //
  256. container_t<Rng>> && //
  257. defer::convertible_to_container<Rng, container_t<Rng>>)))
  258. {
  259. static_assert(!is_infinite<Rng>::value,
  260. "Attempt to convert an infinite range to a container.");
  261. using cont_t = container_t<Rng>;
  262. using iter_t = range_cpp17_iterator_t<Rng>;
  263. using use_reserve_t =
  264. meta::bool_<(bool)to_container_reserve<cont_t, iter_t, Rng>>;
  265. return impl<cont_t, iter_t>(static_cast<Rng &&>(rng), use_reserve_t{});
  266. }
  267. template<typename Rng>
  268. auto operator()(Rng && rng) const -> CPP_ret(container_t<Rng>)( //
  269. requires input_range<Rng> && //
  270. convertible_to_container_container<Rng, container_t<Rng>>)
  271. {
  272. static_assert(!is_infinite<Rng>::value,
  273. "Attempt to convert an infinite range to a container.");
  274. using cont_t = container_t<Rng>;
  275. using iter_t = to_container_iterator<Rng, cont_t>;
  276. using use_reserve_t =
  277. meta::bool_<(bool)to_container_reserve<cont_t, iter_t, Rng>>;
  278. return impl<cont_t, iter_t>(static_cast<Rng &&>(rng), use_reserve_t{});
  279. }
  280. };
  281. template<typename ToContainer>
  282. using to_container_fn = to_container::fn<ToContainer>;
  283. template<template<typename...> class ContT>
  284. struct from_range
  285. {
  286. #if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17
  287. // Attempt to use a deduction guide first...
  288. template<typename Rng>
  289. static auto from_rng_(int) -> decltype(ContT(range_cpp17_iterator_t<Rng>{},
  290. range_cpp17_iterator_t<Rng>{}));
  291. // No deduction guide. Fallback to instantiating with the
  292. // iterator's value type.
  293. template<typename Rng>
  294. static auto from_rng_(long)
  295. -> meta::invoke<meta::quote<ContT>, range_value_t<Rng>>;
  296. template<typename Rng>
  297. using invoke = decltype(from_range::from_rng_<Rng>(0));
  298. #else
  299. template<typename Rng>
  300. using invoke = meta::invoke<meta::quote<ContT>, range_value_t<Rng>>;
  301. #endif
  302. };
  303. } // namespace detail
  304. /// \endcond
  305. /// \addtogroup group-range
  306. /// @{
  307. /// \ingroup group-range
  308. RANGES_INLINE_VARIABLE(detail::to_container_fn<detail::from_range<std::vector>>,
  309. to_vector)
  310. /// \cond
  311. namespace _to_
  312. {
  313. /// \endcond
  314. /// \brief For initializing a container of the specified type with the elements of
  315. /// an Range
  316. template<template<typename...> class ContT>
  317. auto to(RANGES_HIDDEN_DETAIL(detail::to_container = {}))
  318. -> detail::to_container_fn<detail::from_range<ContT>>
  319. {
  320. return {};
  321. }
  322. /// \overload
  323. template<template<typename...> class ContT, typename Rng>
  324. auto to(Rng && rng) -> CPP_ret(ContT<range_value_t<Rng>>)( //
  325. requires range<Rng> &&
  326. detail::convertible_to_container<Rng, ContT<range_value_t<Rng>>>)
  327. {
  328. return detail::to_container_fn<detail::from_range<ContT>>{}(
  329. static_cast<Rng &&>(rng));
  330. }
  331. /// \overload
  332. template<typename Cont>
  333. auto to(RANGES_HIDDEN_DETAIL(detail::to_container = {}))
  334. -> detail::to_container_fn<meta::id<Cont>>
  335. {
  336. return {};
  337. }
  338. /// \overload
  339. template<typename Cont, typename Rng>
  340. auto to(Rng && rng) -> CPP_ret(Cont)( //
  341. requires range<Rng> && detail::convertible_to_container<Rng, Cont>)
  342. {
  343. return detail::to_container_fn<meta::id<Cont>>{}(static_cast<Rng &&>(rng));
  344. }
  345. /// \cond
  346. // Slightly odd initializer_list overloads, undocumented for now.
  347. template<template<typename...> class ContT, typename T>
  348. auto to(std::initializer_list<T> il) -> CPP_ret(ContT<T>)( //
  349. requires detail::convertible_to_container<std::initializer_list<T>, ContT<T>>)
  350. {
  351. return detail::to_container_fn<detail::from_range<ContT>>{}(il);
  352. }
  353. template<typename Cont, typename T>
  354. auto to(std::initializer_list<T> il) -> CPP_ret(Cont)( //
  355. requires detail::convertible_to_container<std::initializer_list<T>, Cont>)
  356. {
  357. return detail::to_container_fn<meta::id<Cont>>{}(il);
  358. }
  359. /// \endcond
  360. /// \cond
  361. } // namespace _to_
  362. using namespace _to_;
  363. /// \endcond
  364. /// @}
  365. ////////////////////////////////////////////////////////////////////////////
  366. /// \cond
  367. namespace _to_
  368. {
  369. // The old name "ranges::to_" is now deprecated:
  370. template<template<typename...> class ContT>
  371. RANGES_DEPRECATED("Please use ranges::to (no underscore) instead.")
  372. auto to_(detail::to_container = {})
  373. -> detail::to_container_fn<detail::from_range<ContT>>
  374. {
  375. return {};
  376. }
  377. template<template<typename...> class ContT, typename Rng>
  378. RANGES_DEPRECATED("Please use ranges::to (no underscore) instead.")
  379. auto to_(Rng && rng) -> CPP_ret(ContT<range_value_t<Rng>>)( //
  380. requires range<Rng> &&
  381. detail::convertible_to_container<Rng, ContT<range_value_t<Rng>>>)
  382. {
  383. return static_cast<Rng &&>(rng) | ranges::to_<ContT>();
  384. }
  385. template<template<typename...> class ContT, typename T>
  386. RANGES_DEPRECATED("Please use ranges::to (no underscore) instead.")
  387. auto to_(std::initializer_list<T> il) -> CPP_ret(ContT<T>)( //
  388. requires detail::convertible_to_container<std::initializer_list<T>, ContT<T>>)
  389. {
  390. return il | ranges::to_<ContT>();
  391. }
  392. template<typename Cont>
  393. RANGES_DEPRECATED("Please use ranges::to (no underscore) instead.")
  394. auto to_(detail::to_container = {}) -> detail::to_container_fn<meta::id<Cont>>
  395. {
  396. return {};
  397. }
  398. template<typename Cont, typename Rng>
  399. RANGES_DEPRECATED("Please use ranges::to (no underscore) instead.")
  400. auto to_(Rng && rng) -> CPP_ret(Cont)( //
  401. requires range<Rng> && detail::convertible_to_container<Rng, Cont>)
  402. {
  403. return static_cast<Rng &&>(rng) | ranges::to_<Cont>();
  404. }
  405. template<typename Cont, typename T>
  406. RANGES_DEPRECATED("Please use ranges::to (no underscore) instead.")
  407. auto to_(std::initializer_list<T> list) -> CPP_ret(Cont)( //
  408. requires detail::convertible_to_container<std::initializer_list<T>, Cont>)
  409. {
  410. return list | ranges::to_<Cont>();
  411. }
  412. } // namespace _to_
  413. /// \endcond
  414. } // namespace ranges
  415. #endif