mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-10-08 11:44:05 +00:00
[libc++][ranges] Implement ranges::to
.
Differential Revision: https://reviews.llvm.org/D142335
This commit is contained in:
parent
7baf5d3841
commit
c3648f37d0
@ -358,7 +358,7 @@ Status
|
||||
--------------------------------------------------- -----------------
|
||||
``__cpp_lib_ranges_starts_ends_with`` *unimplemented*
|
||||
--------------------------------------------------- -----------------
|
||||
``__cpp_lib_ranges_to_container`` *unimplemented*
|
||||
``__cpp_lib_ranges_to_container`` ``202202L``
|
||||
--------------------------------------------------- -----------------
|
||||
``__cpp_lib_ranges_zip`` *unimplemented*
|
||||
--------------------------------------------------- -----------------
|
||||
|
@ -55,6 +55,7 @@ Work has started on the C++17 Parallel STL. This feature is experimental, see
|
||||
|
||||
Implemented Papers
|
||||
------------------
|
||||
- P1206R7 - ``ranges::to``: A function to convert any range to a container
|
||||
- P2520R0 - ``move_iterator<T*>`` should be a random access iterator
|
||||
- P1328R1 - ``constexpr type_info::operator==()``
|
||||
- P1413R3 - Formatting ``thread::id`` (the ``stacktrace`` is not done yet)
|
||||
|
@ -258,7 +258,7 @@
|
||||
"`3820 <https://wg21.link/LWG3820>`__","``cartesian_product_view::iterator::prev`` is not quite right","February 2023","","","|ranges|"
|
||||
"`3825 <https://wg21.link/LWG3825>`__","Missing compile-time argument ``id`` check in ``basic_format_parse_context::next_arg_id``","February 2023","|Complete|","17.0","|format|"
|
||||
"`3204 <https://wg21.link/LWG3204>`__","``sub_match::swap`` only swaps the base class","February 2023","|Complete|","17.0",""
|
||||
"`3733 <https://wg21.link/LWG3733>`__","``ranges::to`` misuses ``cpp17-input-iterator``","February 2023","","","|ranges|"
|
||||
"`3733 <https://wg21.link/LWG3733>`__","``ranges::to`` misuses ``cpp17-input-iterator``","February 2023","|Complete|","17.0","|ranges|"
|
||||
"`3742 <https://wg21.link/LWG3742>`__","``deque::prepend_range`` needs to permute","February 2023","","","|ranges|"
|
||||
"`3790 <https://wg21.link/LWG3790>`__","`P1467 <https://wg21.link/P1467>`__ accidentally changed ``nexttoward``'s signature","February 2023","","",""
|
||||
"`3819 <https://wg21.link/LWG3819>`__","``reference_meows_from_temporary`` should not use ``is_meowible``","February 2023","","",""
|
||||
@ -292,7 +292,7 @@
|
||||
"`3833 <https://wg21.link/LWG3833>`__","Remove specialization ``template<size_t N> struct formatter<const charT[N], charT>``","February 2023","|Complete|","17.0","|format|"
|
||||
"`3836 <https://wg21.link/LWG3836>`__","``std::expected<bool, E1>`` conversion constructor ``expected(const expected<U, G>&)`` should take precedence over ``expected(U&&)`` with operator ``bool``","February 2023","","",""
|
||||
"`3843 <https://wg21.link/LWG3843>`__","``std::expected<T,E>::value() &`` assumes ``E`` is copy constructible","February 2023","|Complete|","17.0",""
|
||||
"`3847 <https://wg21.link/LWG3847>`__","``ranges::to`` can still return views","February 2023","","","|ranges|"
|
||||
"`3847 <https://wg21.link/LWG3847>`__","``ranges::to`` can still return views","February 2023","|Complete|","17.0","|ranges|"
|
||||
"`3862 <https://wg21.link/LWG3862>`__","``basic_const_iterator``'s ``common_type`` specialization is underconstrained","February 2023","","",""
|
||||
"`3865 <https://wg21.link/LWG3865>`__","Sorting a range of ``pairs``","February 2023","|Complete|","17.0","|ranges|"
|
||||
"`3869 <https://wg21.link/LWG3869>`__","Deprecate ``std::errc`` constants related to UNIX STREAMS","February 2023","","",""
|
||||
|
Can't render this file because it has a wrong number of fields in line 2.
|
@ -41,7 +41,7 @@
|
||||
"`P0323R12 <https://wg21.link/P0323R12>`__","LWG","``std::expected``","February 2022","|Complete|","16.0"
|
||||
"`P0533R9 <https://wg21.link/P0533R9>`__","LWG","``constexpr`` for ``<cmath>`` and ``<cstdlib>``","February 2022","|In progress| [#note-P0533R9]_",""
|
||||
"`P0627R6 <https://wg21.link/P0627R6>`__","LWG","Function to mark unreachable code","February 2022","|Complete|","15.0"
|
||||
"`P1206R7 <https://wg21.link/P1206R7>`__","LWG","``ranges::to``: A function to convert any range to a container","February 2022","|In Progress|","","|ranges|"
|
||||
"`P1206R7 <https://wg21.link/P1206R7>`__","LWG","``ranges::to``: A function to convert any range to a container","February 2022","|Complete|","17.0","|ranges|"
|
||||
"`P1413R3 <https://wg21.link/P1413R3>`__","LWG","Deprecate ``std::aligned_storage`` and ``std::aligned_union``","February 2022","|Complete| [#note-P1413R3]_",""
|
||||
"`P2255R2 <https://wg21.link/P2255R2>`__","LWG","A type trait to detect reference binding to temporary","February 2022","",""
|
||||
"`P2273R3 <https://wg21.link/P2273R3>`__","LWG","Making ``std::unique_ptr`` constexpr","February 2022","|Complete|","16.0"
|
||||
|
Can't render this file because it has a wrong number of fields in line 2.
|
@ -1,4 +1,4 @@
|
||||
Standard,Name,Assignee,CL,Status
|
||||
C++23,`ranges::to <https://wg21.link/P1206R7>`_,Unassigned,No patch yet,Not started
|
||||
C++23,`ranges::to <https://wg21.link/P1206R7>`_,Konstantin Varlamov,`D142335 <https://reviews.llvm.org/D142335>`_,Complete
|
||||
C++23,`Pipe support for user-defined range adaptors <https://wg21.link/P2387R3>`_,Unassigned,No patch yet,Not started
|
||||
C++23,`Formatting Ranges <https://wg21.link/P2286R8>`_,Mark de Wever,Various,Complete
|
||||
|
|
@ -646,6 +646,7 @@ set(files
|
||||
__ranges/subrange.h
|
||||
__ranges/take_view.h
|
||||
__ranges/take_while_view.h
|
||||
__ranges/to.h
|
||||
__ranges/transform_view.h
|
||||
__ranges/view_interface.h
|
||||
__ranges/views.h
|
||||
|
247
libcxx/include/__ranges/to.h
Normal file
247
libcxx/include/__ranges/to.h
Normal file
@ -0,0 +1,247 @@
|
||||
// -*- C++ -*-
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef _LIBCPP___RANGES_TO_H
|
||||
#define _LIBCPP___RANGES_TO_H
|
||||
|
||||
#include <__algorithm/ranges_copy.h>
|
||||
#include <__concepts/constructible.h>
|
||||
#include <__concepts/convertible_to.h>
|
||||
#include <__concepts/derived_from.h>
|
||||
#include <__concepts/same_as.h>
|
||||
#include <__config>
|
||||
#include <__functional/bind_back.h>
|
||||
#include <__iterator/back_insert_iterator.h>
|
||||
#include <__iterator/insert_iterator.h>
|
||||
#include <__iterator/iterator_traits.h>
|
||||
#include <__ranges/access.h>
|
||||
#include <__ranges/concepts.h>
|
||||
#include <__ranges/from_range.h>
|
||||
#include <__ranges/range_adaptor.h>
|
||||
#include <__ranges/size.h>
|
||||
#include <__ranges/transform_view.h>
|
||||
#include <__type_traits/add_pointer.h>
|
||||
#include <__type_traits/is_const.h>
|
||||
#include <__type_traits/is_volatile.h>
|
||||
#include <__type_traits/type_identity.h>
|
||||
#include <__utility/declval.h>
|
||||
#include <__utility/forward.h>
|
||||
#include <cstddef>
|
||||
|
||||
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
||||
# pragma GCC system_header
|
||||
#endif
|
||||
|
||||
_LIBCPP_BEGIN_NAMESPACE_STD
|
||||
|
||||
#if _LIBCPP_STD_VER >= 23
|
||||
|
||||
namespace ranges {
|
||||
|
||||
// TODO(clang-15): in the Standard, it's a `constexpr bool` variable, not a concept, but constexpr variables don't
|
||||
// short-circuit properly on Clang 15 (fixed in later versions), so use a concept as a workaround.
|
||||
template <class _Container>
|
||||
concept __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 <class _Container, class _Ref>
|
||||
constexpr bool __container_insertable = requires(_Container& __c, _Ref&& __ref) {
|
||||
requires(
|
||||
requires { __c.push_back(std::forward<_Ref>(__ref)); } ||
|
||||
requires { __c.insert(__c.end(), std::forward<_Ref>(__ref)); });
|
||||
};
|
||||
|
||||
template <class _Ref, class _Container>
|
||||
_LIBCPP_HIDE_FROM_ABI 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());
|
||||
}
|
||||
}
|
||||
|
||||
// Note: making this a concept allows short-circuiting the second condition.
|
||||
template <class _Container, class _Range>
|
||||
concept __try_non_recursive_conversion =
|
||||
!input_range<_Container> || convertible_to<range_reference_t<_Range>, range_value_t<_Container>>;
|
||||
|
||||
template <class _Container, class _Range, class... _Args>
|
||||
concept __constructible_from_iter_pair =
|
||||
common_range<_Range> && requires { typename iterator_traits<iterator_t<_Range>>::iterator_category; } &&
|
||||
derived_from<typename iterator_traits<iterator_t<_Range>>::iterator_category, input_iterator_tag> &&
|
||||
constructible_from<_Container, iterator_t<_Range>, sentinel_t<_Range>, _Args...>;
|
||||
|
||||
template <class>
|
||||
concept __always_false = false;
|
||||
|
||||
// `ranges::to` base template -- the `_Container` type is a simple type template parameter.
|
||||
template <class _Container, input_range _Range, class... _Args>
|
||||
requires(!view<_Container>)
|
||||
_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr _Container to(_Range&& __range, _Args&&... __args) {
|
||||
// Mandates: C is a cv-unqualified class type.
|
||||
static_assert(!is_const_v<_Container>, "The target container cannot be const-qualified, please remove the const");
|
||||
static_assert(
|
||||
!is_volatile_v<_Container>, "The target container cannot be volatile-qualified, please remove the volatile");
|
||||
|
||||
// First see if the non-recursive case applies -- the conversion target is either:
|
||||
// - a range with a convertible value type;
|
||||
// - a non-range type which might support being created from the input argument(s) (e.g. an `optional`).
|
||||
if constexpr (__try_non_recursive_conversion<_Container, _Range>) {
|
||||
// Case 1 -- construct directly from the given range.
|
||||
if constexpr (constructible_from<_Container, _Range, _Args...>) {
|
||||
return _Container(std::forward<_Range>(__range), std::forward<_Args>(__args)...);
|
||||
}
|
||||
|
||||
// Case 2 -- construct using the `from_range_t` tagged constructor.
|
||||
else if constexpr (constructible_from<_Container, from_range_t, _Range, _Args...>) {
|
||||
return _Container(from_range, std::forward<_Range>(__range), std::forward<_Args>(__args)...);
|
||||
}
|
||||
|
||||
// Case 3 -- construct from a begin-end iterator pair.
|
||||
else if constexpr (__constructible_from_iter_pair<_Container, _Range, _Args...>) {
|
||||
return _Container(ranges::begin(__range), ranges::end(__range), std::forward<_Args>(__args)...);
|
||||
}
|
||||
|
||||
// Case 4 -- default-construct (or construct from the extra arguments) and insert, reserving the size if possible.
|
||||
else if constexpr (constructible_from<_Container, _Args...> &&
|
||||
__container_insertable<_Container, range_reference_t<_Range>>) {
|
||||
_Container __result(std::forward<_Args>(__args)...);
|
||||
if constexpr (sized_range<_Range> && __reservable_container<_Container>) {
|
||||
__result.reserve(static_cast<range_size_t<_Container>>(ranges::size(__range)));
|
||||
}
|
||||
|
||||
ranges::copy(__range, ranges::__container_inserter<range_reference_t<_Range>>(__result));
|
||||
|
||||
return __result;
|
||||
|
||||
} else {
|
||||
static_assert(__always_false<_Container>, "ranges::to: unable to convert to the given container type.");
|
||||
}
|
||||
|
||||
// Try the recursive case.
|
||||
} else if constexpr (input_range<range_reference_t<_Range>>) {
|
||||
return ranges::to<_Container>(
|
||||
__range | views::transform([](auto&& __elem) {
|
||||
return ranges::to<range_value_t<_Container>>(std::forward<decltype(__elem)>(__elem));
|
||||
}),
|
||||
std::forward<_Args>(__args)...);
|
||||
|
||||
} else {
|
||||
static_assert(__always_false<_Container>, "ranges::to: unable to convert to the given container type.");
|
||||
}
|
||||
}
|
||||
|
||||
template <class _Range>
|
||||
struct __minimal_input_iterator {
|
||||
using iterator_category = input_iterator_tag;
|
||||
using value_type = range_value_t<_Range>;
|
||||
using difference_type = ptrdiff_t;
|
||||
using pointer = add_pointer_t<range_reference_t<_Range>>;
|
||||
using reference = range_reference_t<_Range>;
|
||||
|
||||
reference operator*() const;
|
||||
pointer operator->() const;
|
||||
__minimal_input_iterator& operator++();
|
||||
__minimal_input_iterator operator++(int);
|
||||
bool operator==(const __minimal_input_iterator&) const;
|
||||
};
|
||||
|
||||
// Deduces the full type of the container from the given template template parameter.
|
||||
template <template <class...> class _Container, input_range _Range, class... _Args>
|
||||
struct _Deducer {
|
||||
_LIBCPP_HIDE_FROM_ABI static constexpr auto __deduce_func() {
|
||||
using _InputIter = __minimal_input_iterator<_Range>;
|
||||
|
||||
// Case 1 -- can construct directly from the given range.
|
||||
if constexpr (requires { _Container(std::declval<_Range>(), std::declval<_Args>()...); }) {
|
||||
using _Result = decltype( //
|
||||
_Container(std::declval<_Range>(), std::declval<_Args>()...));
|
||||
return type_identity<_Result>{};
|
||||
|
||||
// Case 2 -- can construct from the given range using the `from_range_t` tagged constructor.
|
||||
} else if constexpr ( //
|
||||
requires { _Container(from_range, std::declval<_Range>(), std::declval<_Args>()...); }) {
|
||||
using _Result = //
|
||||
decltype(_Container(from_range, std::declval<_Range>(), std::declval<_Args>()...));
|
||||
return type_identity<_Result>{};
|
||||
|
||||
// Case 3 -- can construct from a begin-end iterator pair.
|
||||
} else if constexpr ( //
|
||||
requires { _Container(std::declval<_InputIter>(), std::declval<_InputIter>(), std::declval<_Args>()...); }) {
|
||||
using _Result =
|
||||
decltype(_Container(std::declval<_InputIter>(), std::declval<_InputIter>(), std::declval<_Args>()...));
|
||||
return type_identity<_Result>{};
|
||||
|
||||
} else {
|
||||
static_assert(__always_false<_Range>,
|
||||
"ranges::to: unable to deduce the container type from the template template argument.");
|
||||
}
|
||||
}
|
||||
|
||||
using type = typename decltype(__deduce_func())::type;
|
||||
};
|
||||
|
||||
// `ranges::to` specialization -- `_Container` is a template template parameter requiring deduction to figure out the
|
||||
// container element type.
|
||||
template <template <class...> class _Container, input_range _Range, class... _Args>
|
||||
_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr auto to(_Range&& __range, _Args&&... __args) {
|
||||
using _DeduceExpr = typename _Deducer<_Container, _Range, _Args...>::type;
|
||||
return ranges::to<_DeduceExpr>(std::forward<_Range>(__range), std::forward<_Args>(__args)...);
|
||||
}
|
||||
|
||||
// Range adaptor closure object 1 -- wrapping the `ranges::to` version where `_Container` is a simple type template
|
||||
// parameter.
|
||||
template <class _Container, class... _Args>
|
||||
requires(!view<_Container>)
|
||||
_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr auto to(_Args&&... __args) {
|
||||
// Mandates: C is a cv-unqualified class type.
|
||||
static_assert(!is_const_v<_Container>, "The target container cannot be const-qualified, please remove the const");
|
||||
static_assert(
|
||||
!is_volatile_v<_Container>, "The target container cannot be volatile-qualified, please remove the volatile");
|
||||
|
||||
auto __to_func = []<input_range _Range, class... _Tail>(_Range && __range, _Tail && ... __tail)
|
||||
requires requires { //
|
||||
/**/ ranges::to<_Container>(std::forward<_Range>(__range), std::forward<_Tail>(__tail)...);
|
||||
}
|
||||
{
|
||||
return ranges::to<_Container>(std::forward<_Range>(__range), std::forward<_Tail>(__tail)...);
|
||||
};
|
||||
|
||||
return __range_adaptor_closure_t(std::__bind_back(__to_func, std::forward<_Args>(__args)...));
|
||||
}
|
||||
|
||||
// Range adaptor closure object 2 -- wrapping the `ranges::to` version where `_Container` is a template template
|
||||
// parameter.
|
||||
template <template <class...> class _Container, class... _Args>
|
||||
_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr auto to(_Args&&... __args) {
|
||||
// clang-format off
|
||||
auto __to_func = []<input_range _Range, class... _Tail,
|
||||
class _DeducedExpr = typename _Deducer<_Container, _Range, _Tail...>::type>
|
||||
(_Range&& __range, _Tail&& ... __tail)
|
||||
requires requires { //
|
||||
/**/ ranges::to<_DeducedExpr>(std::forward<_Range>(__range), std::forward<_Tail>(__tail)...);
|
||||
}
|
||||
{
|
||||
return ranges::to<_DeducedExpr>(std::forward<_Range>(__range), std::forward<_Tail>(__tail)...);
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
return __range_adaptor_closure_t(std::__bind_back(__to_func, std::forward<_Args>(__args)...));
|
||||
}
|
||||
|
||||
} // namespace ranges
|
||||
|
||||
#endif // _LIBCPP_STD_VER >= 23
|
||||
|
||||
_LIBCPP_END_NAMESPACE_STD
|
||||
|
||||
#endif // _LIBCPP___RANGES_TO_H
|
@ -1718,6 +1718,7 @@ module std_private_ranges_subrange_fwd [system] {
|
||||
}
|
||||
module std_private_ranges_take_view [system] { header "__ranges/take_view.h" }
|
||||
module std_private_ranges_take_while_view [system] { header "__ranges/take_while_view.h" }
|
||||
module std_private_ranges_to [system] { header "__ranges/to.h" }
|
||||
module std_private_ranges_transform_view [system] {
|
||||
header "__ranges/transform_view.h"
|
||||
export std_private_functional_bind_back
|
||||
|
@ -138,6 +138,16 @@ namespace std::ranges {
|
||||
inline constexpr auto values = elements<1>;
|
||||
}
|
||||
|
||||
// [range.utility.conv], range conversions
|
||||
template<class C, input_range R, class... Args> requires (!view<C>)
|
||||
constexpr C to(R&& r, Args&&... args); // Since C++23
|
||||
template<template<class...> class C, input_range R, class... Args>
|
||||
constexpr auto to(R&& r, Args&&... args); // Since C++23
|
||||
template<class C, class... Args> requires (!view<C>)
|
||||
constexpr auto to(Args&&... args); // Since C++23
|
||||
template<template<class...> class C, class... Args>
|
||||
constexpr auto to(Args&&... args); // Since C++23
|
||||
|
||||
// [range.empty], empty view
|
||||
template<class T>
|
||||
requires is_object_v<T>
|
||||
@ -391,6 +401,7 @@ namespace std {
|
||||
#include <__ranges/subrange.h>
|
||||
#include <__ranges/take_view.h>
|
||||
#include <__ranges/take_while_view.h>
|
||||
#include <__ranges/to.h>
|
||||
#include <__ranges/transform_view.h>
|
||||
#include <__ranges/view_interface.h>
|
||||
#include <__ranges/views.h>
|
||||
|
@ -162,7 +162,7 @@ __cpp_lib_ranges_repeat 202207L <ranges>
|
||||
__cpp_lib_ranges_slide 202202L <ranges>
|
||||
__cpp_lib_ranges_starts_ends_with 202106L <algorithm>
|
||||
__cpp_lib_ranges_to_container 202202L <deque> <forward_list> <list>
|
||||
<map> <priority_queue> <queue>
|
||||
<map> <queue> <ranges>
|
||||
<set> <stack> <string>
|
||||
<unordered_map> <unordered_set> <vector>
|
||||
__cpp_lib_ranges_zip 202110L <ranges> <tuple> <utility>
|
||||
@ -440,7 +440,7 @@ __cpp_lib_within_lifetime 202306L <type_traits>
|
||||
# define __cpp_lib_ranges_repeat 202207L
|
||||
// # define __cpp_lib_ranges_slide 202202L
|
||||
// # define __cpp_lib_ranges_starts_ends_with 202106L
|
||||
// # define __cpp_lib_ranges_to_container 202202L
|
||||
# define __cpp_lib_ranges_to_container 202202L
|
||||
// # define __cpp_lib_ranges_zip 202110L
|
||||
// # define __cpp_lib_reference_from_temporary 202202L
|
||||
// # define __cpp_lib_spanstream 202106L
|
||||
|
@ -95,7 +95,7 @@ export namespace std {
|
||||
using std::ranges::borrowed_subrange_t;
|
||||
|
||||
// [range.utility.conv], range conversions
|
||||
// using std::ranges::to;
|
||||
using std::ranges::to;
|
||||
|
||||
// [range.empty], empty view
|
||||
using std::ranges::empty_view;
|
||||
|
@ -0,0 +1,94 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
|
||||
|
||||
// Test that the "mandates" requirements on the given container are checked correctly using `static_assert`.
|
||||
|
||||
#include <ranges>
|
||||
#include <vector>
|
||||
|
||||
template <bool HasDefaultCtr = true, bool HasSingleArgCtr = true,
|
||||
bool HasInsert = true, bool HasInsertWithRightSignature = true,
|
||||
bool HasPushBack = true, bool HasPushBackWithRightSignature = true>
|
||||
struct Container {
|
||||
using value_type = int;
|
||||
|
||||
int* begin() const { return nullptr; }
|
||||
int* end() const { return nullptr; }
|
||||
|
||||
Container()
|
||||
requires HasDefaultCtr = default;
|
||||
|
||||
Container(int)
|
||||
requires HasSingleArgCtr {
|
||||
}
|
||||
|
||||
int* insert(int*, int)
|
||||
requires (HasInsert && HasInsertWithRightSignature) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int* insert()
|
||||
requires (HasInsert && !HasInsertWithRightSignature) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void push_back(int)
|
||||
requires (HasPushBack && HasPushBackWithRightSignature) {
|
||||
}
|
||||
|
||||
void push_back()
|
||||
requires (HasPushBack && !HasPushBackWithRightSignature) {
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
void test() {
|
||||
using R = std::vector<int>;
|
||||
R in = {1, 2, 3};
|
||||
|
||||
// Case 4 -- default-construct (or construct from the extra arguments) and insert.
|
||||
{ // All constraints satisfied.
|
||||
using C = Container<>;
|
||||
(void)std::ranges::to<C>(in);
|
||||
(void)std::ranges::to<C>(in, 1);
|
||||
(void)std::ranges::to<C>(in, 1.0);
|
||||
}
|
||||
|
||||
{ // No default constructor.
|
||||
using C = Container</*HasDefaultCtr=*/false>;
|
||||
(void)std::ranges::to<C>(in); //expected-error-re@*:* {{{{(static_assert|static assertion)}} failed{{.*}}ranges::to: unable to convert to the given container type}}
|
||||
}
|
||||
|
||||
{ // No single-argument constructor.
|
||||
using C = Container</*HasDefaultCtr=*/true, /*HasSingleArgCtr=*/false>;
|
||||
(void)std::ranges::to<C>(in, 1); //expected-error-re@*:* {{{{(static_assert|static assertion)}} failed{{.*}}ranges::to: unable to convert to the given container type}}
|
||||
}
|
||||
|
||||
{ // No `insert` and no `push_back`.
|
||||
using C = Container</*HasDefaultCtr=*/true, /*HasSingleArgCtr=*/true,
|
||||
/*HasInsert=*/false, /*HasInsertWithRightSignature=*/false,
|
||||
/*HasPushBack=*/false, /*HasPushBackWithRightSignature=*/false>;
|
||||
(void)std::ranges::to<C>(in); //expected-error-re@*:* {{{{(static_assert|static assertion)}} failed{{.*}}ranges::to: unable to convert to the given container type}}
|
||||
}
|
||||
|
||||
{ // No `push_back`, `insert` has a wrong signature.
|
||||
using C = Container</*HasDefaultCtr=*/true, /*HasSingleArgCtr=*/true,
|
||||
/*HasInsert=*/true, /*HasInsertWithRightSignature=*/false,
|
||||
/*HasPushBack=*/false, /*HasPushBackWithRightSignature=*/false>;
|
||||
(void)std::ranges::to<C>(in); //expected-error-re@*:* {{{{(static_assert|static assertion)}} failed{{.*}}ranges::to: unable to convert to the given container type}}
|
||||
}
|
||||
|
||||
{ // No `insert`, `push_back` has a wrong signature.
|
||||
using C = Container</*HasDefaultCtr=*/true, /*HasSingleArgCtr=*/true,
|
||||
/*HasInsert=*/false, /*HasInsertWithRightSignature=*/false,
|
||||
/*HasPushBack=*/true, /*HasPushBackWithRightSignature=*/false>;
|
||||
(void)std::ranges::to<C>(in); //expected-error-re@*:* {{{{(static_assert|static assertion)}} failed{{.*}}ranges::to: unable to convert to the given container type}}
|
||||
}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
|
||||
|
||||
// Test the libc++ extension that `std::ranges::to` is marked as [[nodiscard]].
|
||||
|
||||
#include <ranges>
|
||||
#include <vector>
|
||||
|
||||
void test() {
|
||||
using R = std::vector<int>;
|
||||
R in = {1, 2, 3};
|
||||
std::allocator<int> alloc;
|
||||
|
||||
std::ranges::to<R>(in); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||
std::ranges::to<R>(in, alloc); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||
std::ranges::to<std::vector>(in); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||
std::ranges::to<std::vector>(in, alloc); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||
in | std::ranges::to<R>(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||
in | std::ranges::to<R>(alloc); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||
in | std::ranges::to<std::vector>(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||
in | std::ranges::to<std::vector>(alloc); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
|
||||
// ADDITIONAL_COMPILE_FLAGS: -Wno-deprecated-volatile
|
||||
|
||||
// Test that the "mandates" requirements on the given container are checked using `static_assert`.
|
||||
|
||||
#include <ranges>
|
||||
#include <vector>
|
||||
|
||||
void test() {
|
||||
using R = std::vector<int>;
|
||||
R in = {1, 2, 3};
|
||||
|
||||
(void)std::ranges::to<const R>(in); //expected-error-re@*:* {{{{(static_assert|static assertion)}} failed{{.*}}The target container cannot be const-qualified, please remove the const}}
|
||||
(void)(in | std::ranges::to<const R>()); //expected-error-re@*:* {{{{(static_assert|static assertion)}} failed{{.*}}The target container cannot be const-qualified, please remove the const}}
|
||||
(void)std::ranges::to<volatile R>(in); //expected-error-re@*:* {{{{(static_assert|static assertion)}} failed{{.*}}The target container cannot be volatile-qualified, please remove the volatile}}
|
||||
(void)(in | std::ranges::to<volatile R>()); //expected-error-re@*:* {{{{(static_assert|static assertion)}} failed{{.*}}The target container cannot be volatile-qualified, please remove the volatile}}
|
||||
}
|
@ -135,17 +135,11 @@
|
||||
# error "__cpp_lib_nonmember_container_access should have the value 201411L in c++23"
|
||||
# endif
|
||||
|
||||
# if !defined(_LIBCPP_VERSION)
|
||||
# ifndef __cpp_lib_ranges_to_container
|
||||
# error "__cpp_lib_ranges_to_container should be defined in c++23"
|
||||
# endif
|
||||
# if __cpp_lib_ranges_to_container != 202202L
|
||||
# error "__cpp_lib_ranges_to_container should have the value 202202L in c++23"
|
||||
# endif
|
||||
# else // _LIBCPP_VERSION
|
||||
# ifdef __cpp_lib_ranges_to_container
|
||||
# error "__cpp_lib_ranges_to_container should not be defined because it is unimplemented in libc++!"
|
||||
# endif
|
||||
# ifndef __cpp_lib_ranges_to_container
|
||||
# error "__cpp_lib_ranges_to_container should be defined in c++23"
|
||||
# endif
|
||||
# if __cpp_lib_ranges_to_container != 202202L
|
||||
# error "__cpp_lib_ranges_to_container should have the value 202202L in c++23"
|
||||
# endif
|
||||
|
||||
#elif TEST_STD_VER > 23
|
||||
@ -171,17 +165,11 @@
|
||||
# error "__cpp_lib_nonmember_container_access should have the value 201411L in c++26"
|
||||
# endif
|
||||
|
||||
# if !defined(_LIBCPP_VERSION)
|
||||
# ifndef __cpp_lib_ranges_to_container
|
||||
# error "__cpp_lib_ranges_to_container should be defined in c++26"
|
||||
# endif
|
||||
# if __cpp_lib_ranges_to_container != 202202L
|
||||
# error "__cpp_lib_ranges_to_container should have the value 202202L in c++26"
|
||||
# endif
|
||||
# else // _LIBCPP_VERSION
|
||||
# ifdef __cpp_lib_ranges_to_container
|
||||
# error "__cpp_lib_ranges_to_container should not be defined because it is unimplemented in libc++!"
|
||||
# endif
|
||||
# ifndef __cpp_lib_ranges_to_container
|
||||
# error "__cpp_lib_ranges_to_container should be defined in c++26"
|
||||
# endif
|
||||
# if __cpp_lib_ranges_to_container != 202202L
|
||||
# error "__cpp_lib_ranges_to_container should have the value 202202L in c++26"
|
||||
# endif
|
||||
|
||||
#endif // TEST_STD_VER > 23
|
||||
|
@ -192,17 +192,11 @@
|
||||
# error "__cpp_lib_nonmember_container_access should have the value 201411L in c++23"
|
||||
# endif
|
||||
|
||||
# if !defined(_LIBCPP_VERSION)
|
||||
# ifndef __cpp_lib_ranges_to_container
|
||||
# error "__cpp_lib_ranges_to_container should be defined in c++23"
|
||||
# endif
|
||||
# if __cpp_lib_ranges_to_container != 202202L
|
||||
# error "__cpp_lib_ranges_to_container should have the value 202202L in c++23"
|
||||
# endif
|
||||
# else // _LIBCPP_VERSION
|
||||
# ifdef __cpp_lib_ranges_to_container
|
||||
# error "__cpp_lib_ranges_to_container should not be defined because it is unimplemented in libc++!"
|
||||
# endif
|
||||
# ifndef __cpp_lib_ranges_to_container
|
||||
# error "__cpp_lib_ranges_to_container should be defined in c++23"
|
||||
# endif
|
||||
# if __cpp_lib_ranges_to_container != 202202L
|
||||
# error "__cpp_lib_ranges_to_container should have the value 202202L in c++23"
|
||||
# endif
|
||||
|
||||
#elif TEST_STD_VER > 23
|
||||
@ -242,17 +236,11 @@
|
||||
# error "__cpp_lib_nonmember_container_access should have the value 201411L in c++26"
|
||||
# endif
|
||||
|
||||
# if !defined(_LIBCPP_VERSION)
|
||||
# ifndef __cpp_lib_ranges_to_container
|
||||
# error "__cpp_lib_ranges_to_container should be defined in c++26"
|
||||
# endif
|
||||
# if __cpp_lib_ranges_to_container != 202202L
|
||||
# error "__cpp_lib_ranges_to_container should have the value 202202L in c++26"
|
||||
# endif
|
||||
# else // _LIBCPP_VERSION
|
||||
# ifdef __cpp_lib_ranges_to_container
|
||||
# error "__cpp_lib_ranges_to_container should not be defined because it is unimplemented in libc++!"
|
||||
# endif
|
||||
# ifndef __cpp_lib_ranges_to_container
|
||||
# error "__cpp_lib_ranges_to_container should be defined in c++26"
|
||||
# endif
|
||||
# if __cpp_lib_ranges_to_container != 202202L
|
||||
# error "__cpp_lib_ranges_to_container should have the value 202202L in c++26"
|
||||
# endif
|
||||
|
||||
#endif // TEST_STD_VER > 23
|
||||
|
@ -192,17 +192,11 @@
|
||||
# error "__cpp_lib_nonmember_container_access should have the value 201411L in c++23"
|
||||
# endif
|
||||
|
||||
# if !defined(_LIBCPP_VERSION)
|
||||
# ifndef __cpp_lib_ranges_to_container
|
||||
# error "__cpp_lib_ranges_to_container should be defined in c++23"
|
||||
# endif
|
||||
# if __cpp_lib_ranges_to_container != 202202L
|
||||
# error "__cpp_lib_ranges_to_container should have the value 202202L in c++23"
|
||||
# endif
|
||||
# else // _LIBCPP_VERSION
|
||||
# ifdef __cpp_lib_ranges_to_container
|
||||
# error "__cpp_lib_ranges_to_container should not be defined because it is unimplemented in libc++!"
|
||||
# endif
|
||||
# ifndef __cpp_lib_ranges_to_container
|
||||
# error "__cpp_lib_ranges_to_container should be defined in c++23"
|
||||
# endif
|
||||
# if __cpp_lib_ranges_to_container != 202202L
|
||||
# error "__cpp_lib_ranges_to_container should have the value 202202L in c++23"
|
||||
# endif
|
||||
|
||||
#elif TEST_STD_VER > 23
|
||||
@ -242,17 +236,11 @@
|
||||
# error "__cpp_lib_nonmember_container_access should have the value 201411L in c++26"
|
||||
# endif
|
||||
|
||||
# if !defined(_LIBCPP_VERSION)
|
||||
# ifndef __cpp_lib_ranges_to_container
|
||||
# error "__cpp_lib_ranges_to_container should be defined in c++26"
|
||||
# endif
|
||||
# if __cpp_lib_ranges_to_container != 202202L
|
||||
# error "__cpp_lib_ranges_to_container should have the value 202202L in c++26"
|
||||
# endif
|
||||
# else // _LIBCPP_VERSION
|
||||
# ifdef __cpp_lib_ranges_to_container
|
||||
# error "__cpp_lib_ranges_to_container should not be defined because it is unimplemented in libc++!"
|
||||
# endif
|
||||
# ifndef __cpp_lib_ranges_to_container
|
||||
# error "__cpp_lib_ranges_to_container should be defined in c++26"
|
||||
# endif
|
||||
# if __cpp_lib_ranges_to_container != 202202L
|
||||
# error "__cpp_lib_ranges_to_container should have the value 202202L in c++26"
|
||||
# endif
|
||||
|
||||
#endif // TEST_STD_VER > 23
|
||||
|
@ -279,17 +279,11 @@
|
||||
# error "__cpp_lib_nonmember_container_access should have the value 201411L in c++23"
|
||||
# endif
|
||||
|
||||
# if !defined(_LIBCPP_VERSION)
|
||||
# ifndef __cpp_lib_ranges_to_container
|
||||
# error "__cpp_lib_ranges_to_container should be defined in c++23"
|
||||
# endif
|
||||
# if __cpp_lib_ranges_to_container != 202202L
|
||||
# error "__cpp_lib_ranges_to_container should have the value 202202L in c++23"
|
||||
# endif
|
||||
# else // _LIBCPP_VERSION
|
||||
# ifdef __cpp_lib_ranges_to_container
|
||||
# error "__cpp_lib_ranges_to_container should not be defined because it is unimplemented in libc++!"
|
||||
# endif
|
||||
# ifndef __cpp_lib_ranges_to_container
|
||||
# error "__cpp_lib_ranges_to_container should be defined in c++23"
|
||||
# endif
|
||||
# if __cpp_lib_ranges_to_container != 202202L
|
||||
# error "__cpp_lib_ranges_to_container should have the value 202202L in c++23"
|
||||
# endif
|
||||
|
||||
#elif TEST_STD_VER > 23
|
||||
@ -362,17 +356,11 @@
|
||||
# error "__cpp_lib_nonmember_container_access should have the value 201411L in c++26"
|
||||
# endif
|
||||
|
||||
# if !defined(_LIBCPP_VERSION)
|
||||
# ifndef __cpp_lib_ranges_to_container
|
||||
# error "__cpp_lib_ranges_to_container should be defined in c++26"
|
||||
# endif
|
||||
# if __cpp_lib_ranges_to_container != 202202L
|
||||
# error "__cpp_lib_ranges_to_container should have the value 202202L in c++26"
|
||||
# endif
|
||||
# else // _LIBCPP_VERSION
|
||||
# ifdef __cpp_lib_ranges_to_container
|
||||
# error "__cpp_lib_ranges_to_container should not be defined because it is unimplemented in libc++!"
|
||||
# endif
|
||||
# ifndef __cpp_lib_ranges_to_container
|
||||
# error "__cpp_lib_ranges_to_container should be defined in c++26"
|
||||
# endif
|
||||
# if __cpp_lib_ranges_to_container != 202202L
|
||||
# error "__cpp_lib_ranges_to_container should have the value 202202L in c++26"
|
||||
# endif
|
||||
|
||||
#endif // TEST_STD_VER > 23
|
||||
|
@ -72,17 +72,11 @@
|
||||
# error "__cpp_lib_adaptor_iterator_pair_constructor should have the value 202106L in c++23"
|
||||
# endif
|
||||
|
||||
# if !defined(_LIBCPP_VERSION)
|
||||
# ifndef __cpp_lib_ranges_to_container
|
||||
# error "__cpp_lib_ranges_to_container should be defined in c++23"
|
||||
# endif
|
||||
# if __cpp_lib_ranges_to_container != 202202L
|
||||
# error "__cpp_lib_ranges_to_container should have the value 202202L in c++23"
|
||||
# endif
|
||||
# else // _LIBCPP_VERSION
|
||||
# ifdef __cpp_lib_ranges_to_container
|
||||
# error "__cpp_lib_ranges_to_container should not be defined because it is unimplemented in libc++!"
|
||||
# endif
|
||||
# ifndef __cpp_lib_ranges_to_container
|
||||
# error "__cpp_lib_ranges_to_container should be defined in c++23"
|
||||
# endif
|
||||
# if __cpp_lib_ranges_to_container != 202202L
|
||||
# error "__cpp_lib_ranges_to_container should have the value 202202L in c++23"
|
||||
# endif
|
||||
|
||||
#elif TEST_STD_VER > 23
|
||||
@ -94,17 +88,11 @@
|
||||
# error "__cpp_lib_adaptor_iterator_pair_constructor should have the value 202106L in c++26"
|
||||
# endif
|
||||
|
||||
# if !defined(_LIBCPP_VERSION)
|
||||
# ifndef __cpp_lib_ranges_to_container
|
||||
# error "__cpp_lib_ranges_to_container should be defined in c++26"
|
||||
# endif
|
||||
# if __cpp_lib_ranges_to_container != 202202L
|
||||
# error "__cpp_lib_ranges_to_container should have the value 202202L in c++26"
|
||||
# endif
|
||||
# else // _LIBCPP_VERSION
|
||||
# ifdef __cpp_lib_ranges_to_container
|
||||
# error "__cpp_lib_ranges_to_container should not be defined because it is unimplemented in libc++!"
|
||||
# endif
|
||||
# ifndef __cpp_lib_ranges_to_container
|
||||
# error "__cpp_lib_ranges_to_container should be defined in c++26"
|
||||
# endif
|
||||
# if __cpp_lib_ranges_to_container != 202202L
|
||||
# error "__cpp_lib_ranges_to_container should have the value 202202L in c++26"
|
||||
# endif
|
||||
|
||||
#endif // TEST_STD_VER > 23
|
||||
|
@ -15,15 +15,16 @@
|
||||
|
||||
// Test the feature test macros defined by <ranges>
|
||||
|
||||
/* Constant Value
|
||||
__cpp_lib_ranges 202207L [C++20]
|
||||
__cpp_lib_ranges_as_rvalue 202207L [C++23]
|
||||
__cpp_lib_ranges_chunk 202202L [C++23]
|
||||
__cpp_lib_ranges_chunk_by 202202L [C++23]
|
||||
__cpp_lib_ranges_join_with 202202L [C++23]
|
||||
__cpp_lib_ranges_repeat 202207L [C++23]
|
||||
__cpp_lib_ranges_slide 202202L [C++23]
|
||||
__cpp_lib_ranges_zip 202110L [C++23]
|
||||
/* Constant Value
|
||||
__cpp_lib_ranges 202207L [C++20]
|
||||
__cpp_lib_ranges_as_rvalue 202207L [C++23]
|
||||
__cpp_lib_ranges_chunk 202202L [C++23]
|
||||
__cpp_lib_ranges_chunk_by 202202L [C++23]
|
||||
__cpp_lib_ranges_join_with 202202L [C++23]
|
||||
__cpp_lib_ranges_repeat 202207L [C++23]
|
||||
__cpp_lib_ranges_slide 202202L [C++23]
|
||||
__cpp_lib_ranges_to_container 202202L [C++23]
|
||||
__cpp_lib_ranges_zip 202110L [C++23]
|
||||
*/
|
||||
|
||||
#include <ranges>
|
||||
@ -59,6 +60,10 @@
|
||||
# error "__cpp_lib_ranges_slide should not be defined before c++23"
|
||||
# endif
|
||||
|
||||
# ifdef __cpp_lib_ranges_to_container
|
||||
# error "__cpp_lib_ranges_to_container should not be defined before c++23"
|
||||
# endif
|
||||
|
||||
# ifdef __cpp_lib_ranges_zip
|
||||
# error "__cpp_lib_ranges_zip should not be defined before c++23"
|
||||
# endif
|
||||
@ -93,6 +98,10 @@
|
||||
# error "__cpp_lib_ranges_slide should not be defined before c++23"
|
||||
# endif
|
||||
|
||||
# ifdef __cpp_lib_ranges_to_container
|
||||
# error "__cpp_lib_ranges_to_container should not be defined before c++23"
|
||||
# endif
|
||||
|
||||
# ifdef __cpp_lib_ranges_zip
|
||||
# error "__cpp_lib_ranges_zip should not be defined before c++23"
|
||||
# endif
|
||||
@ -127,6 +136,10 @@
|
||||
# error "__cpp_lib_ranges_slide should not be defined before c++23"
|
||||
# endif
|
||||
|
||||
# ifdef __cpp_lib_ranges_to_container
|
||||
# error "__cpp_lib_ranges_to_container should not be defined before c++23"
|
||||
# endif
|
||||
|
||||
# ifdef __cpp_lib_ranges_zip
|
||||
# error "__cpp_lib_ranges_zip should not be defined before c++23"
|
||||
# endif
|
||||
@ -164,6 +177,10 @@
|
||||
# error "__cpp_lib_ranges_slide should not be defined before c++23"
|
||||
# endif
|
||||
|
||||
# ifdef __cpp_lib_ranges_to_container
|
||||
# error "__cpp_lib_ranges_to_container should not be defined before c++23"
|
||||
# endif
|
||||
|
||||
# ifdef __cpp_lib_ranges_zip
|
||||
# error "__cpp_lib_ranges_zip should not be defined before c++23"
|
||||
# endif
|
||||
@ -243,6 +260,13 @@
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# ifndef __cpp_lib_ranges_to_container
|
||||
# error "__cpp_lib_ranges_to_container should be defined in c++23"
|
||||
# endif
|
||||
# if __cpp_lib_ranges_to_container != 202202L
|
||||
# error "__cpp_lib_ranges_to_container should have the value 202202L in c++23"
|
||||
# endif
|
||||
|
||||
# if !defined(_LIBCPP_VERSION)
|
||||
# ifndef __cpp_lib_ranges_zip
|
||||
# error "__cpp_lib_ranges_zip should be defined in c++23"
|
||||
@ -331,6 +355,13 @@
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# ifndef __cpp_lib_ranges_to_container
|
||||
# error "__cpp_lib_ranges_to_container should be defined in c++26"
|
||||
# endif
|
||||
# if __cpp_lib_ranges_to_container != 202202L
|
||||
# error "__cpp_lib_ranges_to_container should have the value 202202L in c++26"
|
||||
# endif
|
||||
|
||||
# if !defined(_LIBCPP_VERSION)
|
||||
# ifndef __cpp_lib_ranges_zip
|
||||
# error "__cpp_lib_ranges_zip should be defined in c++26"
|
||||
|
@ -249,17 +249,11 @@
|
||||
# error "__cpp_lib_nonmember_container_access should have the value 201411L in c++23"
|
||||
# endif
|
||||
|
||||
# if !defined(_LIBCPP_VERSION)
|
||||
# ifndef __cpp_lib_ranges_to_container
|
||||
# error "__cpp_lib_ranges_to_container should be defined in c++23"
|
||||
# endif
|
||||
# if __cpp_lib_ranges_to_container != 202202L
|
||||
# error "__cpp_lib_ranges_to_container should have the value 202202L in c++23"
|
||||
# endif
|
||||
# else // _LIBCPP_VERSION
|
||||
# ifdef __cpp_lib_ranges_to_container
|
||||
# error "__cpp_lib_ranges_to_container should not be defined because it is unimplemented in libc++!"
|
||||
# endif
|
||||
# ifndef __cpp_lib_ranges_to_container
|
||||
# error "__cpp_lib_ranges_to_container should be defined in c++23"
|
||||
# endif
|
||||
# if __cpp_lib_ranges_to_container != 202202L
|
||||
# error "__cpp_lib_ranges_to_container should have the value 202202L in c++23"
|
||||
# endif
|
||||
|
||||
#elif TEST_STD_VER > 23
|
||||
@ -325,17 +319,11 @@
|
||||
# error "__cpp_lib_nonmember_container_access should have the value 201411L in c++26"
|
||||
# endif
|
||||
|
||||
# if !defined(_LIBCPP_VERSION)
|
||||
# ifndef __cpp_lib_ranges_to_container
|
||||
# error "__cpp_lib_ranges_to_container should be defined in c++26"
|
||||
# endif
|
||||
# if __cpp_lib_ranges_to_container != 202202L
|
||||
# error "__cpp_lib_ranges_to_container should have the value 202202L in c++26"
|
||||
# endif
|
||||
# else // _LIBCPP_VERSION
|
||||
# ifdef __cpp_lib_ranges_to_container
|
||||
# error "__cpp_lib_ranges_to_container should not be defined because it is unimplemented in libc++!"
|
||||
# endif
|
||||
# ifndef __cpp_lib_ranges_to_container
|
||||
# error "__cpp_lib_ranges_to_container should be defined in c++26"
|
||||
# endif
|
||||
# if __cpp_lib_ranges_to_container != 202202L
|
||||
# error "__cpp_lib_ranges_to_container should have the value 202202L in c++26"
|
||||
# endif
|
||||
|
||||
#endif // TEST_STD_VER > 23
|
||||
|
@ -72,17 +72,11 @@
|
||||
# error "__cpp_lib_adaptor_iterator_pair_constructor should have the value 202106L in c++23"
|
||||
# endif
|
||||
|
||||
# if !defined(_LIBCPP_VERSION)
|
||||
# ifndef __cpp_lib_ranges_to_container
|
||||
# error "__cpp_lib_ranges_to_container should be defined in c++23"
|
||||
# endif
|
||||
# if __cpp_lib_ranges_to_container != 202202L
|
||||
# error "__cpp_lib_ranges_to_container should have the value 202202L in c++23"
|
||||
# endif
|
||||
# else // _LIBCPP_VERSION
|
||||
# ifdef __cpp_lib_ranges_to_container
|
||||
# error "__cpp_lib_ranges_to_container should not be defined because it is unimplemented in libc++!"
|
||||
# endif
|
||||
# ifndef __cpp_lib_ranges_to_container
|
||||
# error "__cpp_lib_ranges_to_container should be defined in c++23"
|
||||
# endif
|
||||
# if __cpp_lib_ranges_to_container != 202202L
|
||||
# error "__cpp_lib_ranges_to_container should have the value 202202L in c++23"
|
||||
# endif
|
||||
|
||||
#elif TEST_STD_VER > 23
|
||||
@ -94,17 +88,11 @@
|
||||
# error "__cpp_lib_adaptor_iterator_pair_constructor should have the value 202106L in c++26"
|
||||
# endif
|
||||
|
||||
# if !defined(_LIBCPP_VERSION)
|
||||
# ifndef __cpp_lib_ranges_to_container
|
||||
# error "__cpp_lib_ranges_to_container should be defined in c++26"
|
||||
# endif
|
||||
# if __cpp_lib_ranges_to_container != 202202L
|
||||
# error "__cpp_lib_ranges_to_container should have the value 202202L in c++26"
|
||||
# endif
|
||||
# else // _LIBCPP_VERSION
|
||||
# ifdef __cpp_lib_ranges_to_container
|
||||
# error "__cpp_lib_ranges_to_container should not be defined because it is unimplemented in libc++!"
|
||||
# endif
|
||||
# ifndef __cpp_lib_ranges_to_container
|
||||
# error "__cpp_lib_ranges_to_container should be defined in c++26"
|
||||
# endif
|
||||
# if __cpp_lib_ranges_to_container != 202202L
|
||||
# error "__cpp_lib_ranges_to_container should have the value 202202L in c++26"
|
||||
# endif
|
||||
|
||||
#endif // TEST_STD_VER > 23
|
||||
|
@ -322,17 +322,11 @@
|
||||
# error "__cpp_lib_nonmember_container_access should have the value 201411L in c++23"
|
||||
# endif
|
||||
|
||||
# if !defined(_LIBCPP_VERSION)
|
||||
# ifndef __cpp_lib_ranges_to_container
|
||||
# error "__cpp_lib_ranges_to_container should be defined in c++23"
|
||||
# endif
|
||||
# if __cpp_lib_ranges_to_container != 202202L
|
||||
# error "__cpp_lib_ranges_to_container should have the value 202202L in c++23"
|
||||
# endif
|
||||
# else // _LIBCPP_VERSION
|
||||
# ifdef __cpp_lib_ranges_to_container
|
||||
# error "__cpp_lib_ranges_to_container should not be defined because it is unimplemented in libc++!"
|
||||
# endif
|
||||
# ifndef __cpp_lib_ranges_to_container
|
||||
# error "__cpp_lib_ranges_to_container should be defined in c++23"
|
||||
# endif
|
||||
# if __cpp_lib_ranges_to_container != 202202L
|
||||
# error "__cpp_lib_ranges_to_container should have the value 202202L in c++23"
|
||||
# endif
|
||||
|
||||
# ifndef __cpp_lib_starts_ends_with
|
||||
@ -426,17 +420,11 @@
|
||||
# error "__cpp_lib_nonmember_container_access should have the value 201411L in c++26"
|
||||
# endif
|
||||
|
||||
# if !defined(_LIBCPP_VERSION)
|
||||
# ifndef __cpp_lib_ranges_to_container
|
||||
# error "__cpp_lib_ranges_to_container should be defined in c++26"
|
||||
# endif
|
||||
# if __cpp_lib_ranges_to_container != 202202L
|
||||
# error "__cpp_lib_ranges_to_container should have the value 202202L in c++26"
|
||||
# endif
|
||||
# else // _LIBCPP_VERSION
|
||||
# ifdef __cpp_lib_ranges_to_container
|
||||
# error "__cpp_lib_ranges_to_container should not be defined because it is unimplemented in libc++!"
|
||||
# endif
|
||||
# ifndef __cpp_lib_ranges_to_container
|
||||
# error "__cpp_lib_ranges_to_container should be defined in c++26"
|
||||
# endif
|
||||
# if __cpp_lib_ranges_to_container != 202202L
|
||||
# error "__cpp_lib_ranges_to_container should have the value 202202L in c++26"
|
||||
# endif
|
||||
|
||||
# ifndef __cpp_lib_starts_ends_with
|
||||
|
@ -266,17 +266,11 @@
|
||||
# error "__cpp_lib_nonmember_container_access should have the value 201411L in c++23"
|
||||
# endif
|
||||
|
||||
# if !defined(_LIBCPP_VERSION)
|
||||
# ifndef __cpp_lib_ranges_to_container
|
||||
# error "__cpp_lib_ranges_to_container should be defined in c++23"
|
||||
# endif
|
||||
# if __cpp_lib_ranges_to_container != 202202L
|
||||
# error "__cpp_lib_ranges_to_container should have the value 202202L in c++23"
|
||||
# endif
|
||||
# else // _LIBCPP_VERSION
|
||||
# ifdef __cpp_lib_ranges_to_container
|
||||
# error "__cpp_lib_ranges_to_container should not be defined because it is unimplemented in libc++!"
|
||||
# endif
|
||||
# ifndef __cpp_lib_ranges_to_container
|
||||
# error "__cpp_lib_ranges_to_container should be defined in c++23"
|
||||
# endif
|
||||
# if __cpp_lib_ranges_to_container != 202202L
|
||||
# error "__cpp_lib_ranges_to_container should have the value 202202L in c++23"
|
||||
# endif
|
||||
|
||||
# ifndef __cpp_lib_unordered_map_try_emplace
|
||||
@ -349,17 +343,11 @@
|
||||
# error "__cpp_lib_nonmember_container_access should have the value 201411L in c++26"
|
||||
# endif
|
||||
|
||||
# if !defined(_LIBCPP_VERSION)
|
||||
# ifndef __cpp_lib_ranges_to_container
|
||||
# error "__cpp_lib_ranges_to_container should be defined in c++26"
|
||||
# endif
|
||||
# if __cpp_lib_ranges_to_container != 202202L
|
||||
# error "__cpp_lib_ranges_to_container should have the value 202202L in c++26"
|
||||
# endif
|
||||
# else // _LIBCPP_VERSION
|
||||
# ifdef __cpp_lib_ranges_to_container
|
||||
# error "__cpp_lib_ranges_to_container should not be defined because it is unimplemented in libc++!"
|
||||
# endif
|
||||
# ifndef __cpp_lib_ranges_to_container
|
||||
# error "__cpp_lib_ranges_to_container should be defined in c++26"
|
||||
# endif
|
||||
# if __cpp_lib_ranges_to_container != 202202L
|
||||
# error "__cpp_lib_ranges_to_container should have the value 202202L in c++26"
|
||||
# endif
|
||||
|
||||
# ifndef __cpp_lib_unordered_map_try_emplace
|
||||
|
@ -243,17 +243,11 @@
|
||||
# error "__cpp_lib_nonmember_container_access should have the value 201411L in c++23"
|
||||
# endif
|
||||
|
||||
# if !defined(_LIBCPP_VERSION)
|
||||
# ifndef __cpp_lib_ranges_to_container
|
||||
# error "__cpp_lib_ranges_to_container should be defined in c++23"
|
||||
# endif
|
||||
# if __cpp_lib_ranges_to_container != 202202L
|
||||
# error "__cpp_lib_ranges_to_container should have the value 202202L in c++23"
|
||||
# endif
|
||||
# else // _LIBCPP_VERSION
|
||||
# ifdef __cpp_lib_ranges_to_container
|
||||
# error "__cpp_lib_ranges_to_container should not be defined because it is unimplemented in libc++!"
|
||||
# endif
|
||||
# ifndef __cpp_lib_ranges_to_container
|
||||
# error "__cpp_lib_ranges_to_container should be defined in c++23"
|
||||
# endif
|
||||
# if __cpp_lib_ranges_to_container != 202202L
|
||||
# error "__cpp_lib_ranges_to_container should have the value 202202L in c++23"
|
||||
# endif
|
||||
|
||||
#elif TEST_STD_VER > 23
|
||||
@ -319,17 +313,11 @@
|
||||
# error "__cpp_lib_nonmember_container_access should have the value 201411L in c++26"
|
||||
# endif
|
||||
|
||||
# if !defined(_LIBCPP_VERSION)
|
||||
# ifndef __cpp_lib_ranges_to_container
|
||||
# error "__cpp_lib_ranges_to_container should be defined in c++26"
|
||||
# endif
|
||||
# if __cpp_lib_ranges_to_container != 202202L
|
||||
# error "__cpp_lib_ranges_to_container should have the value 202202L in c++26"
|
||||
# endif
|
||||
# else // _LIBCPP_VERSION
|
||||
# ifdef __cpp_lib_ranges_to_container
|
||||
# error "__cpp_lib_ranges_to_container should not be defined because it is unimplemented in libc++!"
|
||||
# endif
|
||||
# ifndef __cpp_lib_ranges_to_container
|
||||
# error "__cpp_lib_ranges_to_container should be defined in c++26"
|
||||
# endif
|
||||
# if __cpp_lib_ranges_to_container != 202202L
|
||||
# error "__cpp_lib_ranges_to_container should have the value 202202L in c++26"
|
||||
# endif
|
||||
|
||||
#endif // TEST_STD_VER > 23
|
||||
|
@ -192,17 +192,11 @@
|
||||
# error "__cpp_lib_nonmember_container_access should have the value 201411L in c++23"
|
||||
# endif
|
||||
|
||||
# if !defined(_LIBCPP_VERSION)
|
||||
# ifndef __cpp_lib_ranges_to_container
|
||||
# error "__cpp_lib_ranges_to_container should be defined in c++23"
|
||||
# endif
|
||||
# if __cpp_lib_ranges_to_container != 202202L
|
||||
# error "__cpp_lib_ranges_to_container should have the value 202202L in c++23"
|
||||
# endif
|
||||
# else // _LIBCPP_VERSION
|
||||
# ifdef __cpp_lib_ranges_to_container
|
||||
# error "__cpp_lib_ranges_to_container should not be defined because it is unimplemented in libc++!"
|
||||
# endif
|
||||
# ifndef __cpp_lib_ranges_to_container
|
||||
# error "__cpp_lib_ranges_to_container should be defined in c++23"
|
||||
# endif
|
||||
# if __cpp_lib_ranges_to_container != 202202L
|
||||
# error "__cpp_lib_ranges_to_container should have the value 202202L in c++23"
|
||||
# endif
|
||||
|
||||
#elif TEST_STD_VER > 23
|
||||
@ -242,17 +236,11 @@
|
||||
# error "__cpp_lib_nonmember_container_access should have the value 201411L in c++26"
|
||||
# endif
|
||||
|
||||
# if !defined(_LIBCPP_VERSION)
|
||||
# ifndef __cpp_lib_ranges_to_container
|
||||
# error "__cpp_lib_ranges_to_container should be defined in c++26"
|
||||
# endif
|
||||
# if __cpp_lib_ranges_to_container != 202202L
|
||||
# error "__cpp_lib_ranges_to_container should have the value 202202L in c++26"
|
||||
# endif
|
||||
# else // _LIBCPP_VERSION
|
||||
# ifdef __cpp_lib_ranges_to_container
|
||||
# error "__cpp_lib_ranges_to_container should not be defined because it is unimplemented in libc++!"
|
||||
# endif
|
||||
# ifndef __cpp_lib_ranges_to_container
|
||||
# error "__cpp_lib_ranges_to_container should be defined in c++26"
|
||||
# endif
|
||||
# if __cpp_lib_ranges_to_container != 202202L
|
||||
# error "__cpp_lib_ranges_to_container should have the value 202202L in c++26"
|
||||
# endif
|
||||
|
||||
#endif // TEST_STD_VER > 23
|
||||
|
@ -5042,17 +5042,11 @@
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# if !defined(_LIBCPP_VERSION)
|
||||
# ifndef __cpp_lib_ranges_to_container
|
||||
# error "__cpp_lib_ranges_to_container should be defined in c++23"
|
||||
# endif
|
||||
# if __cpp_lib_ranges_to_container != 202202L
|
||||
# error "__cpp_lib_ranges_to_container should have the value 202202L in c++23"
|
||||
# endif
|
||||
# else // _LIBCPP_VERSION
|
||||
# ifdef __cpp_lib_ranges_to_container
|
||||
# error "__cpp_lib_ranges_to_container should not be defined because it is unimplemented in libc++!"
|
||||
# endif
|
||||
# ifndef __cpp_lib_ranges_to_container
|
||||
# error "__cpp_lib_ranges_to_container should be defined in c++23"
|
||||
# endif
|
||||
# if __cpp_lib_ranges_to_container != 202202L
|
||||
# error "__cpp_lib_ranges_to_container should have the value 202202L in c++23"
|
||||
# endif
|
||||
|
||||
# if !defined(_LIBCPP_VERSION)
|
||||
@ -6601,17 +6595,11 @@
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# if !defined(_LIBCPP_VERSION)
|
||||
# ifndef __cpp_lib_ranges_to_container
|
||||
# error "__cpp_lib_ranges_to_container should be defined in c++26"
|
||||
# endif
|
||||
# if __cpp_lib_ranges_to_container != 202202L
|
||||
# error "__cpp_lib_ranges_to_container should have the value 202202L in c++26"
|
||||
# endif
|
||||
# else // _LIBCPP_VERSION
|
||||
# ifdef __cpp_lib_ranges_to_container
|
||||
# error "__cpp_lib_ranges_to_container should not be defined because it is unimplemented in libc++!"
|
||||
# endif
|
||||
# ifndef __cpp_lib_ranges_to_container
|
||||
# error "__cpp_lib_ranges_to_container should be defined in c++26"
|
||||
# endif
|
||||
# if __cpp_lib_ranges_to_container != 202202L
|
||||
# error "__cpp_lib_ranges_to_container should have the value 202202L in c++26"
|
||||
# endif
|
||||
|
||||
# if !defined(_LIBCPP_VERSION)
|
||||
|
@ -0,0 +1,144 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef RANGES_RANGE_UTILITY_RANGE_UTILITY_CONV_CONTAINER_H
|
||||
#define RANGES_RANGE_UTILITY_RANGE_UTILITY_CONV_CONTAINER_H
|
||||
|
||||
#include <algorithm>
|
||||
#include <concepts>
|
||||
#include <cstddef>
|
||||
|
||||
enum class CtrChoice { Invalid, DefaultCtrAndInsert, BeginEndPair, FromRangeT, DirectCtr };
|
||||
|
||||
enum class InserterChoice { Invalid, Insert, PushBack };
|
||||
|
||||
// Allows checking that `ranges::to` correctly follows the order of priority of different constructors -- e.g., if
|
||||
// 3 constructors are available, the `from_range_t` constructor is chosen in favor of the constructor taking two
|
||||
// iterators, etc.
|
||||
template <class ElementType, CtrChoice Rank, InserterChoice Inserter = InserterChoice::Insert, bool CanReserve = false>
|
||||
struct Container {
|
||||
CtrChoice ctr_choice = CtrChoice::Invalid;
|
||||
InserterChoice inserter_choice = InserterChoice::Invalid;
|
||||
bool called_reserve = false;
|
||||
|
||||
int extra_arg1 = 0;
|
||||
char extra_arg2 = 0;
|
||||
|
||||
using value_type = ElementType;
|
||||
static constexpr int Capacity = 8;
|
||||
int size_ = 0;
|
||||
ElementType buffer_[Capacity] = {};
|
||||
|
||||
// Case 1 -- construct directly from the range.
|
||||
|
||||
constexpr explicit Container(std::ranges::input_range auto&& in)
|
||||
requires(Rank >= CtrChoice::DirectCtr)
|
||||
: ctr_choice(CtrChoice::DirectCtr), size_(std::ranges::size(in)) {
|
||||
std::ranges::copy(in, begin());
|
||||
}
|
||||
|
||||
// Check that `ranges::to` can also pass extra parameters.
|
||||
constexpr explicit Container(std::ranges::input_range auto&& in, int arg1, char arg2)
|
||||
requires(Rank >= CtrChoice::DirectCtr)
|
||||
: Container(in) {
|
||||
extra_arg1 = arg1;
|
||||
extra_arg2 = arg2;
|
||||
}
|
||||
|
||||
// Case 2 -- use `from_range_t` constructor.
|
||||
|
||||
constexpr Container(std::from_range_t, std::ranges::input_range auto&& in)
|
||||
requires(Rank >= CtrChoice::FromRangeT)
|
||||
: ctr_choice(CtrChoice::FromRangeT), size_(std::ranges::size(in)) {
|
||||
std::ranges::copy(in, begin());
|
||||
}
|
||||
|
||||
constexpr Container(std::from_range_t, std::ranges::input_range auto&& in, int arg1, char arg2)
|
||||
requires(Rank >= CtrChoice::FromRangeT)
|
||||
: Container(std::from_range, in) {
|
||||
extra_arg1 = arg1;
|
||||
extra_arg2 = arg2;
|
||||
}
|
||||
|
||||
// Case 3 -- use begin-end pair.
|
||||
|
||||
template <class Iter>
|
||||
constexpr Container(Iter b, Iter e)
|
||||
requires(Rank >= CtrChoice::BeginEndPair)
|
||||
: ctr_choice(CtrChoice::BeginEndPair), size_(e - b) {
|
||||
std::ranges::copy(b, e, begin());
|
||||
}
|
||||
|
||||
template <class Iter>
|
||||
constexpr Container(Iter b, Iter e, int arg1, char arg2)
|
||||
requires(Rank >= CtrChoice::BeginEndPair)
|
||||
: Container(b, e) {
|
||||
extra_arg1 = arg1;
|
||||
extra_arg2 = arg2;
|
||||
}
|
||||
|
||||
// Case 4 -- default-construct and insert, reserving the size if possible.
|
||||
|
||||
constexpr Container()
|
||||
requires(Rank >= CtrChoice::DefaultCtrAndInsert)
|
||||
: ctr_choice(CtrChoice::DefaultCtrAndInsert) {}
|
||||
|
||||
constexpr Container(int arg1, char arg2)
|
||||
requires(Rank >= CtrChoice::DefaultCtrAndInsert)
|
||||
: ctr_choice(CtrChoice::DefaultCtrAndInsert), extra_arg1(arg1), extra_arg2(arg2) {}
|
||||
|
||||
constexpr ElementType* begin() { return buffer_; }
|
||||
constexpr ElementType* end() { return buffer_ + size_; }
|
||||
constexpr std::size_t size() const { return size_; }
|
||||
|
||||
template <class T>
|
||||
constexpr void push_back(T val)
|
||||
requires(Inserter >= InserterChoice::PushBack)
|
||||
{
|
||||
inserter_choice = InserterChoice::PushBack;
|
||||
buffer_[size_] = val;
|
||||
++size_;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
constexpr ElementType* insert(ElementType* where, T val)
|
||||
requires(Inserter >= InserterChoice::Insert)
|
||||
{
|
||||
assert(size() + 1 <= Capacity);
|
||||
|
||||
inserter_choice = InserterChoice::Insert;
|
||||
|
||||
std::shift_right(where, end(), 1);
|
||||
*where = val;
|
||||
++size_;
|
||||
|
||||
return where;
|
||||
}
|
||||
|
||||
constexpr void reserve(size_t)
|
||||
requires CanReserve
|
||||
{
|
||||
called_reserve = true;
|
||||
}
|
||||
|
||||
constexpr std::size_t capacity() const
|
||||
requires CanReserve
|
||||
{
|
||||
return Capacity;
|
||||
}
|
||||
|
||||
constexpr std::size_t max_size() const
|
||||
requires CanReserve
|
||||
{
|
||||
return Capacity;
|
||||
}
|
||||
|
||||
friend constexpr bool operator==(const Container&, const Container&) = default;
|
||||
};
|
||||
|
||||
#endif // RANGES_RANGE_UTILITY_RANGE_UTILITY_CONV_CONTAINER_H
|
@ -0,0 +1,574 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
|
||||
|
||||
// template<class C, input_range R, class... Args> requires (!view<C>)
|
||||
// constexpr C to(R&& r, Args&&... args); // Since C++23
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <vector>
|
||||
#include "container.h"
|
||||
#include "test_iterators.h"
|
||||
#include "test_range.h"
|
||||
|
||||
template <class Container, class Range, class... Args>
|
||||
concept HasTo = requires (Range&& range, Args ...args) {
|
||||
std::ranges::to<Container>(std::forward<Range>(range), std::forward<Args>(args)...);
|
||||
};
|
||||
|
||||
struct InputRange {
|
||||
int x = 0;
|
||||
constexpr cpp20_input_iterator<int*> begin() {
|
||||
return cpp20_input_iterator<int*>(&x);
|
||||
}
|
||||
constexpr sentinel_wrapper<cpp20_input_iterator<int*>> end() {
|
||||
return sentinel_wrapper<cpp20_input_iterator<int*>>(begin());
|
||||
}
|
||||
};
|
||||
static_assert(std::ranges::input_range<InputRange>);
|
||||
|
||||
struct common_cpp20_input_iterator {
|
||||
using value_type = int;
|
||||
using difference_type = long long;
|
||||
using iterator_concept = std::input_iterator_tag;
|
||||
// Deliberately not defining `iterator_category` to make sure this class satisfies the `input_iterator` concept but
|
||||
// would fail `derived_from<iterator_category, input_iterator_tag>`.
|
||||
|
||||
int x = 0;
|
||||
|
||||
// Copyable so that it can be used as a sentinel against itself.
|
||||
constexpr decltype(auto) operator*() const { return x; }
|
||||
constexpr common_cpp20_input_iterator& operator++() { return *this; }
|
||||
constexpr void operator++(int) {}
|
||||
constexpr friend bool operator==(common_cpp20_input_iterator, common_cpp20_input_iterator) { return true; }
|
||||
};
|
||||
static_assert(std::input_iterator<common_cpp20_input_iterator>);
|
||||
static_assert(std::sentinel_for<common_cpp20_input_iterator, common_cpp20_input_iterator>);
|
||||
template <class T>
|
||||
concept HasIteratorCategory = requires {
|
||||
typename std::iterator_traits<T>::iterator_category;
|
||||
};
|
||||
static_assert(!HasIteratorCategory<common_cpp20_input_iterator>);
|
||||
|
||||
struct CommonInputRange {
|
||||
int x = 0;
|
||||
constexpr common_cpp20_input_iterator begin() { return {}; }
|
||||
constexpr common_cpp20_input_iterator end() { return begin(); }
|
||||
};
|
||||
static_assert(std::ranges::input_range<CommonInputRange>);
|
||||
static_assert(std::ranges::common_range<CommonInputRange>);
|
||||
|
||||
struct CommonRange {
|
||||
int x = 0;
|
||||
constexpr forward_iterator<int*> begin() {
|
||||
return forward_iterator<int*>(&x);
|
||||
}
|
||||
constexpr forward_iterator<int*> end() {
|
||||
return begin();
|
||||
}
|
||||
};
|
||||
static_assert(std::ranges::input_range<CommonRange>);
|
||||
static_assert(std::ranges::common_range<CommonRange>);
|
||||
|
||||
struct NonCommonRange {
|
||||
int x = 0;
|
||||
constexpr forward_iterator<int*> begin() {
|
||||
return forward_iterator<int*>(&x);
|
||||
}
|
||||
constexpr sentinel_wrapper<forward_iterator<int*>> end() {
|
||||
return sentinel_wrapper<forward_iterator<int*>>(begin());
|
||||
}
|
||||
};
|
||||
static_assert(std::ranges::input_range<NonCommonRange>);
|
||||
static_assert(!std::ranges::common_range<NonCommonRange>);
|
||||
static_assert(std::derived_from<
|
||||
typename std::iterator_traits<std::ranges::iterator_t<NonCommonRange>>::iterator_category,
|
||||
std::input_iterator_tag>);
|
||||
|
||||
using ContainerT = int;
|
||||
static_assert(!std::ranges::view<ContainerT>);
|
||||
static_assert(HasTo<ContainerT, InputRange>);
|
||||
static_assert(!HasTo<test_view<forward_iterator>, InputRange>);
|
||||
|
||||
// Note: it's not possible to check the `input_range` constraint because if it's not satisfied, the pipe adaptor
|
||||
// overload hijacks the call (it takes unconstrained variadic arguments).
|
||||
|
||||
// Check the exact constraints for each one of the cases inside `ranges::to`.
|
||||
|
||||
struct Empty {};
|
||||
|
||||
struct Fallback {
|
||||
using value_type = int;
|
||||
|
||||
CtrChoice ctr_choice = CtrChoice::Invalid;
|
||||
int x = 0;
|
||||
|
||||
constexpr Fallback() : ctr_choice(CtrChoice::DefaultCtrAndInsert) {}
|
||||
constexpr Fallback(Empty) : ctr_choice(CtrChoice::DefaultCtrAndInsert) {}
|
||||
|
||||
constexpr void push_back(value_type) {}
|
||||
constexpr value_type* begin() { return &x; }
|
||||
constexpr value_type* end() { return &x; }
|
||||
};
|
||||
|
||||
struct CtrDirectOrFallback : Fallback {
|
||||
using Fallback::Fallback;
|
||||
constexpr CtrDirectOrFallback(InputRange&&, int = 0) { ctr_choice = CtrChoice::DirectCtr; }
|
||||
};
|
||||
|
||||
struct CtrFromRangeTOrFallback : Fallback {
|
||||
using Fallback::Fallback;
|
||||
constexpr CtrFromRangeTOrFallback(std::from_range_t, InputRange&&, int = 0) { ctr_choice = CtrChoice::FromRangeT; }
|
||||
};
|
||||
|
||||
struct CtrBeginEndPairOrFallback : Fallback {
|
||||
using Fallback::Fallback;
|
||||
template <class Iter>
|
||||
constexpr CtrBeginEndPairOrFallback(Iter, Iter, int = 0) { ctr_choice = CtrChoice::BeginEndPair; }
|
||||
};
|
||||
|
||||
template <bool HasSize>
|
||||
struct MaybeSizedRange {
|
||||
int x = 0;
|
||||
constexpr forward_iterator<int*> begin() { return forward_iterator<int*>(&x); }
|
||||
constexpr forward_iterator<int*> end() { return begin(); }
|
||||
|
||||
constexpr std::size_t size() const
|
||||
requires HasSize {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
static_assert(std::ranges::sized_range<MaybeSizedRange<true>>);
|
||||
static_assert(!std::ranges::sized_range<MaybeSizedRange<false>>);
|
||||
|
||||
template <bool HasCapacity = true, bool CapacityReturnsSizeT = true,
|
||||
bool HasMaxSize = true, bool MaxSizeReturnsSizeT = true>
|
||||
struct Reservable : Fallback {
|
||||
bool reserve_called = false;
|
||||
|
||||
using Fallback::Fallback;
|
||||
|
||||
constexpr std::size_t capacity() const
|
||||
requires (HasCapacity && CapacityReturnsSizeT) {
|
||||
return 0;
|
||||
}
|
||||
constexpr int capacity() const
|
||||
requires (HasCapacity && !CapacityReturnsSizeT) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
constexpr std::size_t max_size() const
|
||||
requires (HasMaxSize && MaxSizeReturnsSizeT) {
|
||||
return 0;
|
||||
}
|
||||
constexpr int max_size() const
|
||||
requires (HasMaxSize && !MaxSizeReturnsSizeT) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
constexpr void reserve(std::size_t) {
|
||||
reserve_called = true;
|
||||
}
|
||||
};
|
||||
static_assert(std::ranges::__reservable_container<Reservable<>>);
|
||||
|
||||
constexpr void test_constraints() {
|
||||
{ // Case 1 -- construct directly from the range.
|
||||
{ // (range)
|
||||
auto result = std::ranges::to<CtrDirectOrFallback>(InputRange());
|
||||
assert(result.ctr_choice == CtrChoice::DirectCtr);
|
||||
}
|
||||
|
||||
{ // (range, arg)
|
||||
auto result = std::ranges::to<CtrDirectOrFallback>(InputRange(), 1);
|
||||
assert(result.ctr_choice == CtrChoice::DirectCtr);
|
||||
}
|
||||
|
||||
{ // (range, convertible-to-arg)
|
||||
auto result = std::ranges::to<CtrDirectOrFallback>(InputRange(), 1.0);
|
||||
assert(result.ctr_choice == CtrChoice::DirectCtr);
|
||||
}
|
||||
|
||||
{ // (range, BAD_arg)
|
||||
auto result = std::ranges::to<CtrDirectOrFallback>(InputRange(), Empty());
|
||||
assert(result.ctr_choice == CtrChoice::DefaultCtrAndInsert);
|
||||
}
|
||||
}
|
||||
|
||||
{ // Case 2 -- construct using the `from_range_t` tagged constructor.
|
||||
{ // (range)
|
||||
auto result = std::ranges::to<CtrFromRangeTOrFallback>(InputRange());
|
||||
assert(result.ctr_choice == CtrChoice::FromRangeT);
|
||||
}
|
||||
|
||||
{ // (range, arg)
|
||||
auto result = std::ranges::to<CtrFromRangeTOrFallback>(InputRange(), 1);
|
||||
assert(result.ctr_choice == CtrChoice::FromRangeT);
|
||||
}
|
||||
|
||||
{ // (range, convertible-to-arg)
|
||||
auto result = std::ranges::to<CtrFromRangeTOrFallback>(InputRange(), 1.0);
|
||||
assert(result.ctr_choice == CtrChoice::FromRangeT);
|
||||
}
|
||||
|
||||
{ // (range, BAD_arg)
|
||||
auto result = std::ranges::to<CtrFromRangeTOrFallback>(InputRange(), Empty());
|
||||
assert(result.ctr_choice == CtrChoice::DefaultCtrAndInsert);
|
||||
}
|
||||
}
|
||||
|
||||
{ // Case 3 -- construct from a begin-end iterator pair.
|
||||
{ // (range)
|
||||
auto result = std::ranges::to<CtrBeginEndPairOrFallback>(CommonRange());
|
||||
assert(result.ctr_choice == CtrChoice::BeginEndPair);
|
||||
}
|
||||
|
||||
{ // (range, arg)
|
||||
auto result = std::ranges::to<CtrBeginEndPairOrFallback>(CommonRange(), 1);
|
||||
assert(result.ctr_choice == CtrChoice::BeginEndPair);
|
||||
}
|
||||
|
||||
{ // (range, convertible-to-arg)
|
||||
auto result = std::ranges::to<CtrBeginEndPairOrFallback>(CommonRange(), 1.0);
|
||||
assert(result.ctr_choice == CtrChoice::BeginEndPair);
|
||||
}
|
||||
|
||||
{ // (BAD_range) -- not a common range.
|
||||
auto result = std::ranges::to<CtrBeginEndPairOrFallback>(NonCommonRange());
|
||||
assert(result.ctr_choice == CtrChoice::DefaultCtrAndInsert);
|
||||
}
|
||||
|
||||
{ // (BAD_range) -- iterator type not derived from `input_iterator_tag`.
|
||||
auto result = std::ranges::to<CtrBeginEndPairOrFallback>(CommonInputRange());
|
||||
assert(result.ctr_choice == CtrChoice::DefaultCtrAndInsert);
|
||||
}
|
||||
|
||||
{ // (range, BAD_arg)
|
||||
auto result = std::ranges::to<CtrBeginEndPairOrFallback>(CommonRange(), Empty());
|
||||
assert(result.ctr_choice == CtrChoice::DefaultCtrAndInsert);
|
||||
}
|
||||
}
|
||||
|
||||
{ // Case 4 -- default-construct (or construct from the extra arguments) and insert, reserving the size if possible.
|
||||
// Note: it's not possible to check the constraints on the default constructor using this approach because there is
|
||||
// nothing to fall back to -- the call will result in a hard error.
|
||||
// However, it's possible to check the constraints on reserving the capacity.
|
||||
|
||||
{ // All constraints satisfied.
|
||||
using C = Reservable<>;
|
||||
auto result = std::ranges::to<C>(MaybeSizedRange<true>());
|
||||
assert(result.reserve_called);
|
||||
}
|
||||
|
||||
{ // !sized_range
|
||||
using C = Reservable<>;
|
||||
auto result = std::ranges::to<C>(MaybeSizedRange<false>());
|
||||
assert(!result.reserve_called);
|
||||
}
|
||||
|
||||
{ // Missing `capacity`.
|
||||
using C = Reservable</*HasCapacity=*/false>;
|
||||
auto result = std::ranges::to<C>(MaybeSizedRange<true>());
|
||||
assert(!result.reserve_called);
|
||||
}
|
||||
|
||||
{ // `capacity` doesn't return `size_type`.
|
||||
using C = Reservable</*HasCapacity=*/true, /*CapacityReturnsSizeT=*/false>;
|
||||
auto result = std::ranges::to<C>(MaybeSizedRange<true>());
|
||||
assert(!result.reserve_called);
|
||||
}
|
||||
|
||||
{ // Missing `max_size`.
|
||||
using C = Reservable</*HasCapacity=*/true, /*CapacityReturnsSizeT=*/true, /*HasMaxSize=*/false>;
|
||||
auto result = std::ranges::to<C>(MaybeSizedRange<true>());
|
||||
assert(!result.reserve_called);
|
||||
}
|
||||
|
||||
{ // `max_size` doesn't return `size_type`.
|
||||
using C = Reservable<
|
||||
/*HasCapacity=*/true, /*CapacityReturnsSizeT=*/true, /*HasMaxSize=*/true, /*MaxSizeReturnsSizeT=*/false>;
|
||||
auto result = std::ranges::to<C>(MaybeSizedRange<true>());
|
||||
assert(!result.reserve_called);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
constexpr void test_ctr_choice_order() {
|
||||
std::array in = {1, 2, 3, 4, 5};
|
||||
int arg1 = 42;
|
||||
char arg2 = 'a';
|
||||
|
||||
{ // Case 1 -- construct directly from the given range.
|
||||
{
|
||||
using C = Container<int, CtrChoice::DirectCtr>;
|
||||
std::same_as<C> decltype(auto) result = std::ranges::to<C>(in);
|
||||
|
||||
assert(result.ctr_choice == CtrChoice::DirectCtr);
|
||||
assert(std::ranges::equal(result, in));
|
||||
assert((in | std::ranges::to<C>()) == result);
|
||||
auto closure = std::ranges::to<C>();
|
||||
assert((in | closure) == result);
|
||||
}
|
||||
|
||||
{ // Extra arguments.
|
||||
using C = Container<int, CtrChoice::DirectCtr>;
|
||||
std::same_as<C> decltype(auto) result = std::ranges::to<C>(in, arg1, arg2);
|
||||
|
||||
assert(result.ctr_choice == CtrChoice::DirectCtr);
|
||||
assert(std::ranges::equal(result, in));
|
||||
assert(result.extra_arg1 == arg1);
|
||||
assert(result.extra_arg2 == arg2);
|
||||
assert((in | std::ranges::to<C>(arg1, arg2)) == result);
|
||||
auto closure = std::ranges::to<C>(arg1, arg2);
|
||||
assert((in | closure) == result);
|
||||
}
|
||||
}
|
||||
|
||||
{ // Case 2 -- construct using the `from_range_t` tag.
|
||||
{
|
||||
using C = Container<int, CtrChoice::FromRangeT>;
|
||||
std::same_as<C> decltype(auto) result = std::ranges::to<C>(in);
|
||||
|
||||
assert(result.ctr_choice == CtrChoice::FromRangeT);
|
||||
assert(std::ranges::equal(result, in));
|
||||
assert((in | std::ranges::to<C>()) == result);
|
||||
auto closure = std::ranges::to<C>();
|
||||
assert((in | closure) == result);
|
||||
}
|
||||
|
||||
{ // Extra arguments.
|
||||
using C = Container<int, CtrChoice::FromRangeT>;
|
||||
std::same_as<C> decltype(auto) result = std::ranges::to<C>(in, arg1, arg2);
|
||||
|
||||
assert(result.ctr_choice == CtrChoice::FromRangeT);
|
||||
assert(std::ranges::equal(result, in));
|
||||
assert(result.extra_arg1 == arg1);
|
||||
assert(result.extra_arg2 == arg2);
|
||||
assert((in | std::ranges::to<C>(arg1, arg2)) == result);
|
||||
auto closure = std::ranges::to<C>(arg1, arg2);
|
||||
assert((in | closure) == result);
|
||||
}
|
||||
}
|
||||
|
||||
{ // Case 3 -- construct from a begin-end pair.
|
||||
{
|
||||
using C = Container<int, CtrChoice::BeginEndPair>;
|
||||
std::same_as<C> decltype(auto) result = std::ranges::to<C>(in);
|
||||
|
||||
assert(result.ctr_choice == CtrChoice::BeginEndPair);
|
||||
assert(std::ranges::equal(result, in));
|
||||
assert((in | std::ranges::to<C>()) == result);
|
||||
auto closure = std::ranges::to<C>();
|
||||
assert((in | closure) == result);
|
||||
}
|
||||
|
||||
{ // Extra arguments.
|
||||
using C = Container<int, CtrChoice::BeginEndPair>;
|
||||
std::same_as<C> decltype(auto) result = std::ranges::to<C>(in, arg1, arg2);
|
||||
|
||||
assert(result.ctr_choice == CtrChoice::BeginEndPair);
|
||||
assert(std::ranges::equal(result, in));
|
||||
assert(result.extra_arg1 == arg1);
|
||||
assert(result.extra_arg2 == arg2);
|
||||
assert((in | std::ranges::to<C>(arg1, arg2)) == result);
|
||||
auto closure = std::ranges::to<C>(arg1, arg2);
|
||||
assert((in | closure) == result);
|
||||
}
|
||||
}
|
||||
|
||||
{ // Case 4 -- default-construct then insert elements.
|
||||
{
|
||||
using C = Container<int, CtrChoice::DefaultCtrAndInsert, InserterChoice::Insert, /*CanReserve=*/false>;
|
||||
std::same_as<C> decltype(auto) result = std::ranges::to<C>(in);
|
||||
|
||||
assert(result.ctr_choice == CtrChoice::DefaultCtrAndInsert);
|
||||
assert(result.inserter_choice == InserterChoice::Insert);
|
||||
assert(std::ranges::equal(result, in));
|
||||
assert(!result.called_reserve);
|
||||
assert((in | std::ranges::to<C>()) == result);
|
||||
auto closure = std::ranges::to<C>();
|
||||
assert((in | closure) == result);
|
||||
}
|
||||
|
||||
{
|
||||
using C = Container<int, CtrChoice::DefaultCtrAndInsert, InserterChoice::Insert, /*CanReserve=*/true>;
|
||||
std::same_as<C> decltype(auto) result = std::ranges::to<C>(in);
|
||||
|
||||
assert(result.ctr_choice == CtrChoice::DefaultCtrAndInsert);
|
||||
assert(result.inserter_choice == InserterChoice::Insert);
|
||||
assert(std::ranges::equal(result, in));
|
||||
assert(result.called_reserve);
|
||||
assert((in | std::ranges::to<C>()) == result);
|
||||
auto closure = std::ranges::to<C>();
|
||||
assert((in | closure) == result);
|
||||
}
|
||||
|
||||
{
|
||||
using C = Container<int, CtrChoice::DefaultCtrAndInsert, InserterChoice::PushBack, /*CanReserve=*/false>;
|
||||
std::same_as<C> decltype(auto) result = std::ranges::to<C>(in);
|
||||
|
||||
assert(result.ctr_choice == CtrChoice::DefaultCtrAndInsert);
|
||||
assert(result.inserter_choice == InserterChoice::PushBack);
|
||||
assert(std::ranges::equal(result, in));
|
||||
assert(!result.called_reserve);
|
||||
assert((in | std::ranges::to<C>()) == result);
|
||||
auto closure = std::ranges::to<C>();
|
||||
assert((in | closure) == result);
|
||||
}
|
||||
|
||||
{
|
||||
using C = Container<int, CtrChoice::DefaultCtrAndInsert, InserterChoice::PushBack, /*CanReserve=*/true>;
|
||||
std::same_as<C> decltype(auto) result = std::ranges::to<C>(in);
|
||||
|
||||
assert(result.ctr_choice == CtrChoice::DefaultCtrAndInsert);
|
||||
assert(result.inserter_choice == InserterChoice::PushBack);
|
||||
assert(std::ranges::equal(result, in));
|
||||
assert(result.called_reserve);
|
||||
assert((in | std::ranges::to<C>()) == result);
|
||||
auto closure = std::ranges::to<C>();
|
||||
assert((in | closure) == result);
|
||||
}
|
||||
|
||||
{ // Extra arguments.
|
||||
using C = Container<int, CtrChoice::DefaultCtrAndInsert, InserterChoice::Insert, /*CanReserve=*/false>;
|
||||
std::same_as<C> decltype(auto) result = std::ranges::to<C>(in, arg1, arg2);
|
||||
|
||||
assert(result.ctr_choice == CtrChoice::DefaultCtrAndInsert);
|
||||
assert(result.inserter_choice == InserterChoice::Insert);
|
||||
assert(std::ranges::equal(result, in));
|
||||
assert(!result.called_reserve);
|
||||
assert(result.extra_arg1 == arg1);
|
||||
assert(result.extra_arg2 == arg2);
|
||||
assert((in | std::ranges::to<C>(arg1, arg2)) == result);
|
||||
auto closure = std::ranges::to<C>(arg1, arg2);
|
||||
assert((in | closure) == result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <CtrChoice Rank>
|
||||
struct NotARange {
|
||||
using value_type = int;
|
||||
|
||||
constexpr NotARange(std::ranges::input_range auto&&)
|
||||
requires (Rank >= CtrChoice::DirectCtr)
|
||||
{}
|
||||
|
||||
constexpr NotARange(std::from_range_t, std::ranges::input_range auto&&)
|
||||
requires (Rank >= CtrChoice::FromRangeT)
|
||||
{}
|
||||
|
||||
template <class Iter>
|
||||
constexpr NotARange(Iter, Iter)
|
||||
requires (Rank >= CtrChoice::BeginEndPair)
|
||||
{}
|
||||
|
||||
constexpr NotARange()
|
||||
requires (Rank >= CtrChoice::DefaultCtrAndInsert)
|
||||
= default;
|
||||
|
||||
constexpr void push_back(int) {}
|
||||
};
|
||||
|
||||
static_assert(!std::ranges::range<NotARange<CtrChoice::DirectCtr>>);
|
||||
|
||||
constexpr void test_lwg_3785() {
|
||||
// Test LWG 3785 ("`ranges::to` is over-constrained on the destination type being a range") -- make sure it's possible
|
||||
// to convert the given input range to a non-range type.
|
||||
std::array in = {1, 2, 3, 4, 5};
|
||||
|
||||
{
|
||||
using C = NotARange<CtrChoice::DirectCtr>;
|
||||
[[maybe_unused]] std::same_as<C> decltype(auto) result = std::ranges::to<C>(in);
|
||||
}
|
||||
|
||||
{
|
||||
using C = NotARange<CtrChoice::FromRangeT>;
|
||||
[[maybe_unused]] std::same_as<C> decltype(auto) result = std::ranges::to<C>(in);
|
||||
}
|
||||
|
||||
{
|
||||
using C = NotARange<CtrChoice::BeginEndPair>;
|
||||
[[maybe_unused]] std::same_as<C> decltype(auto) result = std::ranges::to<C>(in);
|
||||
}
|
||||
|
||||
{
|
||||
using C = NotARange<CtrChoice::DefaultCtrAndInsert>;
|
||||
[[maybe_unused]] std::same_as<C> decltype(auto) result = std::ranges::to<C>(in);
|
||||
}
|
||||
}
|
||||
|
||||
constexpr void test_recursive() {
|
||||
using C1 = Container<int, CtrChoice::DirectCtr>;
|
||||
using C2 = Container<C1, CtrChoice::FromRangeT>;
|
||||
using C3 = Container<C2, CtrChoice::BeginEndPair>;
|
||||
using C4 = Container<C3, CtrChoice::DefaultCtrAndInsert, InserterChoice::PushBack>;
|
||||
using A1 = std::array<int, 4>;
|
||||
using A2 = std::array<A1, 3>;
|
||||
using A3 = std::array<A2, 2>;
|
||||
using A4 = std::array<A3, 2>;
|
||||
|
||||
A4 in = {};
|
||||
{ // Fill the nested array with incremental values.
|
||||
int x = 0;
|
||||
for (auto& a3 : in) {
|
||||
for (auto& a2 : a3) {
|
||||
for (auto& a1 : a2) {
|
||||
for (int& el : a1) {
|
||||
el = x++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::same_as<C4> decltype(auto) result = std::ranges::to<C4>(in);
|
||||
|
||||
assert(result.ctr_choice == CtrChoice::DefaultCtrAndInsert);
|
||||
|
||||
int expected_value = 0;
|
||||
for (auto& c3 : result) {
|
||||
assert(c3.ctr_choice == CtrChoice::BeginEndPair);
|
||||
|
||||
for (auto& c2 : c3) {
|
||||
assert(c2.ctr_choice == CtrChoice::FromRangeT);
|
||||
|
||||
for (auto& c1 : c2) {
|
||||
assert(c1.ctr_choice == CtrChoice::DirectCtr);
|
||||
|
||||
for (int el : c1) {
|
||||
assert(el == expected_value);
|
||||
++expected_value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert((in | std::ranges::to<C4>()) == result);
|
||||
}
|
||||
|
||||
constexpr bool test() {
|
||||
test_constraints();
|
||||
test_ctr_choice_order();
|
||||
test_lwg_3785();
|
||||
test_recursive();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,135 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
|
||||
// There is a bug in older versions of Clang that causes trouble with constraints in classes like
|
||||
// `ContainerWithDirectCtr`.
|
||||
// XFAIL: clang-16, apple-clang-15
|
||||
|
||||
// template<template<class...> class C, input_range R, class... Args>
|
||||
// constexpr auto to(R&& r, Args&&... args); // Since C++23
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include "container.h"
|
||||
|
||||
template <class ElementType>
|
||||
struct ContainerWithDirectCtr : Container<ElementType, CtrChoice::DirectCtr> {
|
||||
using Container<ElementType, CtrChoice::DirectCtr>::Container;
|
||||
};
|
||||
|
||||
template <std::ranges::input_range Range>
|
||||
ContainerWithDirectCtr(Range&&) -> ContainerWithDirectCtr<std::ranges::range_value_t<Range>>;
|
||||
|
||||
template <std::ranges::input_range Range>
|
||||
ContainerWithDirectCtr(Range&&, int, char) -> ContainerWithDirectCtr<std::ranges::range_value_t<Range>>;
|
||||
|
||||
template <class ElementType>
|
||||
struct ContainerWithFromRangeT : Container<ElementType, CtrChoice::FromRangeT> {
|
||||
using Container<ElementType, CtrChoice::FromRangeT>::Container;
|
||||
};
|
||||
|
||||
template <std::ranges::input_range Range>
|
||||
ContainerWithFromRangeT(std::from_range_t, Range&&) -> ContainerWithFromRangeT<std::ranges::range_value_t<Range>>;
|
||||
|
||||
template <std::ranges::input_range Range>
|
||||
ContainerWithFromRangeT(std::from_range_t, Range&&, int, char) ->
|
||||
ContainerWithFromRangeT<std::ranges::range_value_t<Range>>;
|
||||
|
||||
template <class ElementType>
|
||||
struct ContainerWithBeginEndPair : Container<ElementType, CtrChoice::BeginEndPair> {
|
||||
using Container<ElementType, CtrChoice::BeginEndPair>::Container;
|
||||
};
|
||||
|
||||
template <class Iter>
|
||||
ContainerWithBeginEndPair(Iter, Iter) -> ContainerWithBeginEndPair<std::iter_value_t<Iter>>;
|
||||
|
||||
template <class Iter>
|
||||
ContainerWithBeginEndPair(Iter, Iter, int, char) -> ContainerWithBeginEndPair<std::iter_value_t<Iter>>;
|
||||
|
||||
constexpr bool test() {
|
||||
std::array in = {1, 2, 3, 4, 5};
|
||||
int arg1 = 42;
|
||||
char arg2 = 'a';
|
||||
|
||||
{ // Case 1 -- can construct directly from the given range.
|
||||
{
|
||||
std::same_as<ContainerWithDirectCtr<int>> decltype(auto) result = std::ranges::to<ContainerWithDirectCtr>(in);
|
||||
|
||||
assert(result.ctr_choice == CtrChoice::DirectCtr);
|
||||
assert(std::ranges::equal(result, in));
|
||||
assert((in | std::ranges::to<ContainerWithDirectCtr>()) == result);
|
||||
}
|
||||
|
||||
{ // Extra arguments.
|
||||
std::same_as<ContainerWithDirectCtr<int>> decltype(auto) result =
|
||||
std::ranges::to<ContainerWithDirectCtr>(in, arg1, arg2);
|
||||
|
||||
assert(result.ctr_choice == CtrChoice::DirectCtr);
|
||||
assert(std::ranges::equal(result, in));
|
||||
assert(result.extra_arg1 == arg1);
|
||||
assert(result.extra_arg2 == arg2);
|
||||
assert((in | std::ranges::to<ContainerWithDirectCtr>(arg1, arg2)) == result);
|
||||
}
|
||||
}
|
||||
|
||||
{ // Case 2 -- can construct from the given range using the `from_range_t` tagged constructor.
|
||||
{
|
||||
std::same_as<ContainerWithFromRangeT<int>> decltype(auto) result = std::ranges::to<ContainerWithFromRangeT>(in);
|
||||
|
||||
assert(result.ctr_choice == CtrChoice::FromRangeT);
|
||||
assert(std::ranges::equal(result, in));
|
||||
assert((in | std::ranges::to<ContainerWithFromRangeT>()) == result);
|
||||
}
|
||||
|
||||
{ // Extra arguments.
|
||||
std::same_as<ContainerWithFromRangeT<int>> decltype(auto) result =
|
||||
std::ranges::to<ContainerWithFromRangeT>(in, arg1, arg2);
|
||||
|
||||
assert(result.ctr_choice == CtrChoice::FromRangeT);
|
||||
assert(std::ranges::equal(result, in));
|
||||
assert(result.extra_arg1 == arg1);
|
||||
assert(result.extra_arg2 == arg2);
|
||||
assert((in | std::ranges::to<ContainerWithFromRangeT>(arg1, arg2)) == result);
|
||||
}
|
||||
}
|
||||
|
||||
{ // Case 3 -- can construct from a begin-end iterator pair.
|
||||
{
|
||||
std::same_as<ContainerWithBeginEndPair<int>> decltype(auto) result =
|
||||
std::ranges::to<ContainerWithBeginEndPair>(in);
|
||||
|
||||
assert(result.ctr_choice == CtrChoice::BeginEndPair);
|
||||
assert(std::ranges::equal(result, in));
|
||||
assert((in | std::ranges::to<ContainerWithBeginEndPair>()) == result);
|
||||
}
|
||||
|
||||
{ // Extra arguments.
|
||||
std::same_as<ContainerWithBeginEndPair<int>> decltype(auto) result =
|
||||
std::ranges::to<ContainerWithBeginEndPair>(in, arg1, arg2);
|
||||
|
||||
assert(result.ctr_choice == CtrChoice::BeginEndPair);
|
||||
assert(std::ranges::equal(result, in));
|
||||
assert(result.extra_arg1 == arg1);
|
||||
assert(result.extra_arg2 == arg2);
|
||||
assert((in | std::ranges::to<ContainerWithBeginEndPair>(arg1, arg2)) == result);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,214 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
|
||||
|
||||
// Test that `ranges::to` can be used to convert between arbitrary standard containers.
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <deque>
|
||||
#include <forward_list>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <queue>
|
||||
#include <set>
|
||||
#include <stack>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
#include "test_iterators.h"
|
||||
#include "test_range.h"
|
||||
#include "type_algorithms.h"
|
||||
#include "unwrap_container_adaptor.h"
|
||||
|
||||
std::vector<std::vector<int>> ints = {
|
||||
{5, 1, 3, 4, 2},
|
||||
{3},
|
||||
{}
|
||||
};
|
||||
|
||||
std::vector<std::vector<char>> chars = {
|
||||
{'a', 'b', 'c'},
|
||||
{'a'},
|
||||
{}
|
||||
};
|
||||
|
||||
std::vector<std::vector<std::pair<const int, int>>> pairs = {
|
||||
{{1, 2}, {3, 4}, {5, 6}, {7, 8}, {9, 0}},
|
||||
{{1, 2}},
|
||||
{}
|
||||
};
|
||||
|
||||
template <class From, class To>
|
||||
void test_is_equal(std::vector<std::vector<typename From::value_type>> inputs) {
|
||||
for (const auto& in : inputs) {
|
||||
From from(in.begin(), in.end());
|
||||
std::same_as<To> decltype(auto) result = std::ranges::to<To>(from);
|
||||
assert(std::ranges::equal(in, result));
|
||||
}
|
||||
}
|
||||
|
||||
template <class From, class To>
|
||||
void test_is_permutation(std::vector<std::vector<typename From::value_type>> inputs) {
|
||||
for (const auto& in : inputs) {
|
||||
From from(in.begin(), in.end());
|
||||
std::same_as<To> decltype(auto) result = std::ranges::to<To>(in);
|
||||
assert(std::ranges::is_permutation(in, result));
|
||||
}
|
||||
}
|
||||
|
||||
template <class From, class To>
|
||||
void test_is_equal_for_adaptors(std::vector<std::vector<typename From::value_type>> inputs) {
|
||||
for (const auto& in : inputs) {
|
||||
From from(in.begin(), in.end());
|
||||
std::same_as<To> decltype(auto) result = std::ranges::to<To>(in);
|
||||
|
||||
UnwrapAdaptor<From> unwrap_from(std::move(from));
|
||||
UnwrapAdaptor<To> unwrap_to(std::move(result));
|
||||
assert(std::ranges::is_permutation(unwrap_from.get_container(), unwrap_to.get_container()));
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
using sequence_containers = types::type_list<
|
||||
std::vector<T>,
|
||||
std::deque<T>,
|
||||
std::list<T>,
|
||||
std::forward_list<T>
|
||||
>;
|
||||
|
||||
template <class T>
|
||||
using associative_sets = types::type_list<
|
||||
std::set<T>,
|
||||
std::multiset<T>
|
||||
>;
|
||||
|
||||
template <class K, class V>
|
||||
using associative_maps = types::type_list<
|
||||
std::map<K, V>,
|
||||
std::multimap<K, V>
|
||||
>;
|
||||
|
||||
template <class T>
|
||||
using unordered_sets = types::type_list<
|
||||
std::unordered_set<T>,
|
||||
std::unordered_multiset<T>
|
||||
>;
|
||||
|
||||
template <class K, class V>
|
||||
using unordered_maps = types::type_list<
|
||||
std::unordered_map<K, V>,
|
||||
std::unordered_multimap<K, V>
|
||||
>;
|
||||
|
||||
template <class T>
|
||||
using container_adaptors = types::type_list<
|
||||
std::stack<T>,
|
||||
std::queue<T>,
|
||||
std::priority_queue<T>
|
||||
>;
|
||||
|
||||
template <class T>
|
||||
using sequences_and_sets = types::concatenate_t<sequence_containers<T>, associative_sets<T>, unordered_sets<T>>;
|
||||
|
||||
template <class K, class V>
|
||||
using all_containers = types::concatenate_t<
|
||||
sequence_containers<std::pair<const K, V>>,
|
||||
associative_sets<std::pair<const K, V>>,
|
||||
associative_maps<K, V>,
|
||||
unordered_sets<std::pair<const K, V>>,
|
||||
unordered_maps<K, V>>;
|
||||
|
||||
// This is necessary to be able to use `pair`s with unordered sets.
|
||||
template <class K, class V>
|
||||
struct std::hash<std::pair<const K, V>> {
|
||||
std::size_t operator()(const std::pair<const K, V>& p) const {
|
||||
std::size_t h1 = std::hash<K>{}(p.first);
|
||||
std::size_t h2 = std::hash<V>{}(p.second);
|
||||
return h1 ^ (h2 << 1);
|
||||
}
|
||||
};
|
||||
|
||||
void test() {
|
||||
{ // Conversions always preserving equality.
|
||||
{ // sequences <-> sequences
|
||||
types::for_each(sequence_containers<int>{}, []<class From>() {
|
||||
types::for_each(sequence_containers<int>{}, []<class To>() {
|
||||
test_is_equal<From, To>(ints);
|
||||
});
|
||||
});
|
||||
|
||||
types::for_each(sequence_containers<int>{}, []<class From>() {
|
||||
types::for_each(sequence_containers<double>{}, []<class To>() {
|
||||
test_is_equal<From, To>(ints);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
{ // sequences <-> string
|
||||
types::for_each(sequence_containers<char>{}, []<class Seq>() {
|
||||
test_is_equal<Seq, std::basic_string<char>>(chars);
|
||||
test_is_equal<std::basic_string<char>, Seq>(chars);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
{ // sequences/sets <-> sequences/sets
|
||||
types::for_each(sequences_and_sets<int>{}, []<class From>() {
|
||||
types::for_each(sequences_and_sets<int>{}, []<class To>() {
|
||||
test_is_permutation<From, To>(ints);
|
||||
});
|
||||
});
|
||||
|
||||
types::for_each(sequences_and_sets<int>{}, []<class From>() {
|
||||
types::for_each(sequences_and_sets<double>{}, []<class To>() {
|
||||
test_is_permutation<From, To>(ints);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
{ // sequences/sets/maps <-> sequences/sets/maps. Uses `pair` for non-map containers to allow mutual conversion with
|
||||
// map types.
|
||||
types::for_each(all_containers<int, int>{}, []<class From>() {
|
||||
types::for_each(all_containers<int, int>{}, []<class To>() {
|
||||
test_is_permutation<From, To>(pairs);
|
||||
});
|
||||
});
|
||||
|
||||
types::for_each(all_containers<int, int>{}, []<class From>() {
|
||||
types::for_each(all_containers<long, double>{}, []<class To>() {
|
||||
test_is_permutation<From, To>(pairs);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
{ // adaptors <-> adaptors
|
||||
types::for_each(container_adaptors<int>{}, []<class From>() {
|
||||
types::for_each(container_adaptors<int>{}, []<class To>() {
|
||||
test_is_equal_for_adaptors<From, To>(ints);
|
||||
});
|
||||
});
|
||||
|
||||
types::for_each(container_adaptors<int>{}, []<class From>() {
|
||||
types::for_each(container_adaptors<double>{}, []<class To>() {
|
||||
test_is_equal_for_adaptors<From, To>(ints);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
|
||||
return 0;
|
||||
}
|
@ -841,8 +841,8 @@ feature_test_macros = [
|
||||
"forward_list",
|
||||
"list",
|
||||
"map",
|
||||
"priority_queue",
|
||||
"queue",
|
||||
"ranges",
|
||||
"set",
|
||||
"stack",
|
||||
"string",
|
||||
@ -850,7 +850,6 @@ feature_test_macros = [
|
||||
"unordered_set",
|
||||
"vector",
|
||||
],
|
||||
"unimplemented": True,
|
||||
},
|
||||
{
|
||||
"name": "__cpp_lib_ranges_zip",
|
||||
|
Loading…
Reference in New Issue
Block a user