diff options
author | Jonathan Wakely <jwakely@redhat.com> | 2023-09-19 13:23:13 +0100 |
---|---|---|
committer | Jonathan Wakely <jwakely@redhat.com> | 2023-11-23 17:48:41 +0000 |
commit | 7a6a29c455e7755b501c0006e39beb4e56ec2729 (patch) | |
tree | 4ff795bbc89cfb12f0c5b2de2fec7030289aaa36 | |
parent | 0585daf7de0673ade9feca1be66a68178786b48d (diff) | |
download | gcc-7a6a29c455e7755b501c0006e39beb4e56ec2729.zip gcc-7a6a29c455e7755b501c0006e39beb4e56ec2729.tar.gz gcc-7a6a29c455e7755b501c0006e39beb4e56ec2729.tar.bz2 |
libstdc++: Define std::ranges::to for C++23 (P1206R7) [PR111055]
This adds the std::ranges::to functions for C++23. The rest of P1206R7
is not yet implemented, i.e. the new constructors taking the
std::from_range tag, and the new insert_range, assign_range, etc. member
functions. std::ranges::to works with the standard containers even
without the new constructors, so this is useful immediately.
The __cpp_lib_ranges_to_container feature test macro can be defined now,
because that only indicates support for the changes in <ranges>, which
are implemented by this patch. The __cpp_lib_containers_ranges macro
will be defined once all containers support the new member functions.
libstdc++-v3/ChangeLog:
PR libstdc++/111055
* include/bits/ranges_base.h (from_range_t): Define new tag
type.
(from_range): Define new tag object.
* include/bits/version.def (ranges_to_container): Define.
* include/bits/version.h: Regenerate.
* include/std/ranges (ranges::to): Define.
* testsuite/std/ranges/conv/1.cc: New test.
* testsuite/std/ranges/conv/2_neg.cc: New test.
* testsuite/std/ranges/conv/version.cc: New test.
-rw-r--r-- | libstdc++-v3/include/bits/ranges_base.h | 8 | ||||
-rw-r--r-- | libstdc++-v3/include/bits/version.def | 34 | ||||
-rw-r--r-- | libstdc++-v3/include/bits/version.h | 111 | ||||
-rw-r--r-- | libstdc++-v3/include/std/ranges | 361 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/std/ranges/conv/1.cc | 369 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/std/ranges/conv/2_neg.cc | 24 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/std/ranges/conv/version.cc | 19 |
7 files changed, 866 insertions, 60 deletions
diff --git a/libstdc++-v3/include/bits/ranges_base.h b/libstdc++-v3/include/bits/ranges_base.h index 7fa43d1..1ca2c5c 100644 --- a/libstdc++-v3/include/bits/ranges_base.h +++ b/libstdc++-v3/include/bits/ranges_base.h @@ -37,6 +37,7 @@ #include <bits/stl_iterator.h> #include <ext/numeric_traits.h> #include <bits/max_size_type.h> +#include <bits/version.h> #ifdef __cpp_lib_concepts namespace std _GLIBCXX_VISIBILITY(default) @@ -1056,8 +1057,13 @@ namespace ranges using borrowed_iterator_t = __conditional_t<borrowed_range<_Range>, iterator_t<_Range>, dangling>; - } // namespace ranges + +#if __glibcxx_ranges_to_container // C++ >= 23 + struct from_range_t { explicit from_range_t() = default; }; + inline constexpr from_range_t from_range{}; +#endif + _GLIBCXX_END_NAMESPACE_VERSION } // namespace std #endif // library concepts diff --git a/libstdc++-v3/include/bits/version.def b/libstdc++-v3/include/bits/version.def index 605708d..1407778 100644 --- a/libstdc++-v3/include/bits/version.def +++ b/libstdc++-v3/include/bits/version.def @@ -1439,19 +1439,21 @@ ftms = { }; }; -ftms = { - name = to_underlying; - values = { - v = 202102; - cxxmin = 23; - }; -}; +//ftms = { +// name = container_ranges; +// values = { +// v = 202202; +// cxxmin = 23; +// hosted = yes; +// }; +//}; ftms = { - name = unreachable; + name = ranges_to_container; values = { v = 202202; cxxmin = 23; + hosted = yes; }; }; @@ -1684,6 +1686,22 @@ ftms = { }; ftms = { + name = to_underlying; + values = { + v = 202102; + cxxmin = 23; + }; +}; + +ftms = { + name = unreachable; + values = { + v = 202202; + cxxmin = 23; + }; +}; + +ftms = { name = fstream_native_handle; values = { v = 202306; diff --git a/libstdc++-v3/include/bits/version.h b/libstdc++-v3/include/bits/version.h index cacd9375..1fb1d14 100644 --- a/libstdc++-v3/include/bits/version.h +++ b/libstdc++-v3/include/bits/version.h @@ -1740,29 +1740,18 @@ #endif /* !defined(__cpp_lib_reference_from_temporary) && defined(__glibcxx_want_reference_from_temporary) */ #undef __glibcxx_want_reference_from_temporary -// from version.def line 1443 -#if !defined(__cpp_lib_to_underlying) -# if (__cplusplus >= 202100L) -# define __glibcxx_to_underlying 202102L -# if defined(__glibcxx_want_all) || defined(__glibcxx_want_to_underlying) -# define __cpp_lib_to_underlying 202102L -# endif -# endif -#endif /* !defined(__cpp_lib_to_underlying) && defined(__glibcxx_want_to_underlying) */ -#undef __glibcxx_want_to_underlying - -// from version.def line 1451 -#if !defined(__cpp_lib_unreachable) -# if (__cplusplus >= 202100L) -# define __glibcxx_unreachable 202202L -# if defined(__glibcxx_want_all) || defined(__glibcxx_want_unreachable) -# define __cpp_lib_unreachable 202202L +// from version.def line 1452 +#if !defined(__cpp_lib_ranges_to_container) +# if (__cplusplus >= 202100L) && _GLIBCXX_HOSTED +# define __glibcxx_ranges_to_container 202202L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_ranges_to_container) +# define __cpp_lib_ranges_to_container 202202L # endif # endif -#endif /* !defined(__cpp_lib_unreachable) && defined(__glibcxx_want_unreachable) */ -#undef __glibcxx_want_unreachable +#endif /* !defined(__cpp_lib_ranges_to_container) && defined(__glibcxx_want_ranges_to_container) */ +#undef __glibcxx_want_ranges_to_container -// from version.def line 1459 +// from version.def line 1461 #if !defined(__cpp_lib_ranges_zip) # if (__cplusplus >= 202100L) # define __glibcxx_ranges_zip 202110L @@ -1773,7 +1762,7 @@ #endif /* !defined(__cpp_lib_ranges_zip) && defined(__glibcxx_want_ranges_zip) */ #undef __glibcxx_want_ranges_zip -// from version.def line 1467 +// from version.def line 1469 #if !defined(__cpp_lib_ranges_chunk) # if (__cplusplus >= 202100L) # define __glibcxx_ranges_chunk 202202L @@ -1784,7 +1773,7 @@ #endif /* !defined(__cpp_lib_ranges_chunk) && defined(__glibcxx_want_ranges_chunk) */ #undef __glibcxx_want_ranges_chunk -// from version.def line 1475 +// from version.def line 1477 #if !defined(__cpp_lib_ranges_slide) # if (__cplusplus >= 202100L) # define __glibcxx_ranges_slide 202202L @@ -1795,7 +1784,7 @@ #endif /* !defined(__cpp_lib_ranges_slide) && defined(__glibcxx_want_ranges_slide) */ #undef __glibcxx_want_ranges_slide -// from version.def line 1483 +// from version.def line 1485 #if !defined(__cpp_lib_ranges_chunk_by) # if (__cplusplus >= 202100L) # define __glibcxx_ranges_chunk_by 202202L @@ -1806,7 +1795,7 @@ #endif /* !defined(__cpp_lib_ranges_chunk_by) && defined(__glibcxx_want_ranges_chunk_by) */ #undef __glibcxx_want_ranges_chunk_by -// from version.def line 1491 +// from version.def line 1493 #if !defined(__cpp_lib_ranges_join_with) # if (__cplusplus >= 202100L) # define __glibcxx_ranges_join_with 202202L @@ -1817,7 +1806,7 @@ #endif /* !defined(__cpp_lib_ranges_join_with) && defined(__glibcxx_want_ranges_join_with) */ #undef __glibcxx_want_ranges_join_with -// from version.def line 1499 +// from version.def line 1501 #if !defined(__cpp_lib_ranges_repeat) # if (__cplusplus >= 202100L) # define __glibcxx_ranges_repeat 202207L @@ -1828,7 +1817,7 @@ #endif /* !defined(__cpp_lib_ranges_repeat) && defined(__glibcxx_want_ranges_repeat) */ #undef __glibcxx_want_ranges_repeat -// from version.def line 1507 +// from version.def line 1509 #if !defined(__cpp_lib_ranges_stride) # if (__cplusplus >= 202100L) # define __glibcxx_ranges_stride 202207L @@ -1839,7 +1828,7 @@ #endif /* !defined(__cpp_lib_ranges_stride) && defined(__glibcxx_want_ranges_stride) */ #undef __glibcxx_want_ranges_stride -// from version.def line 1515 +// from version.def line 1517 #if !defined(__cpp_lib_ranges_cartesian_product) # if (__cplusplus >= 202100L) # define __glibcxx_ranges_cartesian_product 202207L @@ -1850,7 +1839,7 @@ #endif /* !defined(__cpp_lib_ranges_cartesian_product) && defined(__glibcxx_want_ranges_cartesian_product) */ #undef __glibcxx_want_ranges_cartesian_product -// from version.def line 1523 +// from version.def line 1525 #if !defined(__cpp_lib_ranges_as_rvalue) # if (__cplusplus >= 202100L) # define __glibcxx_ranges_as_rvalue 202207L @@ -1861,7 +1850,7 @@ #endif /* !defined(__cpp_lib_ranges_as_rvalue) && defined(__glibcxx_want_ranges_as_rvalue) */ #undef __glibcxx_want_ranges_as_rvalue -// from version.def line 1531 +// from version.def line 1533 #if !defined(__cpp_lib_ranges_as_const) # if (__cplusplus >= 202100L) # define __glibcxx_ranges_as_const 202207L @@ -1872,7 +1861,7 @@ #endif /* !defined(__cpp_lib_ranges_as_const) && defined(__glibcxx_want_ranges_as_const) */ #undef __glibcxx_want_ranges_as_const -// from version.def line 1539 +// from version.def line 1541 #if !defined(__cpp_lib_ranges_enumerate) # if (__cplusplus >= 202100L) # define __glibcxx_ranges_enumerate 202302L @@ -1883,7 +1872,7 @@ #endif /* !defined(__cpp_lib_ranges_enumerate) && defined(__glibcxx_want_ranges_enumerate) */ #undef __glibcxx_want_ranges_enumerate -// from version.def line 1547 +// from version.def line 1549 #if !defined(__cpp_lib_ranges_fold) # if (__cplusplus >= 202100L) # define __glibcxx_ranges_fold 202207L @@ -1894,7 +1883,7 @@ #endif /* !defined(__cpp_lib_ranges_fold) && defined(__glibcxx_want_ranges_fold) */ #undef __glibcxx_want_ranges_fold -// from version.def line 1555 +// from version.def line 1557 #if !defined(__cpp_lib_ranges_contains) # if (__cplusplus >= 202100L) # define __glibcxx_ranges_contains 202207L @@ -1905,7 +1894,7 @@ #endif /* !defined(__cpp_lib_ranges_contains) && defined(__glibcxx_want_ranges_contains) */ #undef __glibcxx_want_ranges_contains -// from version.def line 1563 +// from version.def line 1565 #if !defined(__cpp_lib_ranges_iota) # if (__cplusplus >= 202100L) # define __glibcxx_ranges_iota 202202L @@ -1916,7 +1905,7 @@ #endif /* !defined(__cpp_lib_ranges_iota) && defined(__glibcxx_want_ranges_iota) */ #undef __glibcxx_want_ranges_iota -// from version.def line 1571 +// from version.def line 1573 #if !defined(__cpp_lib_ranges_find_last) # if (__cplusplus >= 202100L) # define __glibcxx_ranges_find_last 202207L @@ -1927,7 +1916,7 @@ #endif /* !defined(__cpp_lib_ranges_find_last) && defined(__glibcxx_want_ranges_find_last) */ #undef __glibcxx_want_ranges_find_last -// from version.def line 1579 +// from version.def line 1581 #if !defined(__cpp_lib_constexpr_bitset) # if (__cplusplus >= 202100L) && _GLIBCXX_HOSTED && (__cpp_constexpr_dynamic_alloc) # define __glibcxx_constexpr_bitset 202202L @@ -1938,7 +1927,7 @@ #endif /* !defined(__cpp_lib_constexpr_bitset) && defined(__glibcxx_want_constexpr_bitset) */ #undef __glibcxx_want_constexpr_bitset -// from version.def line 1589 +// from version.def line 1591 #if !defined(__cpp_lib_stdatomic_h) # if (__cplusplus >= 202100L) # define __glibcxx_stdatomic_h 202011L @@ -1949,7 +1938,7 @@ #endif /* !defined(__cpp_lib_stdatomic_h) && defined(__glibcxx_want_stdatomic_h) */ #undef __glibcxx_want_stdatomic_h -// from version.def line 1597 +// from version.def line 1599 #if !defined(__cpp_lib_adaptor_iterator_pair_constructor) # if (__cplusplus >= 202100L) && _GLIBCXX_HOSTED # define __glibcxx_adaptor_iterator_pair_constructor 202106L @@ -1960,7 +1949,7 @@ #endif /* !defined(__cpp_lib_adaptor_iterator_pair_constructor) && defined(__glibcxx_want_adaptor_iterator_pair_constructor) */ #undef __glibcxx_want_adaptor_iterator_pair_constructor -// from version.def line 1606 +// from version.def line 1608 #if !defined(__cpp_lib_formatters) # if (__cplusplus >= 202100L) && _GLIBCXX_HOSTED # define __glibcxx_formatters 202302L @@ -1971,7 +1960,7 @@ #endif /* !defined(__cpp_lib_formatters) && defined(__glibcxx_want_formatters) */ #undef __glibcxx_want_formatters -// from version.def line 1615 +// from version.def line 1617 #if !defined(__cpp_lib_forward_like) # if (__cplusplus >= 202100L) # define __glibcxx_forward_like 202207L @@ -1982,7 +1971,7 @@ #endif /* !defined(__cpp_lib_forward_like) && defined(__glibcxx_want_forward_like) */ #undef __glibcxx_want_forward_like -// from version.def line 1623 +// from version.def line 1625 #if !defined(__cpp_lib_ios_noreplace) # if (__cplusplus >= 202100L) && _GLIBCXX_HOSTED # define __glibcxx_ios_noreplace 202207L @@ -1993,7 +1982,7 @@ #endif /* !defined(__cpp_lib_ios_noreplace) && defined(__glibcxx_want_ios_noreplace) */ #undef __glibcxx_want_ios_noreplace -// from version.def line 1632 +// from version.def line 1634 #if !defined(__cpp_lib_move_only_function) # if (__cplusplus >= 202100L) && _GLIBCXX_HOSTED # define __glibcxx_move_only_function 202110L @@ -2004,7 +1993,7 @@ #endif /* !defined(__cpp_lib_move_only_function) && defined(__glibcxx_want_move_only_function) */ #undef __glibcxx_want_move_only_function -// from version.def line 1641 +// from version.def line 1643 #if !defined(__cpp_lib_out_ptr) # if (__cplusplus >= 202100L) # define __glibcxx_out_ptr 202311L @@ -2015,7 +2004,7 @@ #endif /* !defined(__cpp_lib_out_ptr) && defined(__glibcxx_want_out_ptr) */ #undef __glibcxx_want_out_ptr -// from version.def line 1649 +// from version.def line 1651 #if !defined(__cpp_lib_spanstream) # if (__cplusplus >= 202100L) && _GLIBCXX_HOSTED && (__glibcxx_span) # define __glibcxx_spanstream 202106L @@ -2026,7 +2015,7 @@ #endif /* !defined(__cpp_lib_spanstream) && defined(__glibcxx_want_spanstream) */ #undef __glibcxx_want_spanstream -// from version.def line 1659 +// from version.def line 1661 #if !defined(__cpp_lib_stacktrace) # if (__cplusplus >= 202100L) && _GLIBCXX_HOSTED && (_GLIBCXX_HAVE_STACKTRACE) # define __glibcxx_stacktrace 202011L @@ -2037,7 +2026,7 @@ #endif /* !defined(__cpp_lib_stacktrace) && defined(__glibcxx_want_stacktrace) */ #undef __glibcxx_want_stacktrace -// from version.def line 1669 +// from version.def line 1671 #if !defined(__cpp_lib_string_contains) # if (__cplusplus >= 202100L) && _GLIBCXX_HOSTED # define __glibcxx_string_contains 202011L @@ -2048,7 +2037,7 @@ #endif /* !defined(__cpp_lib_string_contains) && defined(__glibcxx_want_string_contains) */ #undef __glibcxx_want_string_contains -// from version.def line 1678 +// from version.def line 1680 #if !defined(__cpp_lib_string_resize_and_overwrite) # if (__cplusplus >= 202100L) && _GLIBCXX_HOSTED # define __glibcxx_string_resize_and_overwrite 202110L @@ -2059,7 +2048,29 @@ #endif /* !defined(__cpp_lib_string_resize_and_overwrite) && defined(__glibcxx_want_string_resize_and_overwrite) */ #undef __glibcxx_want_string_resize_and_overwrite -// from version.def line 1687 +// from version.def line 1689 +#if !defined(__cpp_lib_to_underlying) +# if (__cplusplus >= 202100L) +# define __glibcxx_to_underlying 202102L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_to_underlying) +# define __cpp_lib_to_underlying 202102L +# endif +# endif +#endif /* !defined(__cpp_lib_to_underlying) && defined(__glibcxx_want_to_underlying) */ +#undef __glibcxx_want_to_underlying + +// from version.def line 1697 +#if !defined(__cpp_lib_unreachable) +# if (__cplusplus >= 202100L) +# define __glibcxx_unreachable 202202L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_unreachable) +# define __cpp_lib_unreachable 202202L +# endif +# endif +#endif /* !defined(__cpp_lib_unreachable) && defined(__glibcxx_want_unreachable) */ +#undef __glibcxx_want_unreachable + +// from version.def line 1705 #if !defined(__cpp_lib_fstream_native_handle) # if (__cplusplus > 202302L) && _GLIBCXX_HOSTED # define __glibcxx_fstream_native_handle 202306L @@ -2070,7 +2081,7 @@ #endif /* !defined(__cpp_lib_fstream_native_handle) && defined(__glibcxx_want_fstream_native_handle) */ #undef __glibcxx_want_fstream_native_handle -// from version.def line 1696 +// from version.def line 1714 #if !defined(__cpp_lib_ratio) # if (__cplusplus > 202302L) # define __glibcxx_ratio 202306L @@ -2081,7 +2092,7 @@ #endif /* !defined(__cpp_lib_ratio) && defined(__glibcxx_want_ratio) */ #undef __glibcxx_want_ratio -// from version.def line 1704 +// from version.def line 1722 #if !defined(__cpp_lib_saturation_arithmetic) # if (__cplusplus > 202302L) # define __glibcxx_saturation_arithmetic 202311L @@ -2092,7 +2103,7 @@ #endif /* !defined(__cpp_lib_saturation_arithmetic) && defined(__glibcxx_want_saturation_arithmetic) */ #undef __glibcxx_want_saturation_arithmetic -// from version.def line 1712 +// from version.def line 1730 #if !defined(__cpp_lib_to_string) # if (__cplusplus > 202302L) && _GLIBCXX_HOSTED && (__glibcxx_to_chars) # define __glibcxx_to_string 202306L diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges index 26d6c01..63bea86 100644 --- a/libstdc++-v3/include/std/ranges +++ b/libstdc++-v3/include/std/ranges @@ -64,6 +64,7 @@ #define __glibcxx_want_ranges_repeat #define __glibcxx_want_ranges_slide #define __glibcxx_want_ranges_stride +#define __glibcxx_want_ranges_to_container #define __glibcxx_want_ranges_zip #include <bits/version.h> @@ -9213,8 +9214,366 @@ namespace views::__adaptor namespace views = ranges::views; +#if __cpp_lib_ranges_to_container // C++ >= 23 +namespace ranges +{ +/// @cond undocumented +namespace __detail +{ + template<typename _Container> + constexpr bool __reservable_container + = sized_range<_Container> + && requires(_Container& __c, range_size_t<_Container> __n) { + __c.reserve(__n); + { __c.capacity() } -> same_as<decltype(__n)>; + { __c.max_size() } -> same_as<decltype(__n)>; + }; + + template<typename _Container, typename _Ref> + constexpr bool __container_insertable + = requires(_Container& __c, _Ref&& __ref) { + typename _Container::value_type; + requires ( + requires { __c.push_back(std::forward<_Ref>(__ref)); } + || requires { __c.insert(__c.end(), std::forward<_Ref>(__ref)); } + ); + }; + + template<typename _Ref, typename _Container> + constexpr auto + __container_inserter(_Container& __c) + { + if constexpr (requires { __c.push_back(std::declval<_Ref>()); }) + return std::back_inserter(__c); + else + return std::inserter(__c, __c.end()); + } + + template<typename _Cont, typename _Range> + constexpr bool __toable = requires { + requires (!input_range<_Range> + || convertible_to<range_reference_t<_Range>, + range_value_t<_Cont>>); + }; +} // namespace __detail +/// @endcond + + /// Convert a range to a container. + /** + * @tparam _Cont A container type. + * @param __r A range that models the `input_range` concept. + * @param __args... Arguments to pass to the container constructor. + * @since C++23 + * + * This function converts a range to the `_Cont` type. + * + * For example, `std::ranges::to<std::vector<int>>(some_view)` + * will convert the view to `std::vector<int>`. + * + * Additional constructor arguments for the container can be supplied after + * the input range argument, e.g. + * `std::ranges::to<std::vector<int, Alloc<int>>>(a_range, an_allocator)`. + */ + template<typename _Cont, input_range _Rg, typename... _Args> + requires (!view<_Cont>) + constexpr _Cont + to [[nodiscard]] (_Rg&& __r, _Args&&... __args) + { + static_assert(!is_const_v<_Cont> && !is_volatile_v<_Cont>); + static_assert(is_class_v<_Cont>); + + if constexpr (__detail::__toable<_Cont, _Rg>) + { + if constexpr (constructible_from<_Cont, _Rg, _Args...>) + return _Cont(std::forward<_Rg>(__r), + std::forward<_Args>(__args)...); + else if constexpr (constructible_from<_Cont, from_range_t, _Rg, _Args...>) + return _Cont(from_range, std::forward<_Rg>(__r), + std::forward<_Args>(__args)...); + else if constexpr (requires { common_range<_Rg>; + typename __iter_category_t<iterator_t<_Rg>>; + requires derived_from<__iter_category_t<iterator_t<_Rg>>, + input_iterator_tag>; + requires constructible_from<_Cont, iterator_t<_Rg>, + sentinel_t<_Rg>, _Args...>; + }) + return _Cont(ranges::begin(__r), ranges::end(__r), + std::forward<_Args>(__args)...); + else + { + using __detail::__container_insertable; + using __detail::__reservable_container; + using _RefT = range_reference_t<_Rg>; + static_assert(constructible_from<_Cont, _Args...>); + static_assert(__container_insertable<_Cont, _RefT>); + _Cont __c(std::forward<_Args>(__args)...); + if constexpr (sized_range<_Rg> && __reservable_container<_Cont>) + __c.reserve(static_cast<range_size_t<_Cont>>(ranges::size(__r))); + auto __ins = __detail::__container_inserter<_RefT>(__c); + for (auto&& __e : __r) + *__ins++ = std::forward<decltype(__e)>(__e); + return __c; + } + } + else + { + static_assert(input_range<range_reference_t<_Rg>>); + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 3984. ranges::to's recursion branch may be ill-formed + return ranges::to<_Cont>(ref_view(__r) | views::transform( + []<typename _Elt>(_Elt&& __elem) { + using _ValT = range_value_t<_Cont>; + return ranges::to<_ValT>(std::forward<_Elt>(__elem)); + }), std::forward<_Args>(__args)...); + } + } + +/// @cond undocumented +namespace __detail +{ + template<typename _Rg> + struct _InputIter + { + using iterator_category = input_iterator_tag; + using value_type = range_value_t<_Rg>; + using difference_type = ptrdiff_t; + using pointer = add_pointer_t<range_reference_t<_Rg>>; + using reference = range_reference_t<_Rg>; + reference operator*() const; + pointer operator->() const; + _InputIter& operator++(); + _InputIter operator++(int); + bool operator==(const _InputIter&) const; + }; + +#if 0 + template<template<typename...> typename _Cont, typename _Rg, + typename... _Args> + concept __deduce_expr_1 = requires { + _Cont(std::declval<_Rg>(), std::declval<_Args>()...); + }; + + template<template<typename...> typename _Cont, typename _Rg, + typename... _Args> + concept __deduce_expr_2 = requires { + _Cont(from_range, std::declval<_Rg>(), std::declval<_Args>()...); + }; + + template<template<typename...> typename _Cont, typename _Rg, + typename... _Args> + concept __deduce_expr_3 = requires(_InputIter<_Rg> __i) { + _Cont(std::move(__i), std::move(__i), std::declval<_Args>()...); + }; +#endif + + template<template<typename...> typename _Cont, input_range _Rg, + typename... _Args> + using _DeduceExpr1 + = decltype(_Cont(std::declval<_Rg>(), std::declval<_Args>()...)); + + template<template<typename...> typename _Cont, input_range _Rg, + typename... _Args> + using _DeduceExpr2 + = decltype(_Cont(from_range, std::declval<_Rg>(), + std::declval<_Args>()...)); + + template<template<typename...> typename _Cont, input_range _Rg, + typename... _Args> + using _DeduceExpr3 + = decltype(_Cont(std::declval<_InputIter<_Rg>>(), + std::declval<_InputIter<_Rg>>(), + std::declval<_Args>()...)); + +} // namespace __detail +/// @endcond + + template<template<typename...> typename _Cont, input_range _Rg, + typename... _Args> + constexpr auto + to [[nodiscard]] (_Rg&& __r, _Args&&... __args) + { + using __detail::_DeduceExpr1; + using __detail::_DeduceExpr2; + using __detail::_DeduceExpr3; + if constexpr (requires { typename _DeduceExpr1<_Cont, _Rg, _Args...>; }) + return ranges::to<_DeduceExpr1<_Cont, _Rg, _Args...>>( + std::forward<_Rg>(__r), std::forward<_Args>(__args)...); + else if constexpr (requires { typename _DeduceExpr2<_Cont, _Rg, _Args...>; }) + return ranges::to<_DeduceExpr2<_Cont, _Rg, _Args...>>( + std::forward<_Rg>(__r), std::forward<_Args>(__args)...); + else if constexpr (requires { typename _DeduceExpr3<_Cont, _Rg, _Args...>; }) + return ranges::to<_DeduceExpr3<_Cont, _Rg, _Args...>>( + std::forward<_Rg>(__r), std::forward<_Args>(__args)...); + else + static_assert(false); // Cannot deduce container specialization. + } + +/// @cond undocumented +namespace __detail +{ + template<typename _Cont, typename... _Args> + class _ToClosure + : public views::__adaptor::_RangeAdaptorClosure<_ToClosure<_Cont, _Args...>> + { + tuple<decay_t<_Args>...> _M_bound_args; + + public: + _ToClosure(_Args&&... __args) + : _M_bound_args(std::forward<_Args>(__args)...) + { } + + // TODO: use explicit object functions ("deducing this"). + + template<typename _Rg> + constexpr auto + operator()(_Rg&& __r) & + { + return std::apply([&__r]<typename... _Tp>(_Tp&&... __args) { + return ranges::to<_Cont>(std::forward<_Rg>(__r), + std::forward<_Tp>(__args)...); + }, _M_bound_args); + } + + template<typename _Rg> + constexpr auto + operator()(_Rg&& __r) const & + { + return std::apply([&__r]<typename... _Tp>(_Tp&&... __args) { + return ranges::to<_Cont>(std::forward<_Rg>(__r), + std::forward<_Tp>(__args)...); + }, _M_bound_args); + } + + template<typename _Rg> + constexpr auto + operator()(_Rg&& __r) && + { + return std::apply([&__r]<typename... _Tp>(_Tp&&... __args) { + return ranges::to<_Cont>(std::forward<_Rg>(__r), + std::forward<_Tp>(__args)...); + }, std::move(_M_bound_args)); + } + + template<typename _Rg> + constexpr auto + operator()(_Rg&& __r) const && + { + return std::apply([&__r]<typename... _Tp>(_Tp&&... __args) { + return ranges::to<_Cont>(std::forward<_Rg>(__r), + std::forward<_Tp>(__args)...); + }, std::move(_M_bound_args)); + } + }; +} // namespace __detail +/// @endcond + + /// ranges::to adaptor for converting a range to a container type + /** + * @tparam _Cont A container type. + * @param __args... Arguments to pass to the container constructor. + * @since C++23 + * + * This range adaptor returns a range adaptor closure object that converts + * a range to the `_Cont` type. + * + * For example, `some_view | std::ranges::to<std::vector<int>>()` + * will convert the view to `std::vector<int>`. + * + * Additional constructor arguments for the container can be supplied, e.g. + * `r | std::ranges::to<std::vector<int, Alloc<int>>>(an_allocator)`. + */ + template<typename _Cont, typename... _Args> + requires (!view<_Cont>) + constexpr __detail::_ToClosure<_Cont, _Args...> + to [[nodiscard]] (_Args&&... __args) + { return {std::forward<_Args>(__args)...}; } + +/// @cond undocumented +namespace __detail +{ + template<template<typename...> typename _Cont, typename... _Args> + class _ToClosure2 + : public views::__adaptor::_RangeAdaptorClosure<_ToClosure2<_Cont, _Args...>> + { + tuple<decay_t<_Args>...> _M_bound_args; + + public: + _ToClosure2(_Args&&... __args) + : _M_bound_args(std::forward<_Args>(__args)...) + { } + + // TODO: use explicit object functions ("deducing this"). + + template<typename _Rg> + constexpr auto + operator()(_Rg&& __r) & + { + return std::apply([&__r]<typename... _Tp>(_Tp&&... __args) { + return ranges::to<_Cont>(std::forward<_Rg>(__r), + std::forward<_Tp>(__args)...); + }, _M_bound_args); + } + + template<typename _Rg> + constexpr auto + operator()(_Rg&& __r) const & + { + return std::apply([&__r]<typename... _Tp>(_Tp&&... __args) { + return ranges::to<_Cont>(std::forward<_Rg>(__r), + std::forward<_Tp>(__args)...); + }, _M_bound_args); + } + + template<typename _Rg> + constexpr auto + operator()(_Rg&& __r) && + { + return std::apply([&__r]<typename... _Tp>(_Tp&&... __args) { + return ranges::to<_Cont>(std::forward<_Rg>(__r), + std::forward<_Tp>(__args)...); + }, std::move(_M_bound_args)); + } + + template<typename _Rg> + constexpr auto + operator()(_Rg&& __r) const && + { + return std::apply([&__r]<typename... _Tp>(_Tp&&... __args) { + return ranges::to<_Cont>(std::forward<_Rg>(__r), + std::forward<_Tp>(__args)...); + }, std::move(_M_bound_args)); + } + }; +} // namespace __detail +/// @endcond + + /// ranges::to adaptor for converting a range to a deduced container type. + /** + * @tparam _Cont A container template. + * @param __args... Arguments to pass to the container constructor. + * @since C++23 + * + * This range adaptor returns a range adaptor closure object that converts + * a range to a specialization of the `_Cont` class template. The specific + * specialization of `_Cont` to be used is deduced automatically. + * + * For example, `some_view | std::ranges::to<std::vector>(Alloc<int>{})` + * will convert the view to `std::vector<T, Alloc<T>>`, where `T` is the + * view's value type, i.e. `std::ranges::range_value_t<decltype(some_view)>`. + * + * Additional constructor arguments for the container can be supplied, e.g. + * `r | std::ranges::to<std::vector>(an_allocator)`. + */ + template<template<typename...> typename _Cont, typename... _Args> + constexpr __detail::_ToClosure2<_Cont, _Args...> + to [[nodiscard]] (_Args&&... __args) + { return {std::forward<_Args>(__args)...}; } + +} // namespace ranges +#endif // __cpp_lib_ranges_to_container + _GLIBCXX_END_NAMESPACE_VERSION -} // namespace +} // namespace std #endif // library concepts #endif // C++2a #endif /* _GLIBCXX_RANGES */ diff --git a/libstdc++-v3/testsuite/std/ranges/conv/1.cc b/libstdc++-v3/testsuite/std/ranges/conv/1.cc new file mode 100644 index 0000000..0032cf32 --- /dev/null +++ b/libstdc++-v3/testsuite/std/ranges/conv/1.cc @@ -0,0 +1,369 @@ +// { dg-do run { target c++23 } } + +// C++23 26.5.7 Range conversions [range.utility.conv] + +#include <ranges> +#include <vector> +#include <string> +#include <deque> +#include <list> +#include <forward_list> +#include <map> +#include <testsuite_hooks.h> +#include <testsuite_allocator.h> +#include <testsuite_iterators.h> + +void +test_p1206r7_examples() +{ + using Alloc = __gnu_test::uneq_allocator<int>; + const Alloc alloc(303); + const std::map<int, const char*> m{{1, "one"}, {2, "two"}, {3, "three"}}; + namespace ranges = std::ranges; + + auto l = std::views::iota(1, 10); + // create a vector with the elements of l + auto vec = ranges::to<std::vector<int>>(l); // or vector{std::from_range, l}; + //Specify an allocator + auto b = ranges::to<std::vector<int, Alloc>>(l, alloc); // or vector{std::from_range, l, alloc}; + //deducing value_type + auto c = ranges::to<std::vector>(l); + // explicit conversion int -> long + auto d = ranges::to<std::vector<long>>(l); + //Supports converting associative container to sequence containers + auto f = ranges::to<std::vector>(m); + //Supports converting sequence containers to associative ones + auto g = ranges::to<std::map>(f); + //Pipe syntax + auto g2 = l | ranges::views::take(42) | ranges::to<std::vector>(); + //Pipe syntax with allocator + auto h = l | ranges::views::take(42) | ranges::to<std::vector>(alloc); + //The pipe syntax also support specifying the type and conversions + auto i = l | ranges::views::take(42) | ranges::to<std::vector<long>>(); + // Nested ranges + std::list<std::forward_list<int>> lst = {{0, 1, 2, 3}, {4, 5, 6, 7}}; + auto vec1 = ranges::to<std::vector<std::vector<int>>>(lst); + auto vec2 = ranges::to<std::vector<std::deque<double>>>(lst); + + VERIFY( vec == std::vector<int>(std::ranges::begin(l), std::ranges::end(l)) ); + static_assert(std::is_same_v<decltype(b), std::vector<int, Alloc>>); + VERIFY( b == (std::vector<int, Alloc>(vec.begin(), vec.end())) ); + VERIFY( b.get_allocator() == alloc ); + static_assert(std::is_same_v<decltype(c), std::vector<int>>); + VERIFY( c == vec ); + static_assert(std::is_same_v<decltype(d), std::vector<long>>); + VERIFY( d == std::vector<long>(vec.begin(), vec.end()) ); + VERIFY( g == m ); + static_assert(std::is_same_v<decltype(g2), std::vector<int>>); + VERIFY( g2 == vec ); + static_assert(std::is_same_v<decltype(h), std::vector<int, Alloc>>); + VERIFY( h == b ); + VERIFY( h.get_allocator() == alloc ); + VERIFY( i == d ); + static_assert(std::is_same_v<decltype(vec1), std::vector<std::vector<int>>>); + VERIFY( vec1[1][1] == 5 ); + static_assert(std::is_same_v<decltype(vec2), std::vector<std::deque<double>>>); + VERIFY( vec2[1][2] == 6.0 ); +} + +void +test_example_1() +{ + using namespace std; + using ranges::to; + + // Example 1 from C++23 [range.utility.conv.general] + string_view str = "the quick brown fox"; + auto words = views::split(str, ' ') | to<vector<string>>(); + + VERIFY( (is_same_v<decltype(words), vector<string>>) ); + VERIFY( words == vector<string>({"the", "quick", "brown", "fox"}) ); +} + +template<typename C> +struct Cont1 +{ + template<typename R, typename... Args> + requires std::constructible_from<C, R&, Args&...> + Cont1(R&& r, Args&&... args) + : c(r, args...) + { } + + typename C::iterator begin(); + typename C::iterator end(); + + C c; +}; + +void +test_2_1_1() +{ + // (2.1.1) constructible_from<C, R, Args...> + + std::vector<int> v{1, 2, 3, 4}; + auto v2 = std::ranges::to<std::vector<int>>(v); + static_assert(std::is_same_v<decltype(v2), decltype(v)>); + VERIFY( v2 == v ); + + std::initializer_list<int> il{5, 6, 7, 8}; + v2 = std::ranges::to<std::vector<int>>(il); + VERIFY( v2 == std::vector<int>(il) ); + + v2 = std::ranges::to<std::vector<int>>(il, std::allocator<int>{}); + VERIFY( v2 == std::vector<int>(il) ); + + using Alloc = __gnu_test::uneq_allocator<int>; + using V = std::vector<int, Alloc>; + + V v3({10, 11, 12, 13}, Alloc(14)); + auto v4 = std::ranges::to<V>(v3); + static_assert(std::is_same_v<decltype(v4), V>); + VERIFY( v4 == v3 ); + VERIFY( v4.get_allocator() == v3.get_allocator() ); + + auto v5 = std::ranges::to<V>(v3, Alloc(33)); + VERIFY( v5 == v3 ); + VERIFY( v5.get_allocator() == Alloc(33) ); + + auto v6 = std::ranges::to<V>(il, Alloc(44)); + VERIFY( v6 == V(il) ); + VERIFY( v6.get_allocator() == Alloc(44) ); + + auto c = std::ranges::to<Cont1<V>>(V{1, 2, 3}); + static_assert(std::is_same_v<decltype(c), Cont1<V>>); + VERIFY( c.c == V({1, 2, 3}) ); + + auto c2 = std::ranges::to<Cont1<V>>(V{4, 5, 6}, Alloc(55)); + static_assert(std::is_same_v<decltype(c2), Cont1<V>>); + VERIFY( c2.c == V({4, 5, 6}) ); + VERIFY( c2.c.get_allocator() == Alloc(55) ); + + auto c3 = std::ranges::to<Cont1<V>>(il, Alloc(66)); + static_assert(std::is_same_v<decltype(c2), Cont1<V>>); + VERIFY( c3.c == V(v2.begin(), v2.end()) ); + VERIFY( c3.c.get_allocator() == Alloc(66) ); +} + +template<typename C> +struct Cont2 +{ + template<typename R, typename... Args> + requires std::constructible_from<C, R&, Args&...> + Cont2(std::from_range_t, R&& r, Args&&... args) + : c(r, args...) + { } + + typename C::iterator begin(); + typename C::iterator end(); + + C c; +}; + +void +test_2_1_2() +{ + // (2.1.2) constructible_from<C, from_range_t, R, Args...> + + using Alloc = __gnu_test::uneq_allocator<int>; + using V = std::vector<int, Alloc>; + auto c = std::ranges::to<Cont2<V>>(V{1, 2, 3}); + static_assert(std::is_same_v<decltype(c), Cont2<V>>); + VERIFY( c.c == V({1, 2, 3}) ); + + auto c2 = std::ranges::to<Cont2<V>>(V{4, 5, 6}, Alloc(7)); + static_assert(std::is_same_v<decltype(c2), Cont2<V>>); + VERIFY( c2.c == V({4, 5, 6}) ); + VERIFY( c2.c.get_allocator() == Alloc(7) ); +} + +template<typename C> +struct Cont3 +{ + template<typename It, typename Sent, typename... Args> + requires std::same_as<It, Sent> + && std::constructible_from<C, It&, Sent&, Args&...> + Cont3(It first, Sent last, Args&&... args) + : c(first, last, args...) + { } + + typename C::iterator begin(); + typename C::iterator end(); + + C c; +}; + +void +test_2_1_3() +{ + // (2.1.3) constructible_from<C, iterator_t<R>, sentinel_t<R<, Args...> + + using Alloc = __gnu_test::uneq_allocator<int>; + using V = std::vector<int, Alloc>; + + std::list<unsigned> l{1u, 2u, 3u}; + auto c = std::ranges::to<Cont3<V>>(l); + static_assert(std::is_same_v<decltype(c), Cont3<V>>); + VERIFY( c.c == V(l.begin(), l.end()) ); + + std::list<long> l2{4l, 5l, 6l}; + auto c2 = std::ranges::to<Cont3<V>>(l2, Alloc(78)); + static_assert(std::is_same_v<decltype(c2), Cont3<V>>); + VERIFY( c2.c == V(l2.begin(), l2.end()) ); + VERIFY( c2.c.get_allocator() == Alloc(78) ); +} + +template<typename C, bool UsePushBack = true> +struct Cont4 +{ + using value_type = typename C::value_type; + + // Only support construction with no args or an allocator. + // This forces the use of either push_back or insert to fill the container. + Cont4() { } + Cont4(typename C::allocator_type a) : c(a) { } + + // Required to satisfy range + typename C::iterator begin() { return c.begin(); } + typename C::iterator end() { return c.end(); } + + // Satisfying container-insertable requires either this ... + template<typename T> + requires UsePushBack + && requires(C& c, T&& t) { c.push_back(std::forward<T>(t)); } + void + push_back(T&& t) + { + c.push_back(std::forward<T>(t)); + used_push_back = true; + } + + // ... or this: + template<typename T> + typename C::iterator + insert(typename C::iterator, T&& t) + { + used_push_back = false; + return c.insert(c.end(), std::forward<T>(t)); + } + + // Required to satisfy reservable-container + void + reserve(typename C::size_type n) requires requires(C& c) { c.reserve(n); } + { + c.reserve(n); + used_reserve = true; + } + + // Required to satisfy reservable-container + auto size() const { return c.size(); } + + // Required to satisfy reservable-container + auto capacity() const requires requires(C& c) { c.capacity(); } + { return c.capacity(); } + + // Required to satisfy reservable-container + auto max_size() const { return c.max_size(); } + + C c; + bool used_push_back = false; + bool used_reserve = false; +}; + +void +test_2_1_4() +{ + // (2.1.4) constructible_from<C, Args...> and + // container-insertable<C, range_reference_t<R>> + + using Alloc = __gnu_test::uneq_allocator<int>; + using V = std::vector<int, Alloc>; + + std::list<unsigned> l{1u, 2u, 3u}; + auto c = std::ranges::to<Cont4<V>>(l); + static_assert(std::is_same_v<decltype(c), Cont4<V>>); + VERIFY( c.c == V(l.begin(), l.end()) ); + VERIFY( c.used_push_back ); + VERIFY( c.used_reserve ); + + std::list<long> l2{4l, 5l, 6l}; + auto c2 = std::ranges::to<Cont4<V>>(l2, Alloc(78)); + static_assert(std::is_same_v<decltype(c2), Cont4<V>>); + VERIFY( c2.c == V(l2.begin(), l2.end()) ); + VERIFY( c2.c.get_allocator() == Alloc(78) ); + VERIFY( c2.used_push_back ); + VERIFY( c2.used_reserve ); + + using Alloc2 = __gnu_test::uneq_allocator<short>; + using List = std::list<short, Alloc2>; + auto c3 = std::ranges::to<Cont4<List>>(c.c, Alloc2(99)); + static_assert(std::is_same_v<decltype(c3), Cont4<List>>); + VERIFY( c3.c == List(l.begin(), l.end()) ); + VERIFY( c3.c.get_allocator() == Alloc(99) ); + VERIFY( c3.used_push_back ); + VERIFY( ! c3.used_reserve ); + + auto c4 = std::ranges::to<Cont4<List, false>>(c.c, Alloc2(111)); + static_assert(std::is_same_v<decltype(c4), Cont4<List, false>>); + VERIFY( c4.c == List(l.begin(), l.end()) ); + VERIFY( c4.c.get_allocator() == Alloc(111) ); + VERIFY( ! c4.used_push_back ); + VERIFY( ! c4.used_reserve ); +} + +void +test_2_2() +{ + // (2.2) input_range<range_reference_t<R>> + + std::string s1[]{ "one", "two", "three", "four" }; + std::string s2[]{ "V", "VI", "VII", "VIII" }; + std::string s3[]{ "0x09", "0x0a", "0x0b", "0x0c" }; + using R = __gnu_test::test_input_range<std::string>; + R input_ranges[]{R(s1), R(s2), R(s3)}; + __gnu_test::test_input_range<R> rr(input_ranges); + namespace pmr = std::pmr; + __gnu_test::memory_resource res; +#if _GLIBCXX_USE_CXX11_ABI + auto vvs = std::ranges::to<pmr::vector<pmr::vector<pmr::string>>>(rr, &res); + auto str_alloc = pmr::polymorphic_allocator<char>(&res); +#else + auto vvs = std::ranges::to<pmr::vector<pmr::vector<std::string>>>(rr, &res); + auto str_alloc = std::allocator<char>(); +#endif + VERIFY( vvs[1][1] == "VI" ); + VERIFY( vvs[2][2] == "0x0b" ); + VERIFY( vvs[0].get_allocator().resource() == &res ); + VERIFY( vvs[2][2].get_allocator() == str_alloc ); +} + +void +test_lwg3984() +{ + std::vector<std::vector<int>> v; + auto r = std::views::all(std::move(v)); + auto l = std::ranges::to<std::list<std::list<int>>>(r); + VERIFY(l.empty()); +} + +void +test_nodiscard() +{ + std::vector<int> v; + std::ranges::to<std::vector<long>>(v); // { dg-warning "ignoring return" } + std::ranges::to<std::vector>(v); // { dg-warning "ignoring return" } + std::ranges::to<std::vector<long>>(); // { dg-warning "ignoring return" } + std::ranges::to<std::vector>(); // { dg-warning "ignoring return" } +} + +int main() +{ + test_p1206r7_examples(); + test_example_1(); + test_2_1_1(); + test_2_1_2(); + test_2_1_3(); + test_2_1_4(); + test_2_2(); + test_lwg3984(); + test_nodiscard(); +} diff --git a/libstdc++-v3/testsuite/std/ranges/conv/2_neg.cc b/libstdc++-v3/testsuite/std/ranges/conv/2_neg.cc new file mode 100644 index 0000000..1e5f6f1 --- /dev/null +++ b/libstdc++-v3/testsuite/std/ranges/conv/2_neg.cc @@ -0,0 +1,24 @@ +// { dg-do compile { target c++23 } } + +// C++23 26.5.7 Range conversions [range.utility.conv] + +#include <ranges> +#include <vector> +#include <testsuite_allocator.h> + +void +test_2_1_5() +{ + // (2.1.5) Otherwise, the program is ill-formed. + + using Alloc = __gnu_test::uneq_allocator<int>; + using Vec = std::vector<int, Alloc>; + + std::vector<int> v; + (void) std::ranges::to<Vec>(v, v.get_allocator()); // { dg-error "here" } + + (void) std::ranges::to<Vec>(Vec{}, 1, 2, 3, 4, 5, 6); // { dg-error "here" } +} + +// { dg-error "static assertion failed" "" { target *-*-* } 0 } +// { dg-prune-output "no matching function" } diff --git a/libstdc++-v3/testsuite/std/ranges/conv/version.cc b/libstdc++-v3/testsuite/std/ranges/conv/version.cc new file mode 100644 index 0000000..3373680 --- /dev/null +++ b/libstdc++-v3/testsuite/std/ranges/conv/version.cc @@ -0,0 +1,19 @@ +// { dg-do preprocess { target c++23 } } +// { dg-add-options no_pch } + +#include <ranges> + +#ifndef __cpp_lib_ranges_to_container +# error "Feature test macro for ranges_to_container is missing in <ranges>" +#elif __cpp_lib_ranges_to_container < 202202L +# error "Feature test macro for ranges_to_container has wrong value in <ranges>" +#endif + +#undef __cpp_lib_ranges_to_container +#include <version> + +#ifndef __cpp_lib_ranges_to_container +# error "Feature test macro for ranges_to_container is missing in <version>" +#elif __cpp_lib_ranges_to_container < 202202L +# error "Feature test macro for ranges_to_container has wrong value in <version>" +#endif |