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 14 #ifndef RANGES_V3_RANGE_CONVERSION_HPP 15 #define RANGES_V3_RANGE_CONVERSION_HPP 16 17 #include <vector> 18 19 #include <meta/meta.hpp> 20 21 #include <range/v3/range_fwd.hpp> 22 23 #include <range/v3/action/concepts.hpp> 24 #include <range/v3/functional/pipeable.hpp> 25 #include <range/v3/iterator/common_iterator.hpp> 26 #include <range/v3/range/concepts.hpp> 27 #include <range/v3/range/traits.hpp> 28 #include <range/v3/utility/static_const.hpp> 29 30 #include <range/v3/detail/prologue.hpp> 31 32 namespace ranges 33 { 34 /// \cond 35 namespace detail 36 { 37 struct to_container 38 { 39 template<typename MetaFn> 40 struct fn; 41 42 template<typename MetaFn, typename Fn> 43 struct closure; 44 45 template<typename MetaFn, typename Rng> 46 using container_t = meta::invoke<MetaFn, Rng>; 47 48 template<typename Rng, typename MetaFn> operator |(Rng && rng,closure<MetaFn,fn<MetaFn>> (*)(to_container))49 friend auto operator|(Rng && rng, 50 closure<MetaFn, fn<MetaFn>> (*)(to_container)) 51 -> CPP_broken_friend_ret(container_t<MetaFn, Rng>)( 52 /// \pre 53 requires invocable<fn<MetaFn>, Rng>) 54 { 55 return fn<MetaFn>{}(static_cast<Rng &&>(rng)); 56 } 57 58 template<typename MetaFn, typename Pipeable> operator |(closure<MetaFn,fn<MetaFn>> (*)(to_container),Pipeable pipe)59 friend auto operator|(closure<MetaFn, fn<MetaFn>> (*)(to_container), 60 Pipeable pipe) 61 -> CPP_broken_friend_ret( 62 closure<MetaFn, composed<Pipeable, fn<MetaFn>>>)( 63 /// \pre 64 requires (is_pipeable_v<Pipeable>)) 65 { 66 return closure<MetaFn, composed<Pipeable, fn<MetaFn>>>{ 67 compose(static_cast<Pipeable &&>(pipe), fn<MetaFn>{})}; 68 } 69 }; 70 71 // A simple, light-weight transform iterator that applies ranges::to 72 // to each element in the range. Used by ranges::to to convert a range 73 // of ranges into a container of containers. 74 template<typename Rng, typename Cont> 75 struct to_container_iterator 76 { 77 private: 78 using I = range_cpp17_iterator_t<Rng>; 79 using ValueType = range_value_t<Cont>; 80 I it_; 81 82 public: 83 using difference_type = typename std::iterator_traits<I>::difference_type; 84 using value_type = ValueType; 85 using reference = ValueType; 86 using pointer = typename std::iterator_traits<I>::pointer; 87 using iterator_category = typename std::iterator_traits<I>::iterator_category; 88 89 to_container_iterator() = default; 90 template<typename OtherIt> to_container_iteratorranges::detail::to_container_iterator91 to_container_iterator(OtherIt it) 92 : it_(std::move(it)) 93 {} operator ==(to_container_iterator const & a,to_container_iterator const & b)94 friend bool operator==(to_container_iterator const & a, 95 to_container_iterator const & b) 96 { 97 return a.it_ == b.it_; 98 } operator !=(to_container_iterator const & a,to_container_iterator const & b)99 friend bool operator!=(to_container_iterator const & a, 100 to_container_iterator const & b) 101 { 102 return !(a == b); 103 } operator *ranges::detail::to_container_iterator104 reference operator*() const 105 { 106 return to_container::fn<meta::id<ValueType>>{}(*it_); 107 } operator ++ranges::detail::to_container_iterator108 to_container_iterator & operator++() 109 { 110 ++it_; 111 return *this; 112 } operator ++ranges::detail::to_container_iterator113 to_container_iterator operator++(int) 114 { 115 auto tmp = *this; 116 ++it_; 117 return tmp; 118 } 119 CPP_member operator --ranges::detail::to_container_iterator120 auto operator--() // 121 -> CPP_ret(to_container_iterator &)( 122 /// \pre 123 requires derived_from<iterator_category, 124 std::bidirectional_iterator_tag>) 125 { 126 --it_; 127 return *this; 128 } 129 CPP_member operator --ranges::detail::to_container_iterator130 auto operator--(int) // 131 -> CPP_ret(to_container_iterator &)( 132 /// \pre 133 requires derived_from<iterator_category, 134 std::bidirectional_iterator_tag>) 135 { 136 auto tmp = *this; 137 ++it_; 138 return tmp; 139 } 140 CPP_member operator +=ranges::detail::to_container_iterator141 auto operator+=(difference_type n) // 142 -> CPP_ret(to_container_iterator &)( 143 /// \pre 144 requires derived_from<iterator_category, 145 std::random_access_iterator_tag>) 146 { 147 it_ += n; 148 return *this; 149 } 150 CPP_member operator -=ranges::detail::to_container_iterator151 auto operator-=(difference_type n) // 152 -> CPP_ret(to_container_iterator &)( 153 /// \pre 154 requires derived_from<iterator_category, 155 std::random_access_iterator_tag>) 156 { 157 it_ -= n; 158 return *this; 159 } 160 CPP_broken_friend_member operator +(to_container_iterator i,difference_type n)161 friend auto operator+(to_container_iterator i, difference_type n) // 162 -> CPP_broken_friend_ret(to_container_iterator)( 163 /// \pre 164 requires derived_from<iterator_category, 165 std::random_access_iterator_tag>) 166 { 167 return i += n; 168 } 169 CPP_broken_friend_member operator -(to_container_iterator i,difference_type n)170 friend auto operator-(to_container_iterator i, difference_type n) // 171 -> CPP_broken_friend_ret(to_container_iterator)( 172 /// \pre 173 requires derived_from<iterator_category, 174 std::random_access_iterator_tag>) 175 { 176 return i -= n; 177 } 178 CPP_broken_friend_member operator -(difference_type n,to_container_iterator i)179 friend auto operator-(difference_type n, to_container_iterator i) // 180 -> CPP_broken_friend_ret(to_container_iterator)( 181 /// \pre 182 requires derived_from<iterator_category, 183 std::random_access_iterator_tag>) 184 { 185 return i -= n; 186 } 187 CPP_broken_friend_member operator -(to_container_iterator const & i,to_container_iterator const & j)188 friend auto operator-(to_container_iterator const & i, 189 to_container_iterator const & j) // 190 -> CPP_broken_friend_ret(difference_type)( 191 /// \pre 192 requires derived_from<iterator_category, 193 std::random_access_iterator_tag>) 194 { 195 return i.it_ - j.it_; 196 } 197 CPP_member operator []ranges::detail::to_container_iterator198 auto operator[](difference_type n) const // 199 -> CPP_ret(reference)( 200 /// \pre 201 requires derived_from<iterator_category, 202 std::random_access_iterator_tag>) 203 { 204 return *(*this + n); 205 } 206 }; 207 208 template<typename Rng, typename Cont> 209 using to_container_iterator_t = 210 enable_if_t<(bool)range<Rng>, to_container_iterator<Rng, Cont>>; 211 212 // clang-format off 213 template(typename Rng)( 214 concept (range_and_not_view_)(Rng), 215 range<Rng> AND (!view_<Rng>)); 216 217 template<typename Rng> 218 CPP_concept range_and_not_view = 219 CPP_concept_ref(range_and_not_view_, Rng); 220 221 template(typename Rng, typename Cont)( 222 concept (convertible_to_cont_impl_)(Rng, Cont), 223 constructible_from<range_value_t<Cont>, range_reference_t<Rng>> AND 224 constructible_from< 225 Cont, 226 range_cpp17_iterator_t<Rng>, 227 range_cpp17_iterator_t<Rng>> 228 ); 229 template<typename Rng, typename Cont> 230 CPP_concept convertible_to_cont = // 231 range_and_not_view<Cont> && // 232 move_constructible<Cont> && // 233 CPP_concept_ref(detail::convertible_to_cont_impl_, Rng, Cont); 234 235 template(typename Rng, typename Cont)( 236 concept (convertible_to_cont_cont_impl_)(Rng, Cont), 237 range_and_not_view<range_value_t<Cont>> AND 238 // Test that each element of the input range can be ranges::to<> 239 // to the output container. 240 invocable< 241 to_container::fn<meta::id<range_value_t<Cont>>>, 242 range_reference_t<Rng>> AND 243 constructible_from< 244 Cont, 245 to_container_iterator_t<Rng, Cont>, 246 to_container_iterator_t<Rng, Cont>> 247 ); 248 template<typename Rng, typename Cont> 249 CPP_concept convertible_to_cont_cont = // 250 range<Cont> && // 251 (!view_<Cont>) && // 252 move_constructible<Cont> && // 253 CPP_concept_ref(detail::convertible_to_cont_cont_impl_, Rng, Cont); 254 255 template<typename C, typename I, typename R> 256 CPP_concept to_container_reserve = // 257 reservable_with_assign<C, I> && // 258 sized_range<R>; 259 260 template<typename MetaFn, typename Rng> 261 using container_t = meta::invoke<MetaFn, Rng>; 262 // clang-format on 263 RANGES_STRUCT_WITH_ADL_BARRIER(to_container_closure_base)264 struct RANGES_STRUCT_WITH_ADL_BARRIER(to_container_closure_base) 265 { 266 // clang-format off 267 template(typename Rng, typename MetaFn, typename Fn)( 268 /// \pre 269 requires input_range<Rng> AND 270 convertible_to_cont<Rng, container_t<MetaFn, Rng>>) 271 friend constexpr auto 272 operator|(Rng && rng, to_container::closure<MetaFn, Fn> fn) 273 { 274 return static_cast<Fn &&>(fn)(static_cast<Rng &&>(rng)); 275 } 276 277 template(typename Rng, typename MetaFn, typename Fn)( 278 /// \pre 279 requires input_range<Rng> AND 280 (!convertible_to_cont<Rng, container_t<MetaFn, Rng>>) AND 281 convertible_to_cont_cont<Rng, container_t<MetaFn, Rng>>) 282 friend constexpr auto 283 operator|(Rng && rng, to_container::closure<MetaFn, Fn> fn) 284 { 285 return static_cast<Fn &&>(fn)(static_cast<Rng &&>(rng)); 286 } 287 288 template<typename MetaFn, typename Fn, typename Pipeable> 289 friend constexpr auto operator|(to_container::closure<MetaFn, Fn> sh, 290 Pipeable pipe) 291 -> CPP_broken_friend_ret( 292 to_container::closure<MetaFn, composed<Pipeable, Fn>>)( 293 /// \pre 294 requires is_pipeable_v<Pipeable>) 295 { 296 return to_container::closure<MetaFn, composed<Pipeable, Fn>>{ 297 compose(static_cast<Pipeable &&>(pipe), static_cast<Fn &&>(sh))}; 298 } 299 }; 300 301 template<typename MetaFn, typename Fn> 302 struct to_container::closure 303 : to_container_closure_base 304 , Fn 305 { 306 closure() = default; closureranges::detail::to_container::closure307 constexpr explicit closure(Fn fn) 308 : Fn(static_cast<Fn &&>(fn)) 309 {} 310 }; 311 312 template<typename MetaFn> 313 struct to_container::fn 314 { 315 private: 316 template<typename Cont, typename I, typename Rng> implranges::detail::to_container::fn317 static Cont impl(Rng && rng, std::false_type) 318 { 319 return Cont(I{ranges::begin(rng)}, I{ranges::end(rng)}); 320 } 321 template<typename Cont, typename I, typename Rng> implranges::detail::to_container::fn322 static auto impl(Rng && rng, std::true_type) 323 { 324 Cont c; 325 auto const rng_size = ranges::size(rng); 326 using size_type = decltype(c.max_size()); 327 using C = common_type_t<range_size_t<Rng>, size_type>; 328 RANGES_EXPECT(static_cast<C>(rng_size) <= static_cast<C>(c.max_size())); 329 c.reserve(static_cast<size_type>(rng_size)); 330 c.assign(I{ranges::begin(rng)}, I{ranges::end(rng)}); 331 return c; 332 } 333 334 public: 335 template(typename Rng)( 336 /// \pre 337 requires input_range<Rng> AND 338 convertible_to_cont<Rng, container_t<MetaFn, Rng>>) operator ()ranges::detail::to_container::fn339 container_t<MetaFn, Rng> operator()(Rng && rng) const 340 { 341 static_assert(!is_infinite<Rng>::value, 342 "Attempt to convert an infinite range to a container."); 343 using cont_t = container_t<MetaFn, Rng>; 344 using iter_t = range_cpp17_iterator_t<Rng>; 345 using use_reserve_t = 346 meta::bool_<(bool)to_container_reserve<cont_t, iter_t, Rng>>; 347 return impl<cont_t, iter_t>(static_cast<Rng &&>(rng), use_reserve_t{}); 348 } 349 template(typename Rng)( 350 /// \pre 351 requires input_range<Rng> AND 352 (!convertible_to_cont<Rng, container_t<MetaFn, Rng>>) AND 353 convertible_to_cont_cont<Rng, container_t<MetaFn, Rng>>) operator ()ranges::detail::to_container::fn354 container_t<MetaFn, Rng> operator()(Rng && rng) const 355 { 356 static_assert(!is_infinite<Rng>::value, 357 "Attempt to convert an infinite range to a container."); 358 using cont_t = container_t<MetaFn, Rng>; 359 using iter_t = to_container_iterator<Rng, cont_t>; 360 using use_reserve_t = 361 meta::bool_<(bool)to_container_reserve<cont_t, iter_t, Rng>>; 362 return impl<cont_t, iter_t>(static_cast<Rng &&>(rng), use_reserve_t{}); 363 } 364 }; 365 366 template<typename MetaFn, typename Fn> 367 using to_container_closure = to_container::closure<MetaFn, Fn>; 368 369 template<typename MetaFn> 370 using to_container_fn = to_container_closure<MetaFn, to_container::fn<MetaFn>>; 371 372 template<template<typename...> class ContT> 373 struct from_range 374 { 375 #if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17 376 // Attempt to use a deduction guide first... 377 template<typename Rng> 378 static auto from_rng_(int) // 379 -> decltype(ContT(range_cpp17_iterator_t<Rng>{}, 380 range_cpp17_iterator_t<Rng>{})); 381 // No deduction guide. Fallback to instantiating with the 382 // iterator's value type. 383 template<typename Rng> 384 static auto from_rng_(long) // 385 -> meta::invoke<meta::quote<ContT>, range_value_t<Rng>>; 386 387 template<typename Rng> 388 using invoke = decltype(from_range::from_rng_<Rng>(0)); 389 #else 390 template<typename Rng> 391 using invoke = meta::invoke<meta::quote<ContT>, range_value_t<Rng>>; 392 #endif 393 }; 394 } // namespace detail 395 /// \endcond 396 397 /// \addtogroup group-range 398 /// @{ 399 400 /// \ingroup group-range 401 RANGES_INLINE_VARIABLE(detail::to_container_fn<detail::from_range<std::vector>>, 402 to_vector) 403 404 /// \cond 405 namespace _to_ 406 { 407 /// \endcond 408 409 /// \brief For initializing a container of the specified type with the elements of 410 /// an Range 411 template<template<typename...> class ContT> to(RANGES_HIDDEN_DETAIL (detail::to_container={}))412 auto to(RANGES_HIDDEN_DETAIL(detail::to_container = {})) 413 -> detail::to_container_fn<detail::from_range<ContT>> 414 { 415 return {}; 416 } 417 418 /// \overload 419 template(template<typename...> class ContT, typename Rng)( 420 /// \pre 421 requires range<Rng> AND 422 detail::convertible_to_cont<Rng, ContT<range_value_t<Rng>>>) to(Rng && rng)423 auto to(Rng && rng) -> ContT<range_value_t<Rng>> 424 { 425 return detail::to_container_fn<detail::from_range<ContT>>{}( 426 static_cast<Rng &&>(rng)); 427 } 428 429 /// \overload 430 template<typename Cont> to(RANGES_HIDDEN_DETAIL (detail::to_container={}))431 auto to(RANGES_HIDDEN_DETAIL(detail::to_container = {})) 432 -> detail::to_container_fn<meta::id<Cont>> 433 { 434 return {}; 435 } 436 437 /// \overload 438 template(typename Cont, typename Rng)( 439 /// \pre 440 requires range<Rng> AND detail::convertible_to_cont<Rng, Cont>) to(Rng && rng)441 auto to(Rng && rng) -> Cont 442 { 443 return detail::to_container_fn<meta::id<Cont>>{}(static_cast<Rng &&>(rng)); 444 } 445 446 /// \cond 447 // Slightly odd initializer_list overloads, undocumented for now. 448 template(template<typename...> class ContT, typename T)( 449 /// \pre 450 requires detail::convertible_to_cont<std::initializer_list<T>, ContT<T>>) 451 auto to(std::initializer_list<T> il) -> ContT<T> 452 { 453 return detail::to_container_fn<detail::from_range<ContT>>{}(il); 454 } 455 template(typename Cont, typename T)( 456 /// \pre 457 requires detail::convertible_to_cont<std::initializer_list<T>, Cont>) 458 auto to(std::initializer_list<T> il) -> Cont 459 { 460 return detail::to_container_fn<meta::id<Cont>>{}(il); 461 } 462 /// \endcond 463 464 /// \cond 465 } // namespace _to_ 466 using namespace _to_; 467 /// \endcond 468 /// @} 469 470 //////////////////////////////////////////////////////////////////////////// 471 /// \cond 472 namespace _to_ 473 { 474 // The old name "ranges::to_" is now deprecated: 475 template<template<typename...> class ContT> 476 RANGES_DEPRECATED("Please use ranges::to (no underscore) instead.") 477 detail::to_container_fn<detail::from_range<ContT>> to_(detail::to_container = {}) 478 { 479 return {}; 480 } 481 template(template<typename...> class ContT, typename Rng)( 482 /// \pre 483 requires range<Rng> AND 484 detail::convertible_to_cont<Rng, ContT<range_value_t<Rng>>>) 485 RANGES_DEPRECATED("Please use ranges::to (no underscore) instead.") 486 ContT<range_value_t<Rng>> to_(Rng && rng) 487 { 488 return static_cast<Rng &&>(rng) | ranges::to_<ContT>(); 489 } 490 template(template<typename...> class ContT, typename T)( 491 /// \pre 492 requires detail::convertible_to_cont<std::initializer_list<T>, ContT<T>>) 493 RANGES_DEPRECATED("Please use ranges::to (no underscore) instead.") 494 ContT<T> to_(std::initializer_list<T> il) 495 { 496 return il | ranges::to_<ContT>(); 497 } 498 template<typename Cont> 499 RANGES_DEPRECATED("Please use ranges::to (no underscore) instead.") 500 detail::to_container_fn<meta::id<Cont>> to_(detail::to_container = {}) 501 { 502 return {}; 503 } 504 template(typename Cont, typename Rng)( 505 /// \pre 506 requires range<Rng> AND detail::convertible_to_cont<Rng, Cont>) 507 RANGES_DEPRECATED("Please use ranges::to (no underscore) instead.") 508 Cont to_(Rng && rng) 509 { 510 return static_cast<Rng &&>(rng) | ranges::to_<Cont>(); 511 } 512 template(typename Cont, typename T)( 513 /// \pre 514 requires detail::convertible_to_cont<std::initializer_list<T>, Cont>) 515 RANGES_DEPRECATED("Please use ranges::to (no underscore) instead.") 516 Cont to_(std::initializer_list<T> list) 517 { 518 return list | ranges::to_<Cont>(); 519 } 520 } // namespace _to_ 521 /// \endcond 522 523 template<typename MetaFn, typename Fn> 524 RANGES_INLINE_VAR constexpr bool 525 is_pipeable_v<detail::to_container_closure<MetaFn, Fn>> = true; 526 } // namespace ranges 527 528 #include <range/v3/detail/epilogue.hpp> 529 530 #endif 531