diff --git a/libcxx/docs/Status/Cxx2bPapers.csv b/libcxx/docs/Status/Cxx2bPapers.csv --- a/libcxx/docs/Status/Cxx2bPapers.csv +++ b/libcxx/docs/Status/Cxx2bPapers.csv @@ -41,7 +41,7 @@ "`P0323R12 `__","LWG","``std::expected``","February 2022","|Complete|","16.0" "`P0533R9 `__","LWG","``constexpr`` for ```` and ````","February 2022","|In progress| [#note-P0533R9]_","" "`P0627R6 `__","LWG","Function to mark unreachable code","February 2022","|Complete|","15.0" -"`P1206R7 `__","LWG","``ranges::to``: A function to convert any range to a container","February 2022","","","|ranges|" +"`P1206R7 `__","LWG","``ranges::to``: A function to convert any range to a container","February 2022","|In Progress|","","|ranges|" "`P1413R3 `__","LWG","Deprecate ``std::aligned_storage`` and ``std::aligned_union``","February 2022","|Complete| [#note-P1413R3]_","" "`P2255R2 `__","LWG","A type trait to detect reference binding to temporary","February 2022","","" "`P2273R3 `__","LWG","Making ``std::unique_ptr`` constexpr","February 2022","|Complete|","16.0" diff --git a/libcxx/include/__ranges/container_compatible_range.h b/libcxx/include/__ranges/container_compatible_range.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__ranges/container_compatible_range.h @@ -0,0 +1,33 @@ +// -*- 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_CONTAINER_COMPATIBLE_RANGE_H +#define _LIBCPP___RANGES_CONTAINER_COMPATIBLE_RANGE_H + +#include <__config> +#include <__concepts/convertible_to.h> +#include <__ranges/concepts.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 23 + +template +concept _ContainerCompatibleRange = + ranges::input_range<_Range> && convertible_to, _Tp>; + +#endif // _LIBCPP_STD_VER >= 23 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___RANGES_CONTAINER_COMPATIBLE_RANGE_H diff --git a/libcxx/include/__ranges/from_range.h b/libcxx/include/__ranges/from_range.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__ranges/from_range.h @@ -0,0 +1,33 @@ +// -*- 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_FROM_RANGE_H +#define _LIBCPP___RANGES_FROM_RANGE_H + +#include <__config> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 23 + +struct from_range_t { + _LIBCPP_HIDE_FROM_ABI explicit from_range_t() = default; +}; + +inline constexpr from_range_t from_range{}; + +#endif // _LIBCPP_STD_VER >= 23 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___RANGES_FROM_RANGE_H diff --git a/libcxx/include/string b/libcxx/include/string --- a/libcxx/include/string +++ b/libcxx/include/string @@ -124,6 +124,8 @@ template basic_string(InputIterator begin, InputIterator end, const allocator_type& a = allocator_type()); // constexpr since C++20 + template R> + constexpr basic_string(from_range_t, R&& rg, const Allocator& a = Allocator()); // since C++23 basic_string(initializer_list, const Allocator& = Allocator()); // constexpr since C++20 basic_string(const basic_string&, const Allocator&); // constexpr since C++20 basic_string(basic_string&&, const Allocator&); // constexpr since C++20 @@ -200,6 +202,8 @@ basic_string& append(size_type n, value_type c); // constexpr since C++20 template basic_string& append(InputIterator first, InputIterator last); // constexpr since C++20 + template R> + constexpr basic_string& append_range(R&& rg); // C++23 basic_string& append(initializer_list); // constexpr since C++20 void push_back(value_type c); // constexpr since C++20 @@ -221,6 +225,8 @@ basic_string& assign(size_type n, value_type c); // constexpr since C++20 template basic_string& assign(InputIterator first, InputIterator last); // constexpr since C++20 + template R> + constexpr basic_string& assign_range(R&& rg); // C++23 basic_string& assign(initializer_list); // constexpr since C++20 basic_string& insert(size_type pos1, const basic_string& str); // constexpr since C++20 @@ -237,6 +243,8 @@ iterator insert(const_iterator p, size_type n, value_type c); // constexpr since C++20 template iterator insert(const_iterator p, InputIterator first, InputIterator last); // constexpr since C++20 + template R> + constexpr iterator insert_range(const_iterator p, R&& rg); // C++23 iterator insert(const_iterator p, initializer_list); // constexpr since C++20 basic_string& erase(size_type pos = 0, size_type n = npos); // constexpr since C++20 @@ -262,6 +270,8 @@ basic_string& replace(const_iterator i1, const_iterator i2, size_type n, value_type c); // constexpr since C++20 template basic_string& replace(const_iterator i1, const_iterator i2, InputIterator j1, InputIterator j2); // constexpr since C++20 + template R> + constexpr basic_string& replace_with_range(const_iterator i1, const_iterator i2, R&& rg); // C++23 basic_string& replace(const_iterator i1, const_iterator i2, initializer_list); // constexpr since C++20 size_type copy(value_type* s, size_type n, size_type pos = 0) const; // constexpr since C++20 @@ -354,6 +364,26 @@ char_traits::value_type>, Allocator>; // C++17 +template>> + basic_string(from_range_t, R&&, Allocator = Allocator()) + -> basic_string, char_traits>, + Allocator>; // C++23 + +template> + explicit basic_string(basic_string_view, const Allocator& = Allocator()) + -> basic_string; // C++17 + +template> + basic_string(basic_string_view, + typename see below::size_type, typename see below::size_type, + const Allocator& = Allocator()) + -> basic_string; // C++17 + template basic_string operator+(const basic_string& lhs, @@ -559,6 +589,11 @@ #include <__memory/pointer_traits.h> #include <__memory/swap_allocator.h> #include <__memory_resource/polymorphic_allocator.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__ranges/container_compatible_range.h> +#include <__ranges/from_range.h> +#include <__ranges/size.h> #include <__string/char_traits.h> #include <__string/extern_template_lists.h> #include <__type_traits/is_allocator.h> @@ -660,6 +695,8 @@ struct __uninitialized_size_tag {}; +struct __init_with_sentinel_tag {}; + template class basic_string { @@ -820,6 +857,14 @@ std::__debug_db_insert_c(this); } + template + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 + basic_string(__init_with_sentinel_tag, _Iter __first, _Sent __last, const allocator_type& __a) + : __r_(__default_init_tag(), __a) { + __init_with_sentinel(__first, __last); + std::__debug_db_insert_c(this); + } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 iterator __make_iterator(pointer __p) { return iterator(this, __p); } @@ -1046,6 +1091,21 @@ std::__debug_db_insert_c(this); } +#if _LIBCPP_STD_VER >= 23 + template <_ContainerCompatibleRange<_CharT> _Range> + _LIBCPP_HIDE_FROM_ABI constexpr + basic_string(from_range_t, _Range&& __range, const allocator_type& __a = allocator_type()) + : __r_(__default_init_tag(), __a) { + if constexpr (ranges::forward_range<_Range> || ranges::sized_range<_Range>) { + __init_with_size(ranges::begin(__range), ranges::end(__range), ranges::distance(__range)); + } else { + __init_with_sentinel(ranges::begin(__range), ranges::end(__range)); + } + + std::__debug_db_insert_c(this); + } +#endif + #ifndef _LIBCPP_CXX03_LANG _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string(initializer_list<_CharT> __il) : __r_(__default_init_tag(), __default_init_tag()) { @@ -1259,6 +1319,14 @@ _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string& append(_ForwardIterator __first, _ForwardIterator __last); +#if _LIBCPP_STD_VER >= 23 + template <_ContainerCompatibleRange<_CharT> _Range> + _LIBCPP_HIDE_FROM_ABI + constexpr basic_string& append_range(_Range&& __range) { + return append(basic_string(from_range, std::forward<_Range>(__range), get_allocator())); + } +#endif + #ifndef _LIBCPP_CXX03_LANG _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string& append(initializer_list __il) {return append(__il.begin(), __il.size());} @@ -1322,6 +1390,24 @@ _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string& assign(_ForwardIterator __first, _ForwardIterator __last); +#if _LIBCPP_STD_VER >= 23 + template <_ContainerCompatibleRange<_CharT> _Range> + _LIBCPP_HIDE_FROM_ABI + constexpr basic_string& assign_range(_Range&& __range) { + if constexpr (ranges::forward_range<_Range> || ranges::sized_range<_Range>) { + size_type __n = __string_is_trivial_iterator>::value ? + static_cast(ranges::distance(__range)) : 0; + __assign_with_size(ranges::begin(__range), ranges::end(__range), __n); + + } else { + basic_string __temp(from_range, std::forward<_Range>(__range), __alloc()); + assign(__temp.data(), __temp.size()); + } + + return *this; + } +#endif + #ifndef _LIBCPP_CXX03_LANG _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string& assign(initializer_list __il) {return assign(__il.begin(), __il.size());} @@ -1353,6 +1439,21 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string& insert(size_type __pos, size_type __n, value_type __c); _LIBCPP_CONSTEXPR_SINCE_CXX20 iterator insert(const_iterator __pos, value_type __c); +#if _LIBCPP_STD_VER >= 23 + template <_ContainerCompatibleRange<_CharT> _Range> + _LIBCPP_HIDE_FROM_ABI + constexpr iterator insert_range(const_iterator __position, _Range&& __range) { + if constexpr (ranges::forward_range<_Range> || ranges::sized_range<_Range>) { + auto __n = static_cast(ranges::distance(__range)); + return __insert_with_size(__position, ranges::begin(__range), ranges::end(__range), __n); + + } else { + basic_string __temp(from_range, std::forward<_Range>(__range), __alloc()); + return insert(__position, __temp.data(), __temp.data() + __temp.size()); + } + } +#endif + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 iterator insert(const_iterator __pos, size_type __n, value_type __c) { _LIBCPP_DEBUG_ASSERT(__get_const_db()->__find_c_from_i(&__pos) == this, @@ -1441,6 +1542,15 @@ _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string& replace(const_iterator __i1, const_iterator __i2, _InputIterator __j1, _InputIterator __j2); +#if _LIBCPP_STD_VER >= 23 + template <_ContainerCompatibleRange<_CharT> _Range> + _LIBCPP_HIDE_FROM_ABI + constexpr basic_string& replace_with_range(const_iterator __i1, const_iterator __i2, _Range&& __range) { + basic_string __temp(from_range, std::forward<_Range>(__range), __alloc()); + return replace(__i1, __i2, __temp); + } +#endif + #ifndef _LIBCPP_CXX03_LANG _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string& replace(const_iterator __i1, const_iterator __i2, initializer_list __il) @@ -1699,9 +1809,17 @@ return !__libcpp_is_constant_evaluated() && (__sz < __min_cap); } - template + template + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI + void __assign_with_size(_Iterator __first, _Sentinel __last, size_type __n); + + template + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI + void __assign_with_sentinel(_Iterator __first, _Sentinel __last); + + template _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 - iterator __insert_from_safe_copy(size_type __n, size_type __ip, _ForwardIterator __first, _ForwardIterator __last) { + iterator __insert_from_safe_copy(size_type __n, size_type __ip, _ForwardIterator __first, _Sentinel __last) { size_type __sz = size(); size_type __cap = capacity(); value_type* __p; @@ -1726,6 +1844,10 @@ return begin() + __ip; } + template + _LIBCPP_CONSTEXPR_SINCE_CXX20 + iterator __insert_with_size(const_iterator __pos, _Iterator __first, _Sentinel __last, size_type __n); + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 allocator_type& __alloc() _NOEXCEPT { return __r_.second(); } _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR const allocator_type& __alloc() const _NOEXCEPT { return __r_.second(); } @@ -1828,6 +1950,13 @@ template ::value, int> = 0> inline _LIBCPP_CONSTEXPR_SINCE_CXX20 void __init(_ForwardIterator __first, _ForwardIterator __last); + template + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 + void __init_with_sentinel(_InputIterator __first, _Sentinel __last); + template + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 + void __init_with_size(_InputIterator __first, _Sentinel __last, size_type __sz); + _LIBCPP_CONSTEXPR_SINCE_CXX20 void __grow_by(size_type __old_cap, size_type __delta_cap, size_type __old_sz, size_type __n_copy, size_type __n_del, size_type __n_add = 0); @@ -2014,6 +2143,15 @@ -> basic_string<_CharT, _Traits, _Allocator>; #endif +#if _LIBCPP_STD_VER >= 23 +template >, + class = enable_if_t<__is_allocator<_Allocator>::value> + > +basic_string(from_range_t, _Range&&, _Allocator = _Allocator()) + -> basic_string, char_traits>, _Allocator>; +#endif + template inline _LIBCPP_CONSTEXPR_SINCE_CXX20 void @@ -2159,7 +2297,15 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void basic_string<_CharT, _Traits, _Allocator>::__init(_InputIterator __first, _InputIterator __last) { + __init_with_sentinel(__first, __last); +} + +template +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 +void basic_string<_CharT, _Traits, _Allocator>::__init_with_sentinel(_InputIterator __first, _Sentinel __last) { __default_init(); + #ifndef _LIBCPP_HAS_NO_EXCEPTIONS try { @@ -2182,16 +2328,27 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void basic_string<_CharT, _Traits, _Allocator>::__init(_ForwardIterator __first, _ForwardIterator __last) { + size_type __sz = static_cast(std::distance(__first, __last)); + __init_with_size(__first, __last, __sz); +} + +template +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 +void basic_string<_CharT, _Traits, _Allocator>::__init_with_size( + _InputIterator __first, _Sentinel __last, size_type __sz) { if (__libcpp_is_constant_evaluated()) __r_.first() = __rep(); - size_type __sz = static_cast(std::distance(__first, __last)); + if (__sz > max_size()) __throw_length_error(); + pointer __p; if (__fits_in_sso(__sz)) { __set_short_size(__sz); __p = __get_short_pointer(); + } else { @@ -2447,9 +2604,17 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string<_CharT, _Traits, _Allocator>& basic_string<_CharT, _Traits, _Allocator>::assign(_InputIterator __first, _InputIterator __last) { - const basic_string __temp(__first, __last, __alloc()); - assign(__temp.data(), __temp.size()); - return *this; + __assign_with_sentinel(__first, __last); + return *this; +} + +template +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 +void +basic_string<_CharT, _Traits, _Allocator>::__assign_with_sentinel(_InputIterator __first, _Sentinel __last) { + const basic_string __temp(__init_with_sentinel_tag{}, __first, __last, __alloc()); + assign(__temp.data(), __temp.size()); } template @@ -2457,11 +2622,24 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string<_CharT, _Traits, _Allocator>& basic_string<_CharT, _Traits, _Allocator>::assign(_ForwardIterator __first, _ForwardIterator __last) { + if (__string_is_trivial_iterator<_ForwardIterator>::value) { + size_type __n = static_cast(std::distance(__first, __last)); + __assign_with_size(__first, __last, __n); + } else { + __assign_with_sentinel(__first, __last); + } + + return *this; +} + +template +template +_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI +void +basic_string<_CharT, _Traits, _Allocator>::__assign_with_size(_Iterator __first, _Sentinel __last, size_type __n) { size_type __cap = capacity(); - size_type __n = __string_is_trivial_iterator<_ForwardIterator>::value ? - static_cast(std::distance(__first, __last)) : 0; - if (__string_is_trivial_iterator<_ForwardIterator>::value && + if (__string_is_trivial_iterator<_Iterator>::value && (__cap >= __n || !__addr_in_range(*__first))) { if (__cap < __n) @@ -2478,10 +2656,8 @@ } else { - const basic_string __temp(__first, __last, __alloc()); - assign(__temp.data(), __temp.size()); + __assign_with_sentinel(__first, __last); } - return *this; } template @@ -2787,19 +2963,27 @@ { _LIBCPP_DEBUG_ASSERT(__get_const_db()->__find_c_from_i(&__pos) == this, "string::insert(iterator, range) called with an iterator not referring to this string"); + auto __n = static_cast(std::distance(__first, __last)); + return __insert_with_size(__pos, __first, __last, __n); +} +template +template +_LIBCPP_CONSTEXPR_SINCE_CXX20 +typename basic_string<_CharT, _Traits, _Allocator>::iterator +basic_string<_CharT, _Traits, _Allocator>::__insert_with_size( + const_iterator __pos, _Iterator __first, _Sentinel __last, size_type __n) { size_type __ip = static_cast(__pos - begin()); - size_type __n = static_cast(std::distance(__first, __last)); if (__n == 0) return begin() + __ip; - if (__string_is_trivial_iterator<_ForwardIterator>::value && !__addr_in_range(*__first)) + if (__string_is_trivial_iterator<_Iterator>::value && !__addr_in_range(*__first)) { return __insert_from_safe_copy(__n, __ip, __first, __last); } else { - const basic_string __temp(__first, __last, __alloc()); + const basic_string __temp(__init_with_sentinel_tag{}, __first, __last, __alloc()); return __insert_from_safe_copy(__n, __ip, __temp.begin(), __temp.end()); } } diff --git a/libcxx/test/std/containers/from_range_helpers.h b/libcxx/test/std/containers/from_range_helpers.h new file mode 100644 --- /dev/null +++ b/libcxx/test/std/containers/from_range_helpers.h @@ -0,0 +1,148 @@ +//===----------------------------------------------------------------------===// +// +// 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 SUPPORT_FROM_RANGE_HELPERS_H +#define SUPPORT_FROM_RANGE_HELPERS_H + +#include +#include +#include + +#include "min_allocator.h" +#include "test_allocator.h" +#include "test_iterators.h" +#include "test_macros.h" +#include "type_algorithms.h" + +struct Empty {}; + +template +struct InputRange { + cpp20_input_iterator begin(); + sentinel_wrapper> end(); +}; + +template +constexpr auto wrap_input(Range&& input) { + auto b = Iter(std::ranges::begin(input)); + auto e = Sent(Iter(std::ranges::end(input))); + return std::ranges::subrange(std::move(b), std::move(e)); +} + +template +constexpr auto wrap_input(std::vector& input) { + auto b = Iter(input.data()); + auto e = Sent(Iter(input.data() + input.size())); + return std::ranges::subrange(std::move(b), std::move(e)); +} + +struct KeyValue { + int key; // Only the key is considered for equality comparison. + char value; // Allows distinguishing equivalent instances. + + bool operator<(const KeyValue& other) const { return key < other.key; } + bool operator==(const KeyValue& other) const { return key == other.key; } +}; + +template <> +struct std::hash { + std::size_t operator()(const KeyValue& kv) const { + return kv.key; + } +}; + +#if !defined(TEST_HAS_NO_EXCEPTIONS) +template +struct ThrowingCopy { + static bool throwing_enabled; + static int created_by_copying; + static int destroyed; + int x = 0; // Allows distinguishing between different instances. + + ThrowingCopy() = default; + ThrowingCopy(int value) : x(value) {} + ~ThrowingCopy() { + ++destroyed; + } + + ThrowingCopy(const ThrowingCopy& other) : x(other.x) { + ++created_by_copying; + if (throwing_enabled && created_by_copying == N) { + throw -1; + } + } + + friend auto operator<=>(const ThrowingCopy&, const ThrowingCopy&) = default; + + static void reset() { + created_by_copying = destroyed = 0; + } +}; + +template +struct std::hash> { + std::size_t operator()(const ThrowingCopy& value) const { + return value.x; + } +}; + +template +bool ThrowingCopy::throwing_enabled = true; +template +int ThrowingCopy::created_by_copying = 0; +template +int ThrowingCopy::destroyed = 0; + +template +struct ThrowingAllocator { + using value_type = T; + using char_type = T; + using is_always_equal = std::false_type; + + ThrowingAllocator() = default; + + template + ThrowingAllocator(const ThrowingAllocator&) {} + + T* allocate(std::size_t) { throw 1; } + void deallocate(T*, std::size_t) {} + + template + friend bool operator==(const ThrowingAllocator&, const ThrowingAllocator&) { + return true; + } +}; +#endif + +template +constexpr void for_all_iterators_and_allocators(Func f) { + using Iterators = types::type_list< + cpp20_input_iterator, + forward_iterator, + bidirectional_iterator, + random_access_iterator, + contiguous_iterator, + T* + >; + + types::for_each(Iterators{}, [=]() { + f.template operator(), std::allocator>(); + f.template operator(), test_allocator>(); + f.template operator(), min_allocator>(); + f.template operator(), safe_allocator>(); + + if constexpr (std::sentinel_for) { + f.template operator()>(); + f.template operator()>(); + f.template operator()>(); + f.template operator()>(); + } + }); +} + +#endif // SUPPORT_FROM_RANGE_HELPERS_H diff --git a/libcxx/test/std/containers/insert_range_helpers.h b/libcxx/test/std/containers/insert_range_helpers.h new file mode 100644 --- /dev/null +++ b/libcxx/test/std/containers/insert_range_helpers.h @@ -0,0 +1,123 @@ +//===----------------------------------------------------------------------===// +// +// 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 SUPPORT_INSERT_RANGE_HELPERS_H +#define SUPPORT_INSERT_RANGE_HELPERS_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "from_range_helpers.h" +#include "min_allocator.h" +#include "test_allocator.h" +#include "test_iterators.h" +#include "test_macros.h" +#include "type_algorithms.h" + +// A simple literal-type container. It can be used as a `constexpr` global variable (which isn't supported by +// `std::vector`). +template +class Buffer { + public: + constexpr Buffer() = default; + + constexpr Buffer(std::initializer_list input) { + assert(input.size() <= N); + std::ranges::copy(input, data_); + size_ = input.size(); + } + + // Makes initializing `Buffer` nicer -- allows writing `buf = "abc"` instead of `buf = {'a', 'b', 'c'}`. + // To make the two forms equivalent, omits the terminating null. + template + constexpr Buffer(const char (&input) [N2]) + requires std::same_as { + static_assert(N2 <= N); + std::ranges::copy(input, data_); + // Omit the terminating null. + size_ = input[N2 - 1] == '\0' ? N2 - 1 : N2; + } + + constexpr const T* begin() const { return data_; } + constexpr const T* end() const { return data_ + size_; } + constexpr std::size_t size() const { return size_; } + + private: + std::size_t size_ = 0; + T data_[N] = {}; +}; + +template +struct TestCase { + Buffer initial; + std::size_t index = 0; + Buffer input; + Buffer expected; +}; + +template +constexpr void for_all_iterators_and_allocators(Func f) { + using Iterators = types::type_list< + cpp20_input_iterator, + forward_iterator, + bidirectional_iterator, + random_access_iterator, + contiguous_iterator, + PtrT + >; + + types::for_each(Iterators{}, [=]() { + f.template operator(), std::allocator>(); + f.template operator(), test_allocator>(); + f.template operator(), min_allocator>(); + f.template operator(), safe_allocator>(); + + if constexpr (std::sentinel_for) { + f.template operator()>(); + f.template operator()>(); + f.template operator()>(); + f.template operator()>(); + } + }); +} + +// Uses a shorter list of iterator types for use in `constexpr` mode for cases when running the full set in would take +// too long. +template +constexpr void for_all_iterators_and_allocators_constexpr(Func f) { + using Iterators = types::type_list< + cpp20_input_iterator, + forward_iterator, + PtrT + >; + + types::for_each(Iterators{}, [=]() { + f.template operator(), std::allocator>(); + f.template operator(), test_allocator>(); + f.template operator(), min_allocator>(); + f.template operator(), safe_allocator>(); + + if constexpr (std::sentinel_for) { + f.template operator()>(); + f.template operator()>(); + f.template operator()>(); + f.template operator()>(); + } + }); +} + +#endif // SUPPORT_INSERT_RANGE_HELPERS_H diff --git a/libcxx/test/std/containers/sequences/from_range_sequence_containers.h b/libcxx/test/std/containers/sequences/from_range_sequence_containers.h new file mode 100644 --- /dev/null +++ b/libcxx/test/std/containers/sequences/from_range_sequence_containers.h @@ -0,0 +1,161 @@ +//===----------------------------------------------------------------------===// +// +// 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 SUPPORT_FROM_RANGE_SEQUENCE_CONTAINERS_H +#define SUPPORT_FROM_RANGE_SEQUENCE_CONTAINERS_H + +#include +#include +#include +#include +#include +#include +#include + +#include "../from_range_helpers.h" +#include "MoveOnly.h" +#include "almost_satisfies_types.h" +#include "count_new.h" +#include "test_iterators.h" +#include "test_macros.h" + +template +concept HasSize = requires (const T& value) { value.size(); }; + +template +concept HasFromRangeCtr = requires (Range&& range) { + Container(std::from_range, std::forward(range)); + Container(std::from_range, std::forward(range), std::allocator()); +}; + +template