[libc++][ranges] Implement the changes to vector from P1206 (ranges::to):

- add the `from_range_t` constructors and the related deduction guides;
- add the `insert_range`/`assign_range`/etc. member functions.
(Note: this patch is split from https://reviews.llvm.org/D142335)

Differential Revision: https://reviews.llvm.org/D149826
This commit is contained in:
varconst 2023-05-08 23:40:21 -07:00 committed by Konstantin Varlamov
parent c60461e3f8
commit 17bbb224f9
25 changed files with 2347 additions and 196 deletions

View File

@ -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","","","|ranges|"
"`P1206R7 <https://wg21.link/P1206R7>`__","LWG","``ranges::to``: A function to convert any range to a container","February 2022","|In Progress|","","|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.

View File

@ -581,6 +581,7 @@ set(files
__ranges/as_rvalue_view.h
__ranges/common_view.h
__ranges/concepts.h
__ranges/container_compatible_range.h
__ranges/copyable_box.h
__ranges/counted.h
__ranges/dangling.h
@ -593,6 +594,7 @@ set(files
__ranges/enable_borrowed_range.h
__ranges/enable_view.h
__ranges/filter_view.h
__ranges/from_range.h
__ranges/iota_view.h
__ranges/istream_view.h
__ranges/join_view.h

View File

@ -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 <__concepts/convertible_to.h>
#include <__config>
#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 <class _Range, class _Tp>
concept _ContainerCompatibleRange =
ranges::input_range<_Range> && convertible_to<ranges::range_reference_t<_Range>, _Tp>;
#endif // _LIBCPP_STD_VER >= 23
_LIBCPP_END_NAMESPACE_STD
#endif // _LIBCPP___RANGES_CONTAINER_COMPATIBLE_RANGE_H

View File

@ -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 {
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

View File

@ -170,6 +170,14 @@ public:
__enable_if_t<__is_cpp17_forward_iterator<_ForwardIterator>::value>
__construct_at_end(_ForwardIterator __first, _ForwardIterator __last);
template <class _Iterator, class _Sentinel>
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI
void __construct_at_end_with_sentinel(_Iterator __first, _Sentinel __last);
template <class _Iterator>
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI
void __construct_at_end_with_size(_Iterator __first, size_type __n);
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __destruct_at_begin(pointer __new_begin) {
__destruct_at_begin(__new_begin, is_trivially_destructible<value_type>());
}
@ -279,6 +287,13 @@ template <class _InputIter>
_LIBCPP_CONSTEXPR_SINCE_CXX20 __enable_if_t<__is_exactly_cpp17_input_iterator<_InputIter>::value>
__split_buffer<_Tp, _Allocator>::__construct_at_end(_InputIter __first, _InputIter __last)
{
__construct_at_end_with_sentinel(__first, __last);
}
template <class _Tp, class _Allocator>
template <class _Iterator, class _Sentinel>
_LIBCPP_CONSTEXPR_SINCE_CXX20
void __split_buffer<_Tp, _Allocator>::__construct_at_end_with_sentinel(_Iterator __first, _Sentinel __last) {
__alloc_rr& __a = this->__alloc();
for (; __first != __last; ++__first)
{
@ -296,13 +311,19 @@ __split_buffer<_Tp, _Allocator>::__construct_at_end(_InputIter __first, _InputIt
++this->__end_;
}
}
template <class _Tp, class _Allocator>
template <class _ForwardIterator>
_LIBCPP_CONSTEXPR_SINCE_CXX20 __enable_if_t<__is_cpp17_forward_iterator<_ForwardIterator>::value>
__split_buffer<_Tp, _Allocator>::__construct_at_end(_ForwardIterator __first, _ForwardIterator __last)
{
_ConstructTransaction __tx(&this->__end_, _VSTD::distance(__first, __last));
__construct_at_end_with_size(__first, std::distance(__first, __last));
}
template <class _Tp, class _Allocator>
template <class _ForwardIterator>
_LIBCPP_CONSTEXPR_SINCE_CXX20
void __split_buffer<_Tp, _Allocator>::__construct_at_end_with_size(_ForwardIterator __first, size_type __n) {
_ConstructTransaction __tx(&this->__end_, __n);
for (; __tx.__pos_ != __tx.__end_; ++__tx.__pos_, (void) ++__first) {
__alloc_traits::construct(this->__alloc(),
_VSTD::__to_address(__tx.__pos_), *__first);

View File

@ -1309,62 +1309,64 @@ module std [system] {
export *
module __ranges {
module access { private header "__ranges/access.h" }
module all {
module access { private header "__ranges/access.h" }
module all {
private header "__ranges/all.h"
export functional.__functional.compose
export functional.__functional.perfect_forward
}
module as_rvalue_view { private header "__ranges/as_rvalue_view.h" }
module common_view { private header "__ranges/common_view.h" }
module concepts { private header "__ranges/concepts.h" }
module copyable_box { private header "__ranges/copyable_box.h" }
module counted {
module as_rvalue_view { private header "__ranges/as_rvalue_view.h" }
module common_view { private header "__ranges/common_view.h" }
module concepts { private header "__ranges/concepts.h" }
module container_compatible_range { private header "__ranges/container_compatible_range.h" }
module copyable_box { private header "__ranges/copyable_box.h" }
module counted {
private header "__ranges/counted.h"
export span
}
module dangling { private header "__ranges/dangling.h" }
module data { private header "__ranges/data.h" }
module drop_view { private header "__ranges/drop_view.h" }
module drop_while_view { private header "__ranges/drop_while_view.h" }
module elements_view { private header "__ranges/elements_view.h" }
module empty { private header "__ranges/empty.h" }
module empty_view { private header "__ranges/empty_view.h" }
module enable_borrowed_range { private header "__ranges/enable_borrowed_range.h" }
module enable_view { private header "__ranges/enable_view.h" }
module filter_view { private header "__ranges/filter_view.h" }
module iota_view { private header "__ranges/iota_view.h" }
module istream_view {
module dangling { private header "__ranges/dangling.h" }
module data { private header "__ranges/data.h" }
module drop_view { private header "__ranges/drop_view.h" }
module drop_while_view { private header "__ranges/drop_while_view.h" }
module elements_view { private header "__ranges/elements_view.h" }
module empty { private header "__ranges/empty.h" }
module empty_view { private header "__ranges/empty_view.h" }
module enable_borrowed_range { private header "__ranges/enable_borrowed_range.h" }
module enable_view { private header "__ranges/enable_view.h" }
module filter_view { private header "__ranges/filter_view.h" }
module from_range { private header "__ranges/from_range.h" }
module iota_view { private header "__ranges/iota_view.h" }
module istream_view {
@requires_LIBCXX_ENABLE_LOCALIZATION@
private header "__ranges/istream_view.h"
}
module join_view { private header "__ranges/join_view.h" }
module lazy_split_view { private header "__ranges/lazy_split_view.h" }
module non_propagating_cache { private header "__ranges/non_propagating_cache.h" }
module owning_view { private header "__ranges/owning_view.h" }
module range_adaptor { private header "__ranges/range_adaptor.h" }
module rbegin { private header "__ranges/rbegin.h" }
module ref_view { private header "__ranges/ref_view.h" }
module rend { private header "__ranges/rend.h" }
module reverse_view { private header "__ranges/reverse_view.h" }
module single_view { private header "__ranges/single_view.h" }
module size { private header "__ranges/size.h" }
module split_view { private header "__ranges/split_view.h" }
module subrange {
module join_view { private header "__ranges/join_view.h" }
module lazy_split_view { private header "__ranges/lazy_split_view.h" }
module non_propagating_cache { private header "__ranges/non_propagating_cache.h" }
module owning_view { private header "__ranges/owning_view.h" }
module range_adaptor { private header "__ranges/range_adaptor.h" }
module rbegin { private header "__ranges/rbegin.h" }
module ref_view { private header "__ranges/ref_view.h" }
module rend { private header "__ranges/rend.h" }
module reverse_view { private header "__ranges/reverse_view.h" }
module single_view { private header "__ranges/single_view.h" }
module size { private header "__ranges/size.h" }
module split_view { private header "__ranges/split_view.h" }
module subrange {
private header "__ranges/subrange.h"
export subrange_fwd
}
module subrange_fwd { private header "__fwd/subrange.h" }
module take_view { private header "__ranges/take_view.h" }
module take_while_view { private header "__ranges/take_while_view.h" }
module transform_view {
module subrange_fwd { private header "__fwd/subrange.h" }
module take_view { private header "__ranges/take_view.h" }
module take_while_view { private header "__ranges/take_while_view.h" }
module transform_view {
private header "__ranges/transform_view.h"
export functional.__functional.bind_back
export functional.__functional.perfect_forward
}
module view_interface { private header "__ranges/view_interface.h" }
module views { private header "__ranges/views.h" }
module zip_view { private header "__ranges/zip_view.h" }
module view_interface { private header "__ranges/view_interface.h" }
module views { private header "__ranges/views.h" }
module zip_view { private header "__ranges/zip_view.h" }
}
}
module ratio {

View File

@ -339,6 +339,9 @@ namespace std {
struct tuple_element<1, const ranges::subrange<I, S, K>> {
using type = S;
};
struct from_range_t { explicit from_range_t() = default; }; // Since C++23
inline constexpr from_range_t from_range{}; // Since C++23
}
*/
@ -360,6 +363,7 @@ namespace std {
#include <__ranges/enable_borrowed_range.h>
#include <__ranges/enable_view.h>
#include <__ranges/filter_view.h>
#include <__ranges/from_range.h>
#include <__ranges/iota_view.h>
#include <__ranges/join_view.h>
#include <__ranges/lazy_split_view.h>

View File

@ -41,6 +41,8 @@ public:
vector(size_type n, const value_type& value, const allocator_type& = allocator_type());
template <class InputIterator>
vector(InputIterator first, InputIterator last, const allocator_type& = allocator_type());
template<container-compatible-range<T> R>
constexpr vector(from_range_t, R&& rg, const Allocator& = Allocator()); // C++23
vector(const vector& x);
vector(vector&& x)
noexcept(is_nothrow_move_constructible<allocator_type>::value);
@ -55,6 +57,8 @@ public:
vector& operator=(initializer_list<value_type> il);
template <class InputIterator>
void assign(InputIterator first, InputIterator last);
template<container-compatible-range<T> R>
constexpr void assign_range(R&& rg); // C++23
void assign(size_type n, const value_type& u);
void assign(initializer_list<value_type> il);
@ -99,6 +103,8 @@ public:
void push_back(value_type&& x);
template <class... Args>
reference emplace_back(Args&&... args); // reference in C++17
template<container-compatible-range<T> R>
constexpr void append_range(R&& rg); // C++23
void pop_back();
template <class... Args> iterator emplace(const_iterator position, Args&&... args);
@ -107,6 +113,8 @@ public:
iterator insert(const_iterator position, size_type n, const value_type& x);
template <class InputIterator>
iterator insert(const_iterator position, InputIterator first, InputIterator last);
template<container-compatible-range<T> R>
constexpr iterator insert_range(const_iterator position, R&& rg); // C++23
iterator insert(const_iterator position, initializer_list<value_type> il);
iterator erase(const_iterator position);
@ -165,6 +173,8 @@ public:
vector(size_type n, const value_type& value, const allocator_type& = allocator_type());
template <class InputIterator>
vector(InputIterator first, InputIterator last, const allocator_type& = allocator_type());
template<container-compatible-range<bool> R>
constexpr vector(from_range_t, R&& rg, const Allocator& = Allocator());
vector(const vector& x);
vector(vector&& x)
noexcept(is_nothrow_move_constructible<allocator_type>::value);
@ -179,6 +189,8 @@ public:
vector& operator=(initializer_list<value_type> il);
template <class InputIterator>
void assign(InputIterator first, InputIterator last);
template<container-compatible-range<T> R>
constexpr void assign_range(R&& rg); // C++23
void assign(size_type n, const value_type& u);
void assign(initializer_list<value_type> il);
@ -218,6 +230,8 @@ public:
void push_back(const value_type& x);
template <class... Args> reference emplace_back(Args&&... args); // C++14; reference in C++17
template<container-compatible-range<T> R>
constexpr void append_range(R&& rg); // C++23
void pop_back();
template <class... Args> iterator emplace(const_iterator position, Args&&... args); // C++14
@ -225,6 +239,8 @@ public:
iterator insert(const_iterator position, size_type n, const value_type& x);
template <class InputIterator>
iterator insert(const_iterator position, InputIterator first, InputIterator last);
template<container-compatible-range<T> R>
constexpr iterator insert_range(const_iterator position, R&& rg); // C++23
iterator insert(const_iterator position, initializer_list<value_type> il);
iterator erase(const_iterator position);
@ -247,6 +263,10 @@ template <class InputIterator, class Allocator = allocator<typename iterator_tra
vector(InputIterator, InputIterator, Allocator = Allocator())
-> vector<typename iterator_traits<InputIterator>::value_type, Allocator>; // C++17
template<ranges::input_range R, class Allocator = allocator<ranges::range_value_t<R>>>
vector(from_range_t, R&&, Allocator = Allocator())
-> vector<ranges::range_value_t<R>, Allocator>; // C++23
template <class Allocator> struct hash<std::vector<bool, Allocator>>;
template <class T, class Allocator> bool operator==(const vector<T,Allocator>& x, const vector<T,Allocator>& y);
@ -281,6 +301,7 @@ template<class T, class charT> requires is-vector-bool-reference<T> // Since C++
#include <__algorithm/copy.h>
#include <__algorithm/equal.h>
#include <__algorithm/fill_n.h>
#include <__algorithm/iterator_operations.h>
#include <__algorithm/lexicographical_compare.h>
#include <__algorithm/remove.h>
#include <__algorithm/remove_if.h>
@ -297,6 +318,7 @@ template<class T, class charT> requires is-vector-bool-reference<T> // Since C++
#include <__functional/hash.h>
#include <__functional/unary_function.h>
#include <__iterator/advance.h>
#include <__iterator/distance.h>
#include <__iterator/iterator_traits.h>
#include <__iterator/reverse_iterator.h>
#include <__iterator/wrap_iter.h>
@ -308,6 +330,11 @@ template<class T, class charT> requires is-vector-bool-reference<T> // Since C++
#include <__memory/temp_value.h>
#include <__memory/uninitialized_algorithms.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 <__split_buffer>
#include <__type_traits/is_allocator.h>
#include <__type_traits/is_constructible.h>
@ -317,6 +344,7 @@ template<class T, class charT> requires is-vector-bool-reference<T> // Since C++
#include <__utility/exception_guard.h>
#include <__utility/forward.h>
#include <__utility/move.h>
#include <__utility/pair.h>
#include <__utility/swap.h>
#include <climits>
#include <cstring>
@ -345,7 +373,6 @@ template<class T, class charT> requires is-vector-bool-reference<T> // Since C++
_LIBCPP_PUSH_MACROS
#include <__undef_macros>
_LIBCPP_BEGIN_NAMESPACE_STD
template <class _Tp, class _Allocator /* = allocator<_Tp> */>
@ -437,6 +464,20 @@ public:
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI
vector(_ForwardIterator __first, _ForwardIterator __last, const allocator_type& __a);
#if _LIBCPP_STD_VER >= 23
template <_ContainerCompatibleRange<_Tp> _Range>
_LIBCPP_HIDE_FROM_ABI constexpr vector(from_range_t, _Range&& __range,
const allocator_type& __alloc = allocator_type()) : __end_cap_(nullptr, __alloc) {
if constexpr (ranges::forward_range<_Range> || ranges::sized_range<_Range>) {
auto __n = static_cast<size_type>(ranges::distance(__range));
__init_with_size(ranges::begin(__range), ranges::end(__range), __n);
} else {
__init_with_sentinel(ranges::begin(__range), ranges::end(__range));
}
}
#endif
private:
class __destroy_vector {
public:
@ -502,6 +543,20 @@ public:
int> = 0>
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void assign(_ForwardIterator __first, _ForwardIterator __last);
#if _LIBCPP_STD_VER >= 23
template <_ContainerCompatibleRange<_Tp> _Range>
_LIBCPP_HIDE_FROM_ABI
constexpr void assign_range(_Range&& __range) {
if constexpr (ranges::forward_range<_Range> || ranges::sized_range<_Range>) {
auto __n = static_cast<size_type>(ranges::distance(__range));
__assign_with_size(ranges::begin(__range), ranges::end(__range), __n);
} else {
__assign_with_sentinel(ranges::begin(__range), ranges::end(__range));
}
}
#endif
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void assign(size_type __n, const_reference __u);
#ifndef _LIBCPP_CXX03_LANG
@ -604,6 +659,14 @@ public:
void emplace_back(_Args&&... __args);
#endif
#if _LIBCPP_STD_VER >= 23
template <_ContainerCompatibleRange<_Tp> _Range>
_LIBCPP_HIDE_FROM_ABI
constexpr void append_range(_Range&& __range) {
insert_range(end(), std::forward<_Range>(__range));
}
#endif
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI
void pop_back();
@ -623,6 +686,20 @@ public:
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI iterator
insert(const_iterator __position, _InputIterator __first, _InputIterator __last);
#if _LIBCPP_STD_VER >= 23
template <_ContainerCompatibleRange<_Tp> _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<size_type>(ranges::distance(__range));
return __insert_with_size(__position, ranges::begin(__range), ranges::end(__range), __n);
} else {
return __insert_with_sentinel(__position, ranges::begin(__range), ranges::end(__range));
}
}
#endif
template <
class _ForwardIterator,
__enable_if_t<__is_cpp17_forward_iterator<_ForwardIterator>::value &&
@ -702,9 +779,51 @@ private:
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI
void __construct_at_end(size_type __n, const_reference __x);
template <class _ForwardIterator, __enable_if_t<__is_cpp17_forward_iterator<_ForwardIterator>::value, int> = 0>
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void
__construct_at_end(_ForwardIterator __first, _ForwardIterator __last, size_type __n);
template <class _InputIterator, class _Sentinel>
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI
void __init_with_size(_InputIterator __first, _Sentinel __last, size_type __n) {
auto __guard = std::__make_exception_guard(__destroy_vector(*this));
std::__debug_db_insert_c(this);
if (__n > 0) {
__vallocate(__n);
__construct_at_end(__first, __last, __n);
}
__guard.__complete();
}
template <class _InputIterator, class _Sentinel>
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI
void __init_with_sentinel(_InputIterator __first, _Sentinel __last) {
auto __guard = std::__make_exception_guard(__destroy_vector(*this));
std::__debug_db_insert_c(this);
for (; __first != __last; ++__first)
emplace_back(*__first);
__guard.__complete();
}
template <class _Iterator, class _Sentinel>
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI
void __assign_with_sentinel(_Iterator __first, _Sentinel __last);
template <class _ForwardIterator, class _Sentinel>
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI
void __assign_with_size(_ForwardIterator __first, _Sentinel __last, difference_type __n);
template <class _InputIterator, class _Sentinel>
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI
iterator __insert_with_sentinel(const_iterator __position, _InputIterator __first, _Sentinel __last);
template <class _Iterator, class _Sentinel>
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI
iterator __insert_with_size(const_iterator __position, _Iterator __first, _Sentinel __last, difference_type __n);
template <class _InputIterator, class _Sentinel>
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI
void __construct_at_end(_InputIterator __first, _Sentinel __last, size_type __n);
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __append(size_type __n);
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __append(size_type __n, const_reference __x);
@ -911,6 +1030,15 @@ vector(_InputIterator, _InputIterator, _Alloc)
-> vector<__iter_value_type<_InputIterator>, _Alloc>;
#endif
#if _LIBCPP_STD_VER >= 23
template <ranges::input_range _Range,
class _Alloc = allocator<ranges::range_value_t<_Range>>,
class = enable_if_t<__is_allocator<_Alloc>::value>
>
vector(from_range_t, _Range&&, _Alloc = _Alloc())
-> vector<ranges::range_value_t<_Range>, _Alloc>;
#endif
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_SINCE_CXX20
void
@ -1026,10 +1154,9 @@ vector<_Tp, _Allocator>::__construct_at_end(size_type __n, const_reference __x)
}
template <class _Tp, class _Allocator>
template <class _ForwardIterator, __enable_if_t<__is_cpp17_forward_iterator<_ForwardIterator>::value, int> >
template <class _InputIterator, class _Sentinel>
_LIBCPP_CONSTEXPR_SINCE_CXX20 void
vector<_Tp, _Allocator>::__construct_at_end(_ForwardIterator __first, _ForwardIterator __last, size_type __n)
{
vector<_Tp, _Allocator>::__construct_at_end(_InputIterator __first, _Sentinel __last, size_type __n) {
_ConstructTransaction __tx(*this, __n);
__tx.__pos_ = std::__uninitialized_allocator_copy(__alloc(), __first, __last, __tx.__pos_);
}
@ -1126,11 +1253,7 @@ template <class _InputIterator, __enable_if_t<__is_exactly_cpp17_input_iterator<
_LIBCPP_CONSTEXPR_SINCE_CXX20
vector<_Tp, _Allocator>::vector(_InputIterator __first, _InputIterator __last)
{
auto __guard = std::__make_exception_guard(__destroy_vector(*this));
std::__debug_db_insert_c(this);
for (; __first != __last; ++__first)
emplace_back(*__first);
__guard.__complete();
__init_with_sentinel(__first, __last);
}
template <class _Tp, class _Allocator>
@ -1141,11 +1264,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20
vector<_Tp, _Allocator>::vector(_InputIterator __first, _InputIterator __last, const allocator_type& __a)
: __end_cap_(nullptr, __a)
{
auto __guard = std::__make_exception_guard(__destroy_vector(*this));
std::__debug_db_insert_c(this);
for (; __first != __last; ++__first)
emplace_back(*__first);
__guard.__complete();
__init_with_sentinel(__first, __last);
}
template <class _Tp, class _Allocator>
@ -1155,15 +1274,8 @@ template <class _ForwardIterator, __enable_if_t<__is_cpp17_forward_iterator<_For
_LIBCPP_CONSTEXPR_SINCE_CXX20
vector<_Tp, _Allocator>::vector(_ForwardIterator __first, _ForwardIterator __last)
{
auto __guard = std::__make_exception_guard(__destroy_vector(*this));
std::__debug_db_insert_c(this);
size_type __n = static_cast<size_type>(std::distance(__first, __last));
if (__n > 0)
{
__vallocate(__n);
__construct_at_end(__first, __last, __n);
}
__guard.__complete();
size_type __n = static_cast<size_type>(std::distance(__first, __last));
__init_with_size(__first, __last, __n);
}
template <class _Tp, class _Allocator>
@ -1174,15 +1286,8 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20
vector<_Tp, _Allocator>::vector(_ForwardIterator __first, _ForwardIterator __last, const allocator_type& __a)
: __end_cap_(nullptr, __a)
{
auto __guard = std::__make_exception_guard(__destroy_vector(*this));
std::__debug_db_insert_c(this);
size_type __n = static_cast<size_type>(std::distance(__first, __last));
if (__n > 0)
{
__vallocate(__n);
__construct_at_end(__first, __last, __n);
}
__guard.__complete();
size_type __n = static_cast<size_type>(std::distance(__first, __last));
__init_with_size(__first, __last, __n);
}
template <class _Tp, class _Allocator>
@ -1190,15 +1295,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20
vector<_Tp, _Allocator>::vector(const vector& __x)
: __end_cap_(nullptr, __alloc_traits::select_on_container_copy_construction(__x.__alloc()))
{
auto __guard = std::__make_exception_guard(__destroy_vector(*this));
std::__debug_db_insert_c(this);
size_type __n = __x.size();
if (__n > 0)
{
__vallocate(__n);
__construct_at_end(__x.__begin_, __x.__end_, __n);
}
__guard.__complete();
__init_with_size(__x.__begin_, __x.__end_, __x.size());
}
template <class _Tp, class _Allocator>
@ -1206,15 +1303,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20
vector<_Tp, _Allocator>::vector(const vector& __x, const __type_identity_t<allocator_type>& __a)
: __end_cap_(nullptr, __a)
{
auto __guard = std::__make_exception_guard(__destroy_vector(*this));
std::__debug_db_insert_c(this);
size_type __n = __x.size();
if (__n > 0)
{
__vallocate(__n);
__construct_at_end(__x.__begin_, __x.__end_, __n);
}
__guard.__complete();
__init_with_size(__x.__begin_, __x.__end_, __x.size());
}
template <class _Tp, class _Allocator>
@ -1358,6 +1447,13 @@ template <class _InputIterator, __enable_if_t<__is_exactly_cpp17_input_iterator<
_LIBCPP_CONSTEXPR_SINCE_CXX20 void
vector<_Tp, _Allocator>::assign(_InputIterator __first, _InputIterator __last)
{
__assign_with_sentinel(__first, __last);
}
template <class _Tp, class _Allocator>
template <class _Iterator, class _Sentinel>
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI
void vector<_Tp, _Allocator>::__assign_with_sentinel(_Iterator __first, _Sentinel __last) {
clear();
for (; __first != __last; ++__first)
emplace_back(*__first);
@ -1370,22 +1466,27 @@ template <class _ForwardIterator, __enable_if_t<__is_cpp17_forward_iterator<_For
_LIBCPP_CONSTEXPR_SINCE_CXX20 void
vector<_Tp, _Allocator>::assign(_ForwardIterator __first, _ForwardIterator __last)
{
size_type __new_size = static_cast<size_type>(std::distance(__first, __last));
__assign_with_size(__first, __last, std::distance(__first, __last));
}
template <class _Tp, class _Allocator>
template <class _ForwardIterator, class _Sentinel>
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI
void vector<_Tp, _Allocator>::__assign_with_size(_ForwardIterator __first, _Sentinel __last, difference_type __n) {
size_type __new_size = static_cast<size_type>(__n);
if (__new_size <= capacity())
{
_ForwardIterator __mid = __last;
bool __growing = false;
if (__new_size > size())
{
__growing = true;
__mid = __first;
std::advance(__mid, size());
}
pointer __m = std::copy(__first, __mid, this->__begin_);
if (__growing)
_ForwardIterator __mid = std::next(__first, size());
std::copy(__first, __mid, this->__begin_);
__construct_at_end(__mid, __last, __new_size - size());
}
else
{
pointer __m = std::__copy<_ClassicAlgPolicy>(__first, __last, this->__begin_).second;
this->__destruct_at_end(__m);
}
}
else
{
@ -1815,7 +1916,6 @@ vector<_Tp, _Allocator>::insert(const_iterator __position, size_type __n, const_
}
return __make_iter(__p);
}
template <class _Tp, class _Allocator>
template <class _InputIterator, __enable_if_t<__is_exactly_cpp17_input_iterator<_InputIterator>::value &&
is_constructible<_Tp, typename iterator_traits<_InputIterator>::reference>::value,
@ -1823,8 +1923,17 @@ template <class _InputIterator, __enable_if_t<__is_exactly_cpp17_input_iterator<
_LIBCPP_CONSTEXPR_SINCE_CXX20 typename vector<_Tp, _Allocator>::iterator
vector<_Tp, _Allocator>::insert(const_iterator __position, _InputIterator __first, _InputIterator __last)
{
_LIBCPP_DEBUG_ASSERT(__get_const_db()->__find_c_from_i(std::addressof(__position)) == this,
"vector::insert(iterator, range) called with an iterator not referring to this vector");
return __insert_with_sentinel(__position, __first, __last);
}
template <class _Tp, class _Allocator>
template <class _InputIterator, class _Sentinel>
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI
typename vector<_Tp, _Allocator>::iterator
vector<_Tp, _Allocator>::__insert_with_sentinel(const_iterator __position, _InputIterator __first, _Sentinel __last) {
_LIBCPP_DEBUG_ASSERT(__get_const_db()->__find_c_from_i(std::addressof(__position)) == this,
"vector::insert called with an iterator not referring to this vector");
difference_type __off = __position - begin();
pointer __p = this->__begin_ + __off;
allocator_type& __a = this->__alloc();
@ -1840,7 +1949,7 @@ vector<_Tp, _Allocator>::insert(const_iterator __position, _InputIterator __firs
try
{
#endif // _LIBCPP_HAS_NO_EXCEPTIONS
__v.__construct_at_end(__first, __last);
__v.__construct_at_end_with_sentinel(std::move(__first), std::move(__last));
difference_type __old_size = __old_last - this->__begin_;
difference_type __old_p = __p - this->__begin_;
reserve(__recommend(size() + __v.size()));
@ -1868,17 +1977,27 @@ template <class _ForwardIterator, __enable_if_t<__is_cpp17_forward_iterator<_For
_LIBCPP_CONSTEXPR_SINCE_CXX20 typename vector<_Tp, _Allocator>::iterator
vector<_Tp, _Allocator>::insert(const_iterator __position, _ForwardIterator __first, _ForwardIterator __last)
{
return __insert_with_size(__position, __first, __last, std::distance(__first, __last));
}
template <class _Tp, class _Allocator>
template <class _Iterator, class _Sentinel>
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI
typename vector<_Tp, _Allocator>::iterator
vector<_Tp, _Allocator>::__insert_with_size(const_iterator __position, _Iterator __first, _Sentinel __last,
difference_type __n) {
_LIBCPP_DEBUG_ASSERT(__get_const_db()->__find_c_from_i(std::addressof(__position)) == this,
"vector::insert(iterator, range) called with an iterator not referring to this vector");
"vector::insert called with an iterator not referring to this vector");
auto __insertion_size = __n;
pointer __p = this->__begin_ + (__position - begin());
difference_type __n = std::distance(__first, __last);
if (__n > 0)
{
if (__n <= this->__end_cap() - this->__end_)
{
size_type __old_n = __n;
pointer __old_last = this->__end_;
_ForwardIterator __m = __last;
_Iterator __m = std::next(__first, __n);
difference_type __dx = this->__end_ - __p;
if (__n > __dx)
{
@ -1898,7 +2017,7 @@ vector<_Tp, _Allocator>::insert(const_iterator __position, _ForwardIterator __fi
{
allocator_type& __a = this->__alloc();
__split_buffer<value_type, allocator_type&> __v(__recommend(size() + __n), __p - this->__begin_, __a);
__v.__construct_at_end(__first, __last);
__v.__construct_at_end_with_size(__first, __insertion_size);
__p = __swap_out_circular_buffer(__v, __p);
}
}
@ -2146,6 +2265,23 @@ public:
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 vector(_ForwardIterator __first, _ForwardIterator __last, const allocator_type& __a,
typename enable_if<__is_cpp17_forward_iterator<_ForwardIterator>::value>::type* = 0);
#if _LIBCPP_STD_VER >= 23
template <_ContainerCompatibleRange<bool> _Range>
_LIBCPP_HIDE_FROM_ABI constexpr
vector(from_range_t, _Range&& __range, const allocator_type& __a = allocator_type())
: __begin_(nullptr),
__size_(0),
__cap_alloc_(0, static_cast<__storage_allocator>(__a)) {
if constexpr (ranges::forward_range<_Range> || ranges::sized_range<_Range>) {
auto __n = static_cast<size_type>(ranges::distance(__range));
__init_with_size(ranges::begin(__range), ranges::end(__range), __n);
} else {
__init_with_sentinel(ranges::begin(__range), ranges::end(__range));
}
}
#endif
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 vector(const vector& __v);
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 vector(const vector& __v, const allocator_type& __a);
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 vector& operator=(const vector& __v);
@ -2185,6 +2321,20 @@ public:
>::type
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 assign(_ForwardIterator __first, _ForwardIterator __last);
#if _LIBCPP_STD_VER >= 23
template <_ContainerCompatibleRange<bool> _Range>
_LIBCPP_HIDE_FROM_ABI
constexpr void assign_range(_Range&& __range) {
if constexpr (ranges::forward_range<_Range> || ranges::sized_range<_Range>) {
auto __n = static_cast<size_type>(ranges::distance(__range));
__assign_with_size(ranges::begin(__range), ranges::end(__range), __n);
} else {
__assign_with_sentinel(ranges::begin(__range), ranges::end(__range));
}
}
#endif
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void assign(size_type __n, const value_type& __x);
#ifndef _LIBCPP_CXX03_LANG
@ -2274,6 +2424,14 @@ public:
}
#endif
#if _LIBCPP_STD_VER >= 23
template <_ContainerCompatibleRange<bool> _Range>
_LIBCPP_HIDE_FROM_ABI
constexpr void append_range(_Range&& __range) {
insert_range(end(), std::forward<_Range>(__range));
}
#endif
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void pop_back() {--__size_;}
#if _LIBCPP_STD_VER >= 14
@ -2297,6 +2455,20 @@ public:
>::type
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 insert(const_iterator __position, _ForwardIterator __first, _ForwardIterator __last);
#if _LIBCPP_STD_VER >= 23
template <_ContainerCompatibleRange<bool> _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<size_type>(ranges::distance(__range));
return __insert_with_size(__position, ranges::begin(__range), ranges::end(__range), __n);
} else {
return __insert_with_sentinel(__position, ranges::begin(__range), ranges::end(__range));
}
}
#endif
#ifndef _LIBCPP_CXX03_LANG
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
iterator insert(const_iterator __position, initializer_list<value_type> __il)
@ -2334,6 +2506,53 @@ private:
std::__throw_out_of_range("vector");
}
template <class _InputIterator, class _Sentinel>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
void __init_with_size(_InputIterator __first, _Sentinel __last, size_type __n) {
auto __guard = std::__make_exception_guard(__destroy_vector(*this));
if (__n > 0) {
__vallocate(__n);
__construct_at_end(std::move(__first), std::move(__last), __n);
}
__guard.__complete();
}
template <class _InputIterator, class _Sentinel>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
void __init_with_sentinel(_InputIterator __first, _Sentinel __last) {
#ifndef _LIBCPP_HAS_NO_EXCEPTIONS
try {
#endif // _LIBCPP_HAS_NO_EXCEPTIONS
for (; __first != __last; ++__first)
push_back(*__first);
#ifndef _LIBCPP_HAS_NO_EXCEPTIONS
} catch (...) {
if (__begin_ != nullptr)
__storage_traits::deallocate(__alloc(), __begin_, __cap());
std::__debug_db_invalidate_all(this);
throw;
}
#endif // _LIBCPP_HAS_NO_EXCEPTIONS
}
template <class _Iterator, class _Sentinel>
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI
void __assign_with_sentinel(_Iterator __first, _Sentinel __last);
template <class _ForwardIterator, class _Sentinel>
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI
void __assign_with_size(_ForwardIterator __first, _Sentinel __last, difference_type __ns);
template <class _InputIterator, class _Sentinel>
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI
iterator __insert_with_sentinel(const_iterator __position, _InputIterator __first, _Sentinel __last);
template <class _Iterator, class _Sentinel>
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI
iterator __insert_with_size(const_iterator __position, _Iterator __first, _Sentinel __last, difference_type __n);
// Allocate space for __n objects
// throws length_error if __n > max_size()
// throws (probably bad_alloc) if memory run out
@ -2360,13 +2579,9 @@ private:
{return (__new_size + (__bits_per_word-1)) & ~((size_type)__bits_per_word-1);}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type __recommend(size_type __new_size) const;
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __construct_at_end(size_type __n, bool __x);
template <class _ForwardIterator>
typename enable_if
<
__is_cpp17_forward_iterator<_ForwardIterator>::value,
void
>::type
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __construct_at_end(_ForwardIterator __first, _ForwardIterator __last);
template <class _InputIterator, class _Sentinel>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
void __construct_at_end(_InputIterator __first, _Sentinel __last, size_type __n);
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __append(size_type __n, const_reference __x);
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
reference __make_ref(size_type __pos) _NOEXCEPT
@ -2496,17 +2711,11 @@ vector<bool, _Allocator>::__construct_at_end(size_type __n, bool __x)
}
template <class _Allocator>
template <class _ForwardIterator>
template <class _InputIterator, class _Sentinel>
_LIBCPP_CONSTEXPR_SINCE_CXX20
typename enable_if
<
__is_cpp17_forward_iterator<_ForwardIterator>::value,
void
>::type
vector<bool, _Allocator>::__construct_at_end(_ForwardIterator __first, _ForwardIterator __last)
{
void vector<bool, _Allocator>::__construct_at_end(_InputIterator __first, _Sentinel __last, size_type __n) {
size_type __old_size = this->__size_;
this->__size_ += std::distance(__first, __last);
this->__size_ += __n;
if (__old_size == 0 || ((__old_size - 1) / __bits_per_word) != ((this->__size_ - 1) / __bits_per_word))
{
if (this->__size_ <= __bits_per_word)
@ -2514,7 +2723,7 @@ vector<bool, _Allocator>::__construct_at_end(_ForwardIterator __first, _ForwardI
else
this->__begin_[(this->__size_ - 1) / __bits_per_word] = __storage_type(0);
}
std::copy(__first, __last, __make_iter(__old_size));
std::__copy<_ClassicAlgPolicy>(__first, __last, __make_iter(__old_size));
}
template <class _Allocator>
@ -2608,22 +2817,7 @@ vector<bool, _Allocator>::vector(_InputIterator __first, _InputIterator __last,
__size_(0),
__cap_alloc_(0, __default_init_tag())
{
#ifndef _LIBCPP_HAS_NO_EXCEPTIONS
try
{
#endif // _LIBCPP_HAS_NO_EXCEPTIONS
for (; __first != __last; ++__first)
push_back(*__first);
#ifndef _LIBCPP_HAS_NO_EXCEPTIONS
}
catch (...)
{
if (__begin_ != nullptr)
__storage_traits::deallocate(__alloc(), __begin_, __cap());
std::__debug_db_invalidate_all(this);
throw;
}
#endif // _LIBCPP_HAS_NO_EXCEPTIONS
__init_with_sentinel(__first, __last);
}
template <class _Allocator>
@ -2635,22 +2829,7 @@ vector<bool, _Allocator>::vector(_InputIterator __first, _InputIterator __last,
__size_(0),
__cap_alloc_(0, static_cast<__storage_allocator>(__a))
{
#ifndef _LIBCPP_HAS_NO_EXCEPTIONS
try
{
#endif // _LIBCPP_HAS_NO_EXCEPTIONS
for (; __first != __last; ++__first)
push_back(*__first);
#ifndef _LIBCPP_HAS_NO_EXCEPTIONS
}
catch (...)
{
if (__begin_ != nullptr)
__storage_traits::deallocate(__alloc(), __begin_, __cap());
std::__debug_db_invalidate_all(this);
throw;
}
#endif // _LIBCPP_HAS_NO_EXCEPTIONS
__init_with_sentinel(__first, __last);
}
template <class _Allocator>
@ -2662,14 +2841,8 @@ vector<bool, _Allocator>::vector(_ForwardIterator __first, _ForwardIterator __la
__size_(0),
__cap_alloc_(0, __default_init_tag())
{
auto __guard = std::__make_exception_guard(__destroy_vector(*this));
size_type __n = static_cast<size_type>(std::distance(__first, __last));
if (__n > 0)
{
__vallocate(__n);
__construct_at_end(__first, __last);
}
__guard.__complete();
auto __n = static_cast<size_type>(std::distance(__first, __last));
__init_with_size(__first, __last, __n);
}
template <class _Allocator>
@ -2681,14 +2854,8 @@ vector<bool, _Allocator>::vector(_ForwardIterator __first, _ForwardIterator __la
__size_(0),
__cap_alloc_(0, static_cast<__storage_allocator>(__a))
{
auto __guard = std::__make_exception_guard(__destroy_vector(*this));
size_type __n = static_cast<size_type>(std::distance(__first, __last));
if (__n > 0)
{
__vallocate(__n);
__construct_at_end(__first, __last);
}
__guard.__complete();
auto __n = static_cast<size_type>(std::distance(__first, __last));
__init_with_size(__first, __last, __n);
}
#ifndef _LIBCPP_CXX03_LANG
@ -2704,7 +2871,7 @@ vector<bool, _Allocator>::vector(initializer_list<value_type> __il)
if (__n > 0)
{
__vallocate(__n);
__construct_at_end(__il.begin(), __il.end());
__construct_at_end(__il.begin(), __il.end(), __n);
}
}
@ -2719,7 +2886,7 @@ vector<bool, _Allocator>::vector(initializer_list<value_type> __il, const alloca
if (__n > 0)
{
__vallocate(__n);
__construct_at_end(__il.begin(), __il.end());
__construct_at_end(__il.begin(), __il.end(), __n);
}
}
@ -2735,7 +2902,7 @@ vector<bool, _Allocator>::vector(const vector& __v)
if (__v.size() > 0)
{
__vallocate(__v.size());
__construct_at_end(__v.begin(), __v.end());
__construct_at_end(__v.begin(), __v.end(), __v.size());
}
}
@ -2749,7 +2916,7 @@ vector<bool, _Allocator>::vector(const vector& __v, const allocator_type& __a)
if (__v.size() > 0)
{
__vallocate(__v.size());
__construct_at_end(__v.begin(), __v.end());
__construct_at_end(__v.begin(), __v.end(), __v.size());
}
}
@ -2808,7 +2975,7 @@ vector<bool, _Allocator>::vector(vector&& __v, const __type_identity_t<allocator
else if (__v.size() > 0)
{
__vallocate(__v.size());
__construct_at_end(__v.begin(), __v.end());
__construct_at_end(__v.begin(), __v.end(), __v.size());
}
}
@ -2876,6 +3043,13 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 typename enable_if <__is_exactly_cpp17_input_itera
>::type
vector<bool, _Allocator>::assign(_InputIterator __first, _InputIterator __last)
{
__assign_with_sentinel(__first, __last);
}
template <class _Allocator>
template <class _Iterator, class _Sentinel>
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI
void vector<bool, _Allocator>::__assign_with_sentinel(_Iterator __first, _Sentinel __last) {
clear();
for (; __first != __last; ++__first)
push_back(*__first);
@ -2891,9 +3065,17 @@ typename enable_if
>::type
vector<bool, _Allocator>::assign(_ForwardIterator __first, _ForwardIterator __last)
{
clear();
difference_type __ns = std::distance(__first, __last);
__assign_with_size(__first, __last, std::distance(__first, __last));
}
template <class _Allocator>
template <class _ForwardIterator, class _Sentinel>
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI
void vector<bool, _Allocator>::__assign_with_size(_ForwardIterator __first, _Sentinel __last, difference_type __ns) {
_LIBCPP_ASSERT(__ns >= 0, "invalid range specified");
clear();
const size_t __n = static_cast<size_type>(__ns);
if (__n)
{
@ -2902,7 +3084,7 @@ vector<bool, _Allocator>::assign(_ForwardIterator __first, _ForwardIterator __la
__vdeallocate();
__vallocate(__n);
}
__construct_at_end(__first, __last);
__construct_at_end(__first, __last, __n);
}
}
@ -2916,7 +3098,7 @@ vector<bool, _Allocator>::reserve(size_type __n)
this->__throw_length_error();
vector __v(this->get_allocator());
__v.__vallocate(__n);
__v.__construct_at_end(this->begin(), this->end());
__v.__construct_at_end(this->begin(), this->end(), this->size());
swap(__v);
std::__debug_db_invalidate_all(this);
}
@ -3028,6 +3210,14 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 typename enable_if <__is_exactly_cpp17_input_itera
>::type
vector<bool, _Allocator>::insert(const_iterator __position, _InputIterator __first, _InputIterator __last)
{
return __insert_with_sentinel(__position, __first, __last);
}
template <class _Allocator>
template <class _InputIterator, class _Sentinel>
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI
typename vector<bool, _Allocator>::iterator
vector<bool, _Allocator>::__insert_with_sentinel(const_iterator __position, _InputIterator __first, _Sentinel __last) {
difference_type __off = __position - begin();
iterator __p = __const_iterator_cast(__position);
iterator __old_end = end();
@ -3043,7 +3233,7 @@ vector<bool, _Allocator>::insert(const_iterator __position, _InputIterator __fir
try
{
#endif // _LIBCPP_HAS_NO_EXCEPTIONS
__v.assign(__first, __last);
__v.__assign_with_sentinel(std::move(__first), std::move(__last));
difference_type __old_size = static_cast<difference_type>(__old_end - begin());
difference_type __old_p = __p - begin();
reserve(__recommend(size() + __v.size()));
@ -3073,7 +3263,15 @@ typename enable_if
>::type
vector<bool, _Allocator>::insert(const_iterator __position, _ForwardIterator __first, _ForwardIterator __last)
{
const difference_type __n_signed = std::distance(__first, __last);
return __insert_with_size(__position, __first, __last, std::distance(__first, __last));
}
template <class _Allocator>
template <class _ForwardIterator, class _Sentinel>
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI
typename vector<bool, _Allocator>::iterator
vector<bool, _Allocator>::__insert_with_size(const_iterator __position, _ForwardIterator __first, _Sentinel __last,
difference_type __n_signed) {
_LIBCPP_ASSERT(__n_signed >= 0, "invalid range specified");
const size_type __n = static_cast<size_type>(__n_signed);
iterator __r;
@ -3094,7 +3292,7 @@ vector<bool, _Allocator>::insert(const_iterator __position, _ForwardIterator __f
std::copy_backward(__position, cend(), __v.end());
swap(__v);
}
std::copy(__first, __last, __r);
std::__copy<_ClassicAlgPolicy>(__first, __last, __r);
return __r;
}

View File

@ -580,6 +580,7 @@ END-SCRIPT
#include <__ranges/as_rvalue_view.h> // expected-error@*:* {{use of private header from outside its module: '__ranges/as_rvalue_view.h'}}
#include <__ranges/common_view.h> // expected-error@*:* {{use of private header from outside its module: '__ranges/common_view.h'}}
#include <__ranges/concepts.h> // expected-error@*:* {{use of private header from outside its module: '__ranges/concepts.h'}}
#include <__ranges/container_compatible_range.h> // expected-error@*:* {{use of private header from outside its module: '__ranges/container_compatible_range.h'}}
#include <__ranges/copyable_box.h> // expected-error@*:* {{use of private header from outside its module: '__ranges/copyable_box.h'}}
#include <__ranges/counted.h> // expected-error@*:* {{use of private header from outside its module: '__ranges/counted.h'}}
#include <__ranges/dangling.h> // expected-error@*:* {{use of private header from outside its module: '__ranges/dangling.h'}}
@ -592,6 +593,7 @@ END-SCRIPT
#include <__ranges/enable_borrowed_range.h> // expected-error@*:* {{use of private header from outside its module: '__ranges/enable_borrowed_range.h'}}
#include <__ranges/enable_view.h> // expected-error@*:* {{use of private header from outside its module: '__ranges/enable_view.h'}}
#include <__ranges/filter_view.h> // expected-error@*:* {{use of private header from outside its module: '__ranges/filter_view.h'}}
#include <__ranges/from_range.h> // expected-error@*:* {{use of private header from outside its module: '__ranges/from_range.h'}}
#include <__ranges/iota_view.h> // expected-error@*:* {{use of private header from outside its module: '__ranges/iota_view.h'}}
#include <__ranges/istream_view.h> // expected-error@*:* {{use of private header from outside its module: '__ranges/istream_view.h'}}
#include <__ranges/join_view.h> // expected-error@*:* {{use of private header from outside its module: '__ranges/join_view.h'}}

View File

@ -0,0 +1,154 @@
//===----------------------------------------------------------------------===//
//
// 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 <cstddef>
#include <iterator>
#include <type_traits>
#include "min_allocator.h"
#include "test_allocator.h"
#include "test_iterators.h"
#include "test_macros.h"
#include "type_algorithms.h"
struct Empty {};
template <class T>
struct InputRange {
cpp20_input_iterator<T*> begin();
sentinel_wrapper<cpp20_input_iterator<T*>> end();
};
template <class Iter, class Sent, std::ranges::input_range Range>
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 <class Iter, class Sent, class T>
constexpr auto wrap_input(std::vector<T>& 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<KeyValue> {
std::size_t operator()(const KeyValue& kv) const {
return kv.key;
}
};
#if !defined(TEST_HAS_NO_EXCEPTIONS)
template <int N>
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;
}
}
// Defined to silence GCC warnings. For test purposes, only copy construction is considered `created_by_copying`.
ThrowingCopy& operator=(const ThrowingCopy& other) {
x = other.x;
return *this;
}
friend auto operator<=>(const ThrowingCopy&, const ThrowingCopy&) = default;
static void reset() {
created_by_copying = destroyed = 0;
}
};
template <int N>
struct std::hash<ThrowingCopy<N>> {
std::size_t operator()(const ThrowingCopy<N>& value) const {
return value.x;
}
};
template <int N>
bool ThrowingCopy<N>::throwing_enabled = true;
template <int N>
int ThrowingCopy<N>::created_by_copying = 0;
template <int N>
int ThrowingCopy<N>::destroyed = 0;
template <class T>
struct ThrowingAllocator {
using value_type = T;
using char_type = T;
using is_always_equal = std::false_type;
ThrowingAllocator() = default;
template <class U>
ThrowingAllocator(const ThrowingAllocator<U>&) {}
T* allocate(std::size_t) { throw 1; }
void deallocate(T*, std::size_t) {}
template <class U>
friend bool operator==(const ThrowingAllocator&, const ThrowingAllocator<U>&) {
return true;
}
};
#endif
template <class T, class Func>
constexpr void for_all_iterators_and_allocators(Func f) {
using Iterators = types::type_list<
cpp20_input_iterator<T*>,
forward_iterator<T*>,
bidirectional_iterator<T*>,
random_access_iterator<T*>,
contiguous_iterator<T*>,
T*
>;
types::for_each(Iterators{}, [=]<class Iter>() {
f.template operator()<Iter, sentinel_wrapper<Iter>, std::allocator<T>>();
f.template operator()<Iter, sentinel_wrapper<Iter>, test_allocator<T>>();
f.template operator()<Iter, sentinel_wrapper<Iter>, min_allocator<T>>();
f.template operator()<Iter, sentinel_wrapper<Iter>, safe_allocator<T>>();
if constexpr (std::sentinel_for<Iter, Iter>) {
f.template operator()<Iter, Iter, std::allocator<T>>();
f.template operator()<Iter, Iter, test_allocator<T>>();
f.template operator()<Iter, Iter, min_allocator<T>>();
f.template operator()<Iter, Iter, safe_allocator<T>>();
}
});
}
#endif // SUPPORT_FROM_RANGE_HELPERS_H

View File

@ -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 <algorithm>
#include <array>
#include <cassert>
#include <concepts>
#include <map>
#include <ranges>
#include <set>
#include <type_traits>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#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 T, std::size_t N = 32>
class Buffer {
public:
constexpr Buffer() = default;
constexpr Buffer(std::initializer_list<T> input) {
assert(input.size() <= N);
std::ranges::copy(input, data_);
size_ = input.size();
}
// Makes initializing `Buffer<char>` nicer -- allows writing `buf = "abc"` instead of `buf = {'a', 'b', 'c'}`.
// To make the two forms equivalent, omits the terminating null.
template <std::size_t N2>
constexpr Buffer(const char (&input) [N2])
requires std::same_as<T, char> {
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 <class T>
struct TestCase {
Buffer<T> initial;
std::size_t index = 0;
Buffer<T> input;
Buffer<T> expected;
};
template <class T, class PtrT, class Func>
constexpr void for_all_iterators_and_allocators(Func f) {
using Iterators = types::type_list<
cpp20_input_iterator<PtrT>,
forward_iterator<PtrT>,
bidirectional_iterator<PtrT>,
random_access_iterator<PtrT>,
contiguous_iterator<PtrT>,
PtrT
>;
types::for_each(Iterators{}, [=]<class Iter>() {
f.template operator()<Iter, sentinel_wrapper<Iter>, std::allocator<T>>();
f.template operator()<Iter, sentinel_wrapper<Iter>, test_allocator<T>>();
f.template operator()<Iter, sentinel_wrapper<Iter>, min_allocator<T>>();
f.template operator()<Iter, sentinel_wrapper<Iter>, safe_allocator<T>>();
if constexpr (std::sentinel_for<Iter, Iter>) {
f.template operator()<Iter, Iter, std::allocator<T>>();
f.template operator()<Iter, Iter, test_allocator<T>>();
f.template operator()<Iter, Iter, min_allocator<T>>();
f.template operator()<Iter, Iter, safe_allocator<T>>();
}
});
}
// 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 <class T, class PtrT, class Func>
constexpr void for_all_iterators_and_allocators_constexpr(Func f) {
using Iterators = types::type_list<
cpp20_input_iterator<PtrT>,
forward_iterator<PtrT>,
PtrT
>;
types::for_each(Iterators{}, [=]<class Iter>() {
f.template operator()<Iter, sentinel_wrapper<Iter>, std::allocator<T>>();
f.template operator()<Iter, sentinel_wrapper<Iter>, test_allocator<T>>();
f.template operator()<Iter, sentinel_wrapper<Iter>, min_allocator<T>>();
f.template operator()<Iter, sentinel_wrapper<Iter>, safe_allocator<T>>();
if constexpr (std::sentinel_for<Iter, Iter>) {
f.template operator()<Iter, Iter, std::allocator<T>>();
f.template operator()<Iter, Iter, test_allocator<T>>();
f.template operator()<Iter, Iter, min_allocator<T>>();
f.template operator()<Iter, Iter, safe_allocator<T>>();
}
});
}
#endif // SUPPORT_INSERT_RANGE_HELPERS_H

View File

@ -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 <algorithm>
#include <array>
#include <cassert>
#include <cstddef>
#include <iterator>
#include <ranges>
#include <utility>
#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 <class T>
concept HasSize = requires (const T& value) { value.size(); };
template <class Container, class Range>
concept HasFromRangeCtr = requires (Range&& range) {
Container(std::from_range, std::forward<Range>(range));
Container(std::from_range, std::forward<Range>(range), std::allocator<typename Container::value_type>());
};
template <template <class...> class Container, class T, class U>
constexpr bool test_constraints() {
// Input range with the same value type.
static_assert(HasFromRangeCtr<Container<T>, InputRange<T>>);
// Input range with a convertible value type.
static_assert(HasFromRangeCtr<Container<T>, InputRange<U>>);
// Input range with a non-convertible value type.
static_assert(!HasFromRangeCtr<Container<T>, InputRange<Empty>>);
// Not an input range.
static_assert(!HasFromRangeCtr<Container<T>, InputRangeNotDerivedFrom>);
static_assert(!HasFromRangeCtr<Container<T>, InputRangeNotIndirectlyReadable>);
static_assert(!HasFromRangeCtr<Container<T>, InputRangeNotInputOrOutputIterator>);
// Note: there are no constraints on the allocator (it's not a separate template type of the constructor)`.
return true;
}
// Note: `std::array` is used to avoid dealing with `vector<bool>`.
template <template <class ...> class Container,
class T,
class Iter,
class Sent,
class Alloc,
std::size_t N,
class ValidateFunc>
constexpr void test_sequence_container_with_input(std::array<T, N>&& input, ValidateFunc validate) {
auto in = wrap_input<Iter, Sent>(input);
{ // (range)
Container<T> c(std::from_range, in);
if constexpr (HasSize<Container<T>>) {
assert(c.size() == static_cast<std::size_t>(std::distance(c.begin(), c.end())));
}
assert(std::ranges::equal(in, c));
validate(c);
}
{ // (range, allocator)
Alloc alloc;
Container<T, Alloc> c(std::from_range, in, alloc);
assert(c.get_allocator() == alloc);
if constexpr (HasSize<Container<T, Alloc>>) {
assert(c.size() == static_cast<std::size_t>(std::distance(c.begin(), c.end())));
}
assert(std::ranges::equal(in, c));
validate(c);
}
}
template <template <class ...> class Container,
class T,
class Iter,
class Sent,
class Alloc,
class ValidateFunc>
constexpr void test_sequence_container(ValidateFunc validate) {
// Normal input.
test_sequence_container_with_input<Container, T, Iter, Sent, Alloc>(std::array{0, 5, 12, 7, -1, 8, 26}, validate);
// Empty input.
test_sequence_container_with_input<Container, T, Iter, Sent, Alloc>(std::array<int, 0>{}, validate);
// Single-element input.
test_sequence_container_with_input<Container, T, Iter, Sent, Alloc>(std::array{5}, validate);
}
template <template <class ...> class Container>
constexpr void test_sequence_container_move_only() {
MoveOnly input[5];
std::ranges::subrange in(std::move_iterator{input}, std::move_iterator{input + 5});
[[maybe_unused]] Container<MoveOnly> c(std::from_range, in);
}
template <class Iter,
class Sent,
class Alloc,
class ValidateFunc>
constexpr void test_vector_bool(ValidateFunc validate) {
// Normal input.
test_sequence_container_with_input<std::vector, bool, Iter, Sent, Alloc>(
std::array{true, false, false, true, false, true, true, true, false, true}, validate);
// Empty input.
test_sequence_container_with_input<std::vector, bool, Iter, Sent, Alloc>(std::array<bool, 0>{}, validate);
// Single-element input.
test_sequence_container_with_input<std::vector, bool, Iter, Sent, Alloc>(std::array{true}, validate);
}
template <template <class ...> class Container>
void test_exception_safety_throwing_copy() {
#if !defined(TEST_HAS_NO_EXCEPTIONS)
using T = ThrowingCopy<3>;
T::reset();
T in[5];
try {
Container<T> c(std::from_range, in);
assert(false); // The constructor call above should throw.
} catch (int) {
assert(T::created_by_copying == 3);
assert(T::destroyed == 2); // No destructor call for the partially-constructed element.
}
#endif
}
template <template <class ...> class Container, class T>
void test_exception_safety_throwing_allocator() {
#if !defined(TEST_HAS_NO_EXCEPTIONS)
T in[] = {0, 1};
try {
ThrowingAllocator<T> alloc;
globalMemCounter.reset();
Container<T, ThrowingAllocator<T>> c(std::from_range, in, alloc);
assert(false); // The constructor call above should throw.
} catch (int) {
assert(globalMemCounter.new_called == globalMemCounter.delete_called);
}
#endif
}
#endif // SUPPORT_FROM_RANGE_SEQUENCE_CONTAINERS_H

View File

@ -0,0 +1,827 @@
//===----------------------------------------------------------------------===//
//
// 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_SEQUENCE_CONTAINERS_H
#define SUPPORT_INSERT_RANGE_SEQUENCE_CONTAINERS_H
#include <algorithm>
#include <cassert>
#include <concepts>
#include <cstddef>
#include <initializer_list>
#include <ranges>
#include <type_traits>
#include <vector>
#include "../from_range_helpers.h"
#include "../insert_range_helpers.h"
#include "MoveOnly.h"
#include "almost_satisfies_types.h"
#include "count_new.h"
#include "min_allocator.h"
#include "test_allocator.h"
#include "test_iterators.h"
#include "test_macros.h"
#include "type_algorithms.h"
template <class Container, class Range>
concept HasInsertRange = requires (Container& c, Range&& range) {
c.insert_range(c.end(), range);
};
template <template <class...> class Container, class T, class U>
constexpr bool test_constraints_insert_range() {
// Input range with the same value type.
static_assert(HasInsertRange<Container<T>, InputRange<T>>);
// Input range with a convertible value type.
static_assert(HasInsertRange<Container<T>, InputRange<U>>);
// Input range with a non-convertible value type.
static_assert(!HasInsertRange<Container<T>, InputRange<Empty>>);
// Not an input range.
static_assert(!HasInsertRange<Container<T>, InputRangeNotDerivedFrom>);
static_assert(!HasInsertRange<Container<T>, InputRangeNotIndirectlyReadable>);
static_assert(!HasInsertRange<Container<T>, InputRangeNotInputOrOutputIterator>);
return true;
}
template <class Container, class Range>
concept HasAppendRange = requires (Container& c, Range&& range) {
c.append_range(range);
};
template <template <class...> class Container, class T, class U>
constexpr bool test_constraints_append_range() {
// Input range with the same value type.
static_assert(HasAppendRange<Container<T>, InputRange<T>>);
// Input range with a convertible value type.
static_assert(HasAppendRange<Container<T>, InputRange<U>>);
// Input range with a non-convertible value type.
static_assert(!HasAppendRange<Container<T>, InputRange<Empty>>);
// Not an input range.
static_assert(!HasAppendRange<Container<T>, InputRangeNotDerivedFrom>);
static_assert(!HasAppendRange<Container<T>, InputRangeNotIndirectlyReadable>);
static_assert(!HasAppendRange<Container<T>, InputRangeNotInputOrOutputIterator>);
return true;
}
template <class Container, class Range>
concept HasPrependRange = requires (Container& c, Range&& range) {
c.prepend_range(range);
};
template <template <class...> class Container, class T, class U>
constexpr bool test_constraints_prepend_range() {
// Input range with the same value type.
static_assert(HasPrependRange<Container<T>, InputRange<T>>);
// Input range with a convertible value type.
static_assert(HasPrependRange<Container<T>, InputRange<U>>);
// Input range with a non-convertible value type.
static_assert(!HasPrependRange<Container<T>, InputRange<Empty>>);
// Not an input range.
static_assert(!HasPrependRange<Container<T>, InputRangeNotDerivedFrom>);
static_assert(!HasPrependRange<Container<T>, InputRangeNotIndirectlyReadable>);
static_assert(!HasPrependRange<Container<T>, InputRangeNotInputOrOutputIterator>);
return true;
}
template <class Container, class Range>
concept HasAssignRange = requires (Container& c, Range&& range) {
c.assign_range(range);
};
template <template <class...> class Container, class T, class U>
constexpr bool test_constraints_assign_range() {
// Input range with the same value type.
static_assert(HasAssignRange<Container<T>, InputRange<T>>);
// Input range with a convertible value type.
static_assert(HasAssignRange<Container<T>, InputRange<U>>);
// Input range with a non-convertible value type.
static_assert(!HasAssignRange<Container<T>, InputRange<Empty>>);
// Not an input range.
static_assert(!HasAssignRange<Container<T>, InputRangeNotDerivedFrom>);
static_assert(!HasAssignRange<Container<T>, InputRangeNotIndirectlyReadable>);
static_assert(!HasAssignRange<Container<T>, InputRangeNotInputOrOutputIterator>);
return true;
}
// Empty container.
template <class T>
TestCase<T> constexpr EmptyContainer_EmptyRange {
.initial = {}, .index = 0, .input = {}, .expected = {}
};
// Note: specializations for `bool` still use `vector<int>` for inputs. This is to avoid dealing with `vector<bool>` and
// its iterators over proxy types.
template <> constexpr TestCase<int> EmptyContainer_EmptyRange<bool> {
.initial = {}, .index = 0, .input = {}, .expected = {}
};
template <class T> constexpr TestCase<T> EmptyContainer_OneElementRange;
template <> constexpr TestCase<int> EmptyContainer_OneElementRange<int> {
.initial = {}, .index = 0, .input = {5}, .expected = {5}
};
template <> constexpr TestCase<char> EmptyContainer_OneElementRange<char> {
.initial = {}, .index = 0, .input = "a", .expected = "a"
};
template <> constexpr TestCase<int> EmptyContainer_OneElementRange<bool> {
.initial = {}, .index = 0, .input = {true}, .expected = {true}
};
template <class T> constexpr TestCase<T> EmptyContainer_MidRange;
template <> constexpr TestCase<int> EmptyContainer_MidRange<int> {
.initial = {}, .index = 0, .input = {5, 3, 1, 7, 9}, .expected = {5, 3, 1, 7, 9}
};
template <> constexpr TestCase<char> EmptyContainer_MidRange<char> {
.initial = {}, .index = 0, .input = "aeiou", .expected = "aeiou"
};
template <> constexpr TestCase<int> EmptyContainer_MidRange<bool> {
.initial = {}, .index = 0, .input = {1, 1, 0, 1, 1}, .expected = {1, 1, 0, 1, 1}
};
// One-element container.
template <class T> constexpr TestCase<T> OneElementContainer_Begin_EmptyRange;
template <> constexpr TestCase<int> OneElementContainer_Begin_EmptyRange<int> {
.initial = {3}, .index = 0, .input = {}, .expected = {3}
};
template <> constexpr TestCase<char> OneElementContainer_Begin_EmptyRange<char> {
.initial = "B", .index = 0, .input = {}, .expected = "B"
};
template <> constexpr TestCase<int> OneElementContainer_Begin_EmptyRange<bool> {
.initial = {0}, .index = 0, .input = {}, .expected = {0}
};
template <class T> constexpr TestCase<T> OneElementContainer_End_EmptyRange;
template <> constexpr TestCase<int> OneElementContainer_End_EmptyRange<int> {
.initial = {3}, .index = 1, .input = {}, .expected = {3}
};
template <> constexpr TestCase<char> OneElementContainer_End_EmptyRange<char> {
.initial = "B", .index = 1, .input = {}, .expected = "B"
};
template <> constexpr TestCase<int> OneElementContainer_End_EmptyRange<bool> {
.initial = {0}, .index = 1, .input = {}, .expected = {0}
};
template <class T> constexpr TestCase<T> OneElementContainer_Begin_OneElementRange;
template <> constexpr TestCase<int> OneElementContainer_Begin_OneElementRange<int> {
.initial = {3}, .index = 0, .input = {-5}, .expected = {-5, 3}
};
template <> constexpr TestCase<char> OneElementContainer_Begin_OneElementRange<char> {
.initial = "B", .index = 0, .input = "a", .expected = "aB"
};
template <> constexpr TestCase<int> OneElementContainer_Begin_OneElementRange<bool> {
.initial = {0}, .index = 0, .input = {1}, .expected = {1, 0}
};
template <class T> constexpr TestCase<T> OneElementContainer_End_OneElementRange;
template <> constexpr TestCase<int> OneElementContainer_End_OneElementRange<int> {
.initial = {3}, .index = 1, .input = {-5}, .expected = {3, -5}
};
template <> constexpr TestCase<char> OneElementContainer_End_OneElementRange<char> {
.initial = "B", .index = 1, .input = "a", .expected = "Ba"
};
template <> constexpr TestCase<int> OneElementContainer_End_OneElementRange<bool> {
.initial = {0}, .index = 1, .input = {1}, .expected = {0, 1}
};
template <class T> constexpr TestCase<T> OneElementContainer_Begin_MidRange;
template <> constexpr TestCase<int> OneElementContainer_Begin_MidRange<int> {
.initial = {3}, .index = 0, .input = {-5, -3, -1, -7, -9}, .expected = {-5, -3, -1, -7, -9, 3}
};
template <> constexpr TestCase<char> OneElementContainer_Begin_MidRange<char> {
.initial = "B", .index = 0, .input = "aeiou", .expected = "aeiouB"
};
template <> constexpr TestCase<int> OneElementContainer_Begin_MidRange<bool> {
.initial = {0}, .index = 0, .input = {1, 1, 0, 1, 1}, .expected = {1, 1, 0, 1, 1, 0}
};
template <class T> constexpr TestCase<T> OneElementContainer_End_MidRange;
template <> constexpr TestCase<int> OneElementContainer_End_MidRange<int> {
.initial = {3}, .index = 1, .input = {-5, -3, -1, -7, -9}, .expected = {3, -5, -3, -1, -7, -9}
};
template <> constexpr TestCase<char> OneElementContainer_End_MidRange<char> {
.initial = "B", .index = 1, .input = "aeiou", .expected = "Baeiou"
};
template <> constexpr TestCase<int> OneElementContainer_End_MidRange<bool> {
.initial = {0}, .index = 1, .input = {1, 1, 0, 1, 1}, .expected = {0, 1, 1, 0, 1, 1}
};
// Full container / empty range.
template <class T> constexpr TestCase<T> FullContainer_Begin_EmptyRange;
template <> constexpr TestCase<int> FullContainer_Begin_EmptyRange<int> {
.initial = {11, 29, 35, 14, 84}, .index = 0, .input = {}, .expected = {11, 29, 35, 14, 84}
};
template <> constexpr TestCase<char> FullContainer_Begin_EmptyRange<char> {
.initial = "_BCD_", .index = 0, .input = {}, .expected = "_BCD_"
};
template <> constexpr TestCase<int> FullContainer_Begin_EmptyRange<bool> {
.initial = {0, 0, 1, 0, 0}, .index = 0, .input = {}, .expected = {0, 0, 1, 0, 0}
};
template <class T> constexpr TestCase<T> FullContainer_Mid_EmptyRange;
template <> constexpr TestCase<int> FullContainer_Mid_EmptyRange<int> {
.initial = {11, 29, 35, 14, 84}, .index = 2, .input = {}, .expected = {11, 29, 35, 14, 84}
};
template <> constexpr TestCase<char> FullContainer_Mid_EmptyRange<char> {
.initial = "_BCD_", .index = 2, .input = {}, .expected = "_BCD_"
};
template <> constexpr TestCase<int> FullContainer_Mid_EmptyRange<bool> {
.initial = {0, 0, 1, 0, 0}, .index = 2, .input = {}, .expected = {0, 0, 1, 0, 0}
};
template <class T> constexpr TestCase<T> FullContainer_End_EmptyRange;
template <> constexpr TestCase<int> FullContainer_End_EmptyRange<int> {
.initial = {11, 29, 35, 14, 84}, .index = 5, .input = {}, .expected = {11, 29, 35, 14, 84}
};
template <> constexpr TestCase<char> FullContainer_End_EmptyRange<char> {
.initial = "_BCD_", .index = 5, .input = {}, .expected = "_BCD_"
};
template <> constexpr TestCase<int> FullContainer_End_EmptyRange<bool> {
.initial = {0, 0, 1, 0, 0}, .index = 5, .input = {}, .expected = {0, 0, 1, 0, 0}
};
// Full container / one-element range.
template <class T> constexpr TestCase<T> FullContainer_Begin_OneElementRange;
template <> constexpr TestCase<int> FullContainer_Begin_OneElementRange<int> {
.initial = {11, 29, 35, 14, 84}, .index = 0, .input = {-5}, .expected = {-5, 11, 29, 35, 14, 84}
};
template <> constexpr TestCase<char> FullContainer_Begin_OneElementRange<char> {
.initial = "_BCD_", .index = 0, .input = "a", .expected = "a_BCD_"
};
template <> constexpr TestCase<int> FullContainer_Begin_OneElementRange<bool> {
.initial = {0, 0, 1, 0, 0}, .index = 0, .input = {1}, .expected = {1, 0, 0, 1, 0, 0}
};
template <class T> constexpr TestCase<T> FullContainer_Mid_OneElementRange;
template <> constexpr TestCase<int> FullContainer_Mid_OneElementRange<int> {
.initial = {11, 29, 35, 14, 84}, .index = 2, .input = {-5}, .expected = {11, 29, -5, 35, 14, 84}
};
template <> constexpr TestCase<char> FullContainer_Mid_OneElementRange<char> {
.initial = "_BCD_", .index = 2, .input = "a", .expected = "_BaCD_"
};
template <> constexpr TestCase<int> FullContainer_Mid_OneElementRange<bool> {
.initial = {0, 0, 1, 0, 0}, .index = 2, .input = {1}, .expected = {0, 0, 1, 1, 0, 0}
};
template <class T> constexpr TestCase<T> FullContainer_End_OneElementRange;
template <> constexpr TestCase<int> FullContainer_End_OneElementRange<int> {
.initial = {11, 29, 35, 14, 84}, .index = 5, .input = {-5}, .expected = {11, 29, 35, 14, 84, -5}
};
template <> constexpr TestCase<char> FullContainer_End_OneElementRange<char> {
.initial = "_BCD_", .index = 5, .input = "a", .expected = "_BCD_a"
};
template <> constexpr TestCase<int> FullContainer_End_OneElementRange<bool> {
.initial = {0, 0, 1, 0, 0}, .index = 5, .input = {1}, .expected = {0, 0, 1, 0, 0, 1}
};
// Full container / mid-sized range.
template <class T> constexpr TestCase<T> FullContainer_Begin_MidRange;
template <> constexpr TestCase<int> FullContainer_Begin_MidRange<int> {
.initial = {11, 29, 35, 14, 84},
.index = 0,
.input = {-5, -3, -1, -7, -9},
.expected = {-5, -3, -1, -7, -9, 11, 29, 35, 14, 84}
};
template <> constexpr TestCase<char> FullContainer_Begin_MidRange<char> {
.initial = "_BCD_",
.index = 0,
.input = "aeiou",
.expected = "aeiou_BCD_"
};
template <> constexpr TestCase<int> FullContainer_Begin_MidRange<bool> {
.initial = {0, 0, 1, 0, 1},
.index = 0,
.input = {1, 1, 0, 1, 1},
.expected = {1, 1, 0, 1, 1, 0, 0, 1, 0, 1}
};
template <class T> constexpr TestCase<T> FullContainer_Mid_MidRange;
template <> constexpr TestCase<int> FullContainer_Mid_MidRange<int> {
.initial = {11, 29, 35, 14, 84},
.index = 2,
.input = {-5, -3, -1, -7, -9},
.expected = {11, 29, -5, -3, -1, -7, -9, 35, 14, 84}
};
template <> constexpr TestCase<char> FullContainer_Mid_MidRange<char> {
.initial = "_BCD_",
.index = 2,
.input = "aeiou",
.expected = "_BaeiouCD_"
};
template <> constexpr TestCase<int> FullContainer_Mid_MidRange<bool> {
.initial = {0, 0, 1, 0, 1},
.index = 2,
.input = {1, 1, 0, 1, 1},
.expected = {0, 0, 1, 1, 0, 1, 1, 1, 0, 1}
};
template <class T> constexpr TestCase<T> FullContainer_End_MidRange;
template <> constexpr TestCase<int> FullContainer_End_MidRange<int> {
.initial = {11, 29, 35, 14, 84},
.index = 5,
.input = {-5, -3, -1, -7, -9},
.expected = {11, 29, 35, 14, 84, -5, -3, -1, -7, -9}
};
template <> constexpr TestCase<char> FullContainer_End_MidRange<char> {
.initial = "_BCD_",
.index = 5,
.input = "aeiou",
.expected = "_BCD_aeiou"
};
template <> constexpr TestCase<int> FullContainer_End_MidRange<bool> {
.initial = {0, 0, 1, 0, 1},
.index = 5,
.input = {1, 1, 0, 1, 1},
.expected = {0, 0, 1, 0, 1, 1, 1, 0, 1, 1}
};
// Full container / long range.
template <class T> constexpr TestCase<T> FullContainer_Begin_LongRange;
template <> constexpr TestCase<int> FullContainer_Begin_LongRange<int> {
.initial = {11, 29, 35, 14, 84},
.index = 0,
.input = {-5, -3, -1, -7, -9, -19, -48, -56, -13, -14, -29, -88, -17, -1, -5, -11, -89, -21, -33, -48},
.expected = {
-5, -3, -1, -7, -9, -19, -48, -56, -13, -14, -29, -88, -17, -1, -5, -11, -89, -21, -33, -48, 11, 29, 35, 14, 84
}
};
template <> constexpr TestCase<char> FullContainer_Begin_LongRange<char> {
.initial = "_BCD_",
.index = 0,
.input = "aeiouqwxyz5781964203",
.expected = "aeiouqwxyz5781964203_BCD_"
};
template <> constexpr TestCase<int> FullContainer_Begin_LongRange<bool> {
.initial = {0, 0, 1, 0, 0},
.index = 0,
.input = {1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0},
.expected = {
1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0
}
};
template <class T> constexpr TestCase<T> FullContainer_Mid_LongRange;
template <> constexpr TestCase<int> FullContainer_Mid_LongRange<int> {
.initial = {11, 29, 35, 14, 84},
.index = 2,
.input = {-5, -3, -1, -7, -9, -19, -48, -56, -13, -14, -29, -88, -17, -1, -5, -11, -89, -21, -33, -48},
.expected = {
11, 29, -5, -3, -1, -7, -9, -19, -48, -56, -13, -14, -29, -88, -17, -1, -5, -11, -89, -21, -33, -48, 35, 14, 84
}
};
template <> constexpr TestCase<char> FullContainer_Mid_LongRange<char> {
.initial = "_BCD_",
.index = 2,
.input = "aeiouqwxyz5781964203",
.expected = "_Baeiouqwxyz5781964203CD_"
};
template <> constexpr TestCase<int> FullContainer_Mid_LongRange<bool> {
.initial = {0, 0, 1, 0, 0},
.index = 2,
.input = {1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0},
.expected = {
0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0
}
};
template <class T> constexpr TestCase<T> FullContainer_End_LongRange;
template <> constexpr TestCase<int> FullContainer_End_LongRange<int> {
.initial = {11, 29, 35, 14, 84},
.index = 5,
.input = {-5, -3, -1, -7, -9, -19, -48, -56, -13, -14, -29, -88, -17, -1, -5, -11, -89, -21, -33, -48},
.expected = {
11, 29, 35, 14, 84, -5, -3, -1, -7, -9, -19, -48, -56, -13, -14, -29, -88, -17, -1, -5, -11, -89, -21, -33, -48
}
};
template <> constexpr TestCase<char> FullContainer_End_LongRange<char> {
.initial = "_BCD_",
.index = 5,
.input = "aeiouqwxyz5781964203",
.expected = "_BCD_aeiouqwxyz5781964203"
};
template <> constexpr TestCase<int> FullContainer_End_LongRange<bool> {
.initial = {0, 0, 1, 0, 1},
.index = 5,
.input = {1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0},
.expected = {
0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0
}
};
// Sequence containers tests.
template <class Container, class Iter, class Sent, class Validate>
constexpr void test_sequence_insert_range(Validate validate) {
using T = typename Container::value_type;
auto get_pos = [](auto& c, auto& test_case) { return std::ranges::next(c.begin(), test_case.index); };
auto test = [&](auto& test_case) {
Container c(test_case.initial.begin(), test_case.initial.end());
auto in = wrap_input<Iter, Sent>(test_case.input);
auto pos = get_pos(c, test_case);
auto result = c.insert_range(pos, in);
assert(result == get_pos(c, test_case));
validate(c);
return std::ranges::equal(c, test_case.expected);
};
{ // Empty container.
// empty_c.insert_range(end, empty_range)
assert(test(EmptyContainer_EmptyRange<T>));
// empty_c.insert_range(end, one_element_range)
assert(test(EmptyContainer_OneElementRange<T>));
// empty_c.insert_range(end, mid_range)
assert(test(EmptyContainer_MidRange<T>));
}
{ // One-element container.
// one_element_c.insert_range(begin, empty_range)
assert(test(OneElementContainer_Begin_EmptyRange<T>));
// one_element_c.insert_range(end, empty_range)
assert(test(OneElementContainer_End_EmptyRange<T>));
// one_element_c.insert_range(begin, one_element_range)
assert(test(OneElementContainer_Begin_OneElementRange<T>));
// one_element_c.insert_range(end, one_element_range)
assert(test(OneElementContainer_End_OneElementRange<T>));
// one_element_c.insert_range(begin, mid_range)
assert(test(OneElementContainer_Begin_MidRange<T>));
// one_element_c.insert_range(end, mid_range)
assert(test(OneElementContainer_End_MidRange<T>));
}
{ // Full container.
// full_container.insert_range(begin, empty_range)
assert(test(FullContainer_Begin_EmptyRange<T>));
// full_container.insert_range(mid, empty_range)
assert(test(FullContainer_Mid_EmptyRange<T>));
// full_container.insert_range(end, empty_range)
assert(test(FullContainer_End_EmptyRange<T>));
// full_container.insert_range(begin, one_element_range)
assert(test(FullContainer_Begin_OneElementRange<T>));
// full_container.insert_range(end, one_element_range)
assert(test(FullContainer_Mid_OneElementRange<T>));
// full_container.insert_range(end, one_element_range)
assert(test(FullContainer_End_OneElementRange<T>));
// full_container.insert_range(begin, mid_range)
assert(test(FullContainer_Begin_MidRange<T>));
// full_container.insert_range(mid, mid_range)
assert(test(FullContainer_Mid_MidRange<T>));
// full_container.insert_range(end, mid_range)
assert(test(FullContainer_End_MidRange<T>));
// full_container.insert_range(begin, long_range)
assert(test(FullContainer_Begin_LongRange<T>));
// full_container.insert_range(mid, long_range)
assert(test(FullContainer_Mid_LongRange<T>));
// full_container.insert_range(end, long_range)
assert(test(FullContainer_End_LongRange<T>));
}
}
template <class Container, class Iter, class Sent, class Validate>
constexpr void test_sequence_prepend_range(Validate validate) {
using T = typename Container::value_type;
auto test = [&](auto& test_case) {
Container c(test_case.initial.begin(), test_case.initial.end());
auto in = wrap_input<Iter, Sent>(test_case.input);
c.prepend_range(in);
validate(c);
return std::ranges::equal(c, test_case.expected);
};
{ // Empty container.
// empty_c.prepend_range(empty_range)
assert(test(EmptyContainer_EmptyRange<T>));
// empty_c.prepend_range(one_element_range)
assert(test(EmptyContainer_OneElementRange<T>));
// empty_c.prepend_range(mid_range)
assert(test(EmptyContainer_MidRange<T>));
}
{ // One-element container.
// one_element_c.prepend_range(empty_range)
assert(test(OneElementContainer_Begin_EmptyRange<T>));
// one_element_c.prepend_range(one_element_range)
assert(test(OneElementContainer_Begin_OneElementRange<T>));
// one_element_c.prepend_range(mid_range)
assert(test(OneElementContainer_Begin_MidRange<T>));
}
{ // Full container.
// full_container.prepend_range(empty_range)
assert(test(FullContainer_Begin_EmptyRange<T>));
// full_container.prepend_range(one_element_range)
assert(test(FullContainer_Begin_OneElementRange<T>));
// full_container.prepend_range(mid_range)
assert(test(FullContainer_Begin_MidRange<T>));
// full_container.prepend_range(long_range)
assert(test(FullContainer_Begin_LongRange<T>));
}
}
template <class Container, class Iter, class Sent, class Validate>
constexpr void test_sequence_append_range(Validate validate) {
using T = typename Container::value_type;
auto test = [&](auto& test_case) {
Container c(test_case.initial.begin(), test_case.initial.end());
auto in = wrap_input<Iter, Sent>(test_case.input);
c.append_range(in);
validate(c);
return std::ranges::equal(c, test_case.expected);
};
{ // Empty container.
// empty_c.append_range(empty_range)
assert(test(EmptyContainer_EmptyRange<T>));
// empty_c.append_range(one_element_range)
assert(test(EmptyContainer_OneElementRange<T>));
// empty_c.append_range(mid_range)
assert(test(EmptyContainer_MidRange<T>));
}
{ // One-element container.
// one_element_c.append_range(empty_range)
assert(test(OneElementContainer_End_EmptyRange<T>));
// one_element_c.append_range(one_element_range)
assert(test(OneElementContainer_End_OneElementRange<T>));
// one_element_c.append_range(mid_range)
assert(test(OneElementContainer_End_MidRange<T>));
}
{ // Full container.
// full_container.append_range(empty_range)
assert(test(FullContainer_End_EmptyRange<T>));
// full_container.append_range(one_element_range)
assert(test(FullContainer_End_OneElementRange<T>));
// full_container.append_range(mid_range)
assert(test(FullContainer_End_MidRange<T>));
// full_container.append_range(long_range)
assert(test(FullContainer_End_LongRange<T>));
}
}
template <class Container, class Iter, class Sent, class Validate>
constexpr void test_sequence_assign_range(Validate validate) {
using T = typename Container::value_type;
auto& initial_empty = EmptyContainer_EmptyRange<T>.initial;
auto& initial_one_element = OneElementContainer_Begin_EmptyRange<T>.initial;
auto& initial_full = FullContainer_Begin_EmptyRange<T>.initial;
auto& input_empty = FullContainer_Begin_EmptyRange<T>.input;
auto& input_one_element = FullContainer_Begin_OneElementRange<T>.input;
auto& input_mid_range = FullContainer_Begin_MidRange<T>.input;
auto& input_long_range = FullContainer_Begin_LongRange<T>.input;
auto test = [&](auto& initial, auto& input) {
Container c(initial.begin(), initial.end());
auto in = wrap_input<Iter, Sent>(input);
c.assign_range(in);
validate(c);
return std::ranges::equal(c, input);
};
{ // Empty container.
// empty_container.assign_range(empty_range)
assert(test(initial_empty, input_empty));
// empty_container.assign_range(one_element_range)
assert(test(initial_empty, input_one_element));
// empty_container.assign_range(mid_range)
assert(test(initial_empty, input_mid_range));
// empty_container.assign_range(long_range)
assert(test(initial_empty, input_long_range));
}
{ // One-element container.
// one_element_container.assign_range(empty_range)
assert(test(initial_one_element, input_empty));
// one_element_container.assign_range(one_element_range)
assert(test(initial_one_element, input_one_element));
// one_element_container.assign_range(mid_range)
assert(test(initial_one_element, input_mid_range));
// one_element_container.assign_range(long_range)
assert(test(initial_one_element, input_long_range));
}
{ // Full container.
// full_container.assign_range(empty_range)
assert(test(initial_full, input_empty));
// full_container.assign_range(one_element_range)
assert(test(initial_full, input_one_element));
// full_container.assign_range(mid_range)
assert(test(initial_full, input_mid_range));
// full_container.assign_range(long_range)
assert(test(initial_full, input_long_range));
}
}
// Move-only types.
template <template <class ...> class Container>
constexpr void test_sequence_insert_range_move_only() {
MoveOnly input[5];
std::ranges::subrange in(std::move_iterator{input}, std::move_iterator{input + 5});
Container<MoveOnly> c;
c.insert_range(c.end(), in);
}
template <template <class ...> class Container>
constexpr void test_sequence_prepend_range_move_only() {
MoveOnly input[5];
std::ranges::subrange in(std::move_iterator{input}, std::move_iterator{input + 5});
Container<MoveOnly> c;
c.prepend_range(in);
}
template <template <class ...> class Container>
constexpr void test_sequence_append_range_move_only() {
MoveOnly input[5];
std::ranges::subrange in(std::move_iterator{input}, std::move_iterator{input + 5});
Container<MoveOnly> c;
c.append_range(in);
}
template <template <class ...> class Container>
constexpr void test_sequence_assign_range_move_only() {
MoveOnly input[5];
std::ranges::subrange in(std::move_iterator{input}, std::move_iterator{input + 5});
Container<MoveOnly> c;
c.assign_range(in);
}
// Exception safety.
template <template <class ...> class Container>
void test_insert_range_exception_safety_throwing_copy() {
#if !defined(TEST_HAS_NO_EXCEPTIONS)
using T = ThrowingCopy<3>;
T::reset();
T in[5];
try {
Container<T> c;
c.insert_range(c.end(), in);
assert(false); // The function call above should throw.
} catch (int) {
assert(T::created_by_copying == 3);
assert(T::destroyed == 2); // No destructor call for the partially-constructed element.
}
#endif
}
template <template <class ...> class Container, class T>
void test_insert_range_exception_safety_throwing_allocator() {
#if !defined(TEST_HAS_NO_EXCEPTIONS)
T in[] = {0, 1};
try {
ThrowingAllocator<T> alloc;
globalMemCounter.reset();
Container<T, ThrowingAllocator<T>> c(alloc);
c.insert_range(c.end(), in);
assert(false); // The function call above should throw.
} catch (int) {
assert(globalMemCounter.new_called == globalMemCounter.delete_called);
}
#endif
}
template <template <class ...> class Container>
void test_prepend_range_exception_safety_throwing_copy() {
#if !defined(TEST_HAS_NO_EXCEPTIONS)
using T = ThrowingCopy<3>;
T::reset();
T in[5];
try {
Container<T> c;
c.prepend_range(in);
assert(false); // The function call above should throw.
} catch (int) {
assert(T::created_by_copying == 3);
assert(T::destroyed == 2); // No destructor call for the partially-constructed element.
}
#endif
}
template <template <class ...> class Container, class T>
void test_prepend_range_exception_safety_throwing_allocator() {
#if !defined(TEST_HAS_NO_EXCEPTIONS)
T in[] = {0, 1};
try {
ThrowingAllocator<T> alloc;
globalMemCounter.reset();
Container<T, ThrowingAllocator<T>> c(alloc);
c.prepend_range(in);
assert(false); // The function call above should throw.
} catch (int) {
assert(globalMemCounter.new_called == globalMemCounter.delete_called);
}
#endif
}
template <template <class ...> class Container>
void test_append_range_exception_safety_throwing_copy() {
#if !defined(TEST_HAS_NO_EXCEPTIONS)
using T = ThrowingCopy<3>;
T::reset();
T in[5];
try {
Container<T> c;
c.append_range(in);
assert(false); // The function call above should throw.
} catch (int) {
assert(T::created_by_copying == 3);
assert(T::destroyed == 2); // No destructor call for the partially-constructed element.
}
#endif
}
template <template <class ...> class Container, class T>
void test_append_range_exception_safety_throwing_allocator() {
#if !defined(TEST_HAS_NO_EXCEPTIONS)
T in[] = {0, 1};
try {
ThrowingAllocator<T> alloc;
globalMemCounter.reset();
Container<T, ThrowingAllocator<T>> c(alloc);
c.append_range(in);
assert(false); // The function call above should throw.
} catch (int) {
assert(globalMemCounter.new_called == globalMemCounter.delete_called);
}
#endif
}
template <template <class ...> class Container>
void test_assign_range_exception_safety_throwing_copy() {
#if !defined(TEST_HAS_NO_EXCEPTIONS)
using T = ThrowingCopy<3>;
T::reset();
T in[5];
try {
Container<T> c;
c.assign_range(in);
assert(false); // The function call above should throw.
} catch (int) {
assert(T::created_by_copying == 3);
assert(T::destroyed == 2); // No destructor call for the partially-constructed element.
}
#endif
}
template <template <class ...> class Container, class T>
void test_assign_range_exception_safety_throwing_allocator() {
#if !defined(TEST_HAS_NO_EXCEPTIONS)
T in[] = {0, 1};
try {
ThrowingAllocator<T> alloc;
globalMemCounter.reset();
Container<T, ThrowingAllocator<T>> c(alloc);
c.assign_range(in);
assert(false); // The function call above should throw.
} catch (int) {
assert(globalMemCounter.new_called == globalMemCounter.delete_called);
}
#endif
}
#endif // SUPPORT_INSERT_RANGE_SEQUENCE_CONTAINERS_H

View File

@ -0,0 +1,72 @@
//===----------------------------------------------------------------------===//
//
// 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(has-fconstexpr-steps): -fconstexpr-steps=2000000
// template<container-compatible-range<bool> R>
// constexpr void append_range(R&& rg); // C++23
#include <vector>
#include "../insert_range_sequence_containers.h"
#include "test_macros.h"
// Tested cases:
// - different kinds of insertions (appending an {empty/one-element/mid-sized/long range} into an
// {empty/one-element/full} container);
// - an exception is thrown when allocating new elements.
constexpr bool test() {
static_assert(test_constraints_append_range<std::vector, bool, char>());
for_all_iterators_and_allocators<bool, const int*>([]<class Iter, class Sent, class Alloc>() {
test_sequence_append_range<std::vector<bool, Alloc>, Iter, Sent>([](auto&& c) {
LIBCPP_ASSERT(c.__invariants());
// `is_contiguous_container_asan_correct` doesn't work on `vector<bool>`.
});
});
{ // Vector may or may not need to reallocate because of the insertion -- make sure to test both cases.
{ // Ensure reallocation happens.
constexpr int N = 255;
bool in[N] = {};
std::vector<bool> v = {0, 0, 0, 1, 1, 0, 0, 0};
auto initial = v;
assert(v.capacity() < v.size() + std::ranges::size(in));
v.append_range(in);
// Because `in` is very large (it has to be to exceed the large capacity that `vector<bool>` allocates), it is
// impractical to have the expected value as a literal.
assert(v.size() == initial.size() + N);
assert(std::ranges::equal(v.begin(), v.begin() + initial.size(), initial.begin(), initial.end()));
assert(std::ranges::equal(v.begin() + initial.size(), v.end(), std::ranges::begin(in), std::ranges::end(in)));
}
{ // Ensure no reallocation happens.
bool in[] = {1, 1, 1, 1, 0, 0, 1, 1, 1, 1};
std::vector<bool> v = {0, 0, 0, 1, 1, 0, 0, 0};
v.reserve(v.size() + std::ranges::size(in));
assert(v.capacity() >= v.size() + std::ranges::size(in));
v.append_range(in);
assert(std::ranges::equal(v, std::vector<bool>{0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1}));
}
}
return true;
}
int main(int, char**) {
test();
static_assert(test());
// Note: `test_append_range_exception_safety_throwing_copy` doesn't apply because copying booleans cannot throw.
test_append_range_exception_safety_throwing_allocator<std::vector, bool>();
return 0;
}

View File

@ -0,0 +1,65 @@
//===----------------------------------------------------------------------===//
//
// 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(has-fconstexpr-steps): -fconstexpr-steps=2000000
// template<container-compatible-range<bool> R>
// constexpr void assign_range(R&& rg); // C++23
#include <vector>
#include "../insert_range_sequence_containers.h"
#include "test_macros.h"
// Tested cases:
// - different kinds of assignments (assigning an {empty/one-element/mid-sized/long range} to an
// {empty/one-element/full} container);
// - an exception is thrown when allocating new elements.
constexpr bool test() {
static_assert(test_constraints_assign_range<std::vector, bool, char>());
for_all_iterators_and_allocators<bool, const int*>([]<class Iter, class Sent, class Alloc>() {
test_sequence_assign_range<std::vector<bool, Alloc>, Iter, Sent>([](auto&& c) {
LIBCPP_ASSERT(c.__invariants());
// `is_contiguous_container_asan_correct` doesn't work on `vector<bool>`.
});
});
{ // Vector may or may not need to reallocate because of the assignment -- make sure to test both cases.
{ // Ensure reallocation happens. Note that `vector<bool>` typically reserves a lot of capacity.
constexpr int N = 255;
bool in[N] = {};
std::vector<bool> v = {0, 0, 0, 1, 1, 0, 0, 0};
assert(v.capacity() < v.size() + std::ranges::size(in));
v.assign_range(in);
assert(std::ranges::equal(v, in));
}
{ // Ensure no reallocation happens.
bool in[] = {1, 1, 0, 1, 1};
std::vector<bool> v = {0, 0, 0, 1, 1, 0, 0, 0};
v.assign_range(in);
assert(std::ranges::equal(v, in));
}
}
return true;
}
int main(int, char**) {
test();
static_assert(test());
// Note: `test_assign_range_exception_safety_throwing_copy` doesn't apply because copying booleans cannot throw.
test_assign_range_exception_safety_throwing_allocator<std::vector, bool>();
return 0;
}

View File

@ -0,0 +1,40 @@
//===----------------------------------------------------------------------===//
//
// 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
#include <vector>
#include "../from_range_sequence_containers.h"
#include "test_macros.h"
// template<container-compatible-range<T> R>
// vector(from_range_t, R&& rg, const Allocator& = Allocator()); // C++23
constexpr bool test() {
for_all_iterators_and_allocators<bool>([]<class Iter, class Sent, class Alloc>() {
test_vector_bool<Iter, Sent, Alloc>([](const auto& c) {
LIBCPP_ASSERT(c.__invariants());
// `is_contiguous_container_asan_correct` doesn't work on `vector<bool>`.
});
});
return true;
}
int main(int, char**) {
test();
static_assert(test());
static_assert(test_constraints<std::vector, bool, char>());
// Note: test_exception_safety_throwing_copy doesn't apply because copying a boolean cannot throw.
test_exception_safety_throwing_allocator<std::vector, bool>();
return 0;
}

View File

@ -0,0 +1,72 @@
//===----------------------------------------------------------------------===//
//
// 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(has-fconstexpr-steps): -fconstexpr-steps=2000000
// template<container-compatible-range<bool> R>
// constexpr iterator insert_range(const_iterator position, R&& rg); // C++23
#include <vector>
#include "../insert_range_sequence_containers.h"
#include "test_macros.h"
// Tested cases:
// - different kinds of insertions (inserting an {empty/one-element/mid-sized/long range} into an
// {empty/one-element/full} container at the {beginning/middle/end});
// - an exception is thrown when allocating new elements.
constexpr bool test() {
static_assert(test_constraints_insert_range<std::vector, bool, char>());
for_all_iterators_and_allocators<bool, const int*>([]<class Iter, class Sent, class Alloc>() {
test_sequence_insert_range<std::vector<bool, Alloc>, Iter, Sent>([](auto&& c) {
LIBCPP_ASSERT(c.__invariants());
// `is_contiguous_container_asan_correct` doesn't work on `vector<bool>`.
});
});
{ // Vector may or may not need to reallocate because of the insertion -- make sure to test both cases.
{ // Ensure reallocation happens.
constexpr int N = 255;
bool in[N] = {};
std::vector<bool> v = {0, 0, 0, 1, 1, 0, 0, 0};
auto initial = v;
assert(v.capacity() < v.size() + std::ranges::size(in));
v.insert_range(v.end(), in);
// Because `in` is very large (it has to be to exceed the large capacity that `vector<bool>` allocates), it is
// impractical to have the expected value as a literal.
assert(v.size() == initial.size() + N);
assert(std::ranges::equal(v.begin(), v.begin() + initial.size(), initial.begin(), initial.end()));
assert(std::ranges::equal(v.begin() + initial.size(), v.end(), std::ranges::begin(in), std::ranges::end(in)));
}
{ // Ensure no reallocation happens.
bool in[] = {1, 1, 1, 1, 0, 0, 1, 1, 1, 1};
std::vector<bool> v = {0, 0, 0, 1, 1, 0, 0, 0};
v.reserve(v.size() + std::ranges::size(in));
assert(v.capacity() >= v.size() + std::ranges::size(in));
v.insert_range(v.end(), in);
assert(std::ranges::equal(v, std::vector<bool>{0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1}));
}
}
return true;
}
int main(int, char**) {
test();
static_assert(test());
// Note: `test_insert_range_exception_safety_throwing_copy` doesn't apply because copying booleans cannot throw.
test_insert_range_exception_safety_throwing_allocator<std::vector, bool>();
return 0;
}

View File

@ -0,0 +1,42 @@
//===----------------------------------------------------------------------===//
//
// 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<container-compatible-range<T> R>
// vector(from_range_t, R&& rg, const Allocator& = Allocator()); // C++23
#include <vector>
#include "../../from_range_sequence_containers.h"
#include "asan_testing.h"
#include "test_macros.h"
constexpr bool test() {
for_all_iterators_and_allocators<int>([]<class Iter, class Sent, class Alloc>() {
test_sequence_container<std::vector, int, Iter, Sent, Alloc>([](const auto& c) {
LIBCPP_ASSERT(c.__invariants());
LIBCPP_ASSERT(is_contiguous_container_asan_correct(c));
});
});
test_sequence_container_move_only<std::vector>();
return true;
}
int main(int, char**) {
static_assert(test_constraints<std::vector, int, double>());
test();
static_assert(test());
test_exception_safety_throwing_copy<std::vector>();
test_exception_safety_throwing_allocator<std::vector, int>();
return 0;
}

View File

@ -13,14 +13,18 @@
// vector(InputIterator, InputIterator, Allocator = Allocator())
// -> vector<typename iterator_traits<InputIterator>::value_type, Allocator>;
//
// template<ranges::input_range R, class Allocator = allocator<ranges::range_value_t<R>>>
// vector(from_range_t, R&&, Allocator = Allocator())
// -> vector<ranges::range_value_t<R>, Allocator>; // C++23
#include <algorithm>
#include <vector>
#include <array>
#include <cassert>
#include <cstddef>
#include <climits> // INT_MAX
#include <cstddef>
#include <iterator>
#include <type_traits>
#include <vector>
#include "deduction_guides_sfinae_checks.h"
#include "test_macros.h"
@ -94,6 +98,20 @@ TEST_CONSTEXPR_CXX20 bool tests() {
assert(vec.size() == 0);
}
#if TEST_STD_VER >= 23
{
{
std::vector c(std::from_range, std::array<int, 0>());
static_assert(std::is_same_v<decltype(c), std::vector<int>>);
}
{
using Alloc = test_allocator<int>;
std::vector c(std::from_range, std::array<int, 0>(), Alloc());
static_assert(std::is_same_v<decltype(c), std::vector<int, Alloc>>);
}
}
#endif
// A couple of vector<bool> tests, too!
{

View File

@ -177,6 +177,7 @@ int main(int, char**) {
Allocator<int> alloc(false);
AllocVec vec(cpp17_input_iterator<int*>(a), cpp17_input_iterator<int*>(a + 2), alloc);
} catch (int) {
// FIXME: never called.
}
check_new_delete_called();
@ -185,6 +186,7 @@ int main(int, char**) {
Allocator<int> alloc(false);
AllocVec vec(forward_iterator<int*>(a), forward_iterator<int*>(a + 2), alloc);
} catch (int) {
// FIXME: never called.
}
check_new_delete_called();

View File

@ -0,0 +1,70 @@
//===----------------------------------------------------------------------===//
//
// 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(has-fconstexpr-steps): -fconstexpr-steps=2000000
// template<container-compatible-range<T> R>
// constexpr void append_range(R&& rg); // C++23
#include <vector>
#include "../../insert_range_sequence_containers.h"
#include "asan_testing.h"
#include "test_macros.h"
// Tested cases:
// - different kinds of insertions (appending an {empty/one-element/mid-sized/long range} into an
// {empty/one-element/full} container);
// - appending move-only elements;
// - an exception is thrown when copying the elements or when allocating new elements.
constexpr bool test() {
static_assert(test_constraints_append_range<std::vector, int, double>());
for_all_iterators_and_allocators<int, const int*>([]<class Iter, class Sent, class Alloc>() {
test_sequence_append_range<std::vector<int, Alloc>, Iter, Sent>([](auto&& c) {
LIBCPP_ASSERT(c.__invariants());
LIBCPP_ASSERT(is_contiguous_container_asan_correct(c));
});
});
test_sequence_append_range_move_only<std::vector>();
{ // Vector may or may not need to reallocate because of the insertion -- make sure to test both cases.
{ // Ensure reallocation happens.
int in[] = {-1, -2, -3, -4, -5, -6, -7, -8, -9, -10};
std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8};
v.shrink_to_fit();
assert(v.capacity() < v.size() + std::ranges::size(in));
v.append_range(in);
assert(std::ranges::equal(v, std::array{1, 2, 3, 4, 5, 6, 7, 8, -1, -2, -3, -4, -5, -6, -7, -8, -9, -10}));
}
{ // Ensure no reallocation happens.
int in[] = {-1, -2, -3, -4, -5, -6, -7, -8, -9, -10};
std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8};
v.reserve(v.size() + std::ranges::size(in));
assert(v.capacity() >= v.size() + std::ranges::size(in));
v.append_range(in);
assert(std::ranges::equal(v, std::array{1, 2, 3, 4, 5, 6, 7, 8, -1, -2, -3, -4, -5, -6, -7, -8, -9, -10}));
}
}
return true;
}
int main(int, char**) {
test();
static_assert(test());
test_append_range_exception_safety_throwing_copy<std::vector>();
test_append_range_exception_safety_throwing_allocator<std::vector, int>();
return 0;
}

View File

@ -0,0 +1,78 @@
//===----------------------------------------------------------------------===//
//
// 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(has-fconstexpr-steps): -fconstexpr-steps=2000000
// template<container-compatible-range<T> R>
// constexpr void assign_range(R&& rg); // C++23
#include <vector>
#include "../../insert_range_sequence_containers.h"
#include "asan_testing.h"
#include "test_macros.h"
// Tested cases:
// - different kinds of assignments (assigning an {empty/one-element/mid-sized/long range} to an
// {empty/one-element/full} container);
// - assigning move-only elements;
// - an exception is thrown when copying the elements or when allocating new elements.
constexpr bool test() {
static_assert(test_constraints_assign_range<std::vector, int, double>());
for_all_iterators_and_allocators<int, const int*>([]<class Iter, class Sent, class Alloc>() {
test_sequence_assign_range<std::vector<int, Alloc>, Iter, Sent>([](auto&& c) {
LIBCPP_ASSERT(c.__invariants());
LIBCPP_ASSERT(is_contiguous_container_asan_correct(c));
});
});
test_sequence_assign_range_move_only<std::vector>();
{ // Vector may or may not need to reallocate because of the assignment -- make sure to test both cases.
{ // Ensure reallocation happens.
int in[] = {-1, -2, -3, -4, -5, -6, -7, -8, -9, -10};
std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8};
v.shrink_to_fit();
assert(v.capacity() < v.size() + std::ranges::size(in));
v.assign_range(in);
assert(std::ranges::equal(v, in));
}
{ // Ensure no reallocation happens -- the input range is shorter than the vector.
int in[] = {-1, -2, -3, -4, -5};
std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8};
v.assign_range(in);
assert(std::ranges::equal(v, in));
}
{ // Ensure no reallocation happens -- the input range is longer than the vector but within capacity.
int in[] = {-1, -2, -3, -4, -5, -6, -7, -8};
std::vector<int> v = {1, 2, 3, 4, 5};
v.reserve(std::ranges::size(in));
assert(v.capacity() >= std::ranges::size(in));
v.assign_range(in);
assert(std::ranges::equal(v, in));
}
}
return true;
}
int main(int, char**) {
test();
static_assert(test());
test_assign_range_exception_safety_throwing_copy<std::vector>();
test_assign_range_exception_safety_throwing_allocator<std::vector, int>();
return 0;
}

View File

@ -0,0 +1,71 @@
//===----------------------------------------------------------------------===//
//
// 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(has-fconstexpr-steps): -fconstexpr-steps=2000000
// template<container-compatible-range<T> R>
// constexpr iterator insert_range(const_iterator position, R&& rg); // C++23
#include <vector>
#include "../../insert_range_sequence_containers.h"
#include "asan_testing.h"
#include "test_macros.h"
// Tested cases:
// - different kinds of insertions (inserting an {empty/one-element/mid-sized/long range} into an
// {empty/one-element/full} container at the {beginning/middle/end});
// - inserting move-only elements;
// - an exception is thrown when copying the elements or when allocating new elements.
constexpr bool test() {
for_all_iterators_and_allocators<int, const int*>([]<class Iter, class Sent, class Alloc>() {
test_sequence_insert_range<std::vector<int, Alloc>, Iter, Sent>([](auto&& c) {
LIBCPP_ASSERT(c.__invariants());
LIBCPP_ASSERT(is_contiguous_container_asan_correct(c));
});
});
test_sequence_insert_range_move_only<std::vector>();
{ // Vector may or may not need to reallocate because of the insertion -- make sure to test both cases.
{ // Ensure reallocation happens.
int in[] = {-1, -2, -3, -4, -5, -6, -7, -8, -9, -10};
std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8};
v.shrink_to_fit();
assert(v.capacity() < v.size() + std::ranges::size(in));
v.insert_range(v.end(), in);
assert(std::ranges::equal(v, std::array{1, 2, 3, 4, 5, 6, 7, 8, -1, -2, -3, -4, -5, -6, -7, -8, -9, -10}));
}
{ // Ensure no reallocation happens.
int in[] = {-1, -2, -3, -4, -5, -6, -7, -8, -9, -10};
std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8};
v.reserve(v.size() + std::ranges::size(in));
assert(v.capacity() >= v.size() + std::ranges::size(in));
v.insert_range(v.end(), in);
assert(std::ranges::equal(v, std::array{1, 2, 3, 4, 5, 6, 7, 8, -1, -2, -3, -4, -5, -6, -7, -8, -9, -10}));
}
}
return true;
}
int main(int, char**) {
test();
static_assert(test());
static_assert(test_constraints_insert_range<std::vector, int, double>());
test_insert_range_exception_safety_throwing_copy<std::vector>();
test_insert_range_exception_safety_throwing_allocator<std::vector, int>();
return 0;
}

View File

@ -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
// struct from_range_t { explicit from_range_t() = default; }; // Since C++23
// inline constexpr from_range_t from_range{}; // Since C++23
#include <ranges>
template <class T>
void check(std::from_range_t);
template <class T>
concept IsCtrNonexplicit = requires {
check<T>({});
};
// Verify that the constructor is `explicit`.
static_assert(!IsCtrNonexplicit<std::from_range_t>);

View File

@ -18,6 +18,25 @@
#include <utility>
#include "test_macros.h"
#if TEST_STD_VER >= 23
#include "almost_satisfies_types.h"
#endif
#if TEST_STD_VER >= 23
template <class T>
struct RangeT {
T* begin();
T* end();
};
static_assert(std::ranges::input_range<RangeT<int>>);
template <class T>
using BadRangeT = InputRangeNotDerivedFromGeneric<T>;
static_assert(std::ranges::range<BadRangeT<int>>);
static_assert(!std::ranges::input_range<BadRangeT<int>>);
#endif
// `SFINAEs_away` template variable checks whether the template arguments for
// a given template class `Instantiated` can be deduced from the given
@ -34,17 +53,20 @@ template<template<typename ...> class Instantiated, class ...CtrArgs>
constexpr bool SFINAEs_away =
decltype(SFINAEs_away_impl<Instantiated, CtrArgs...>(0))::value;
struct Empty {};
// For sequence containers the deduction guides should be SFINAE'd away when
// given:
// - "bad" input iterators (that is, a type not qualifying as an input
// iterator);
// - a bad allocator.
template<template<typename ...> class Container, typename InstantiatedContainer>
// - a bad allocator;
// - a range not satisfying the `input_range` concept.
template<template<typename ...> class Container, typename InstantiatedContainer, typename BadAlloc = Empty>
constexpr void SequenceContainerDeductionGuidesSfinaeAway() {
using Alloc = std::allocator<int>;
using Iter = int*;
using T = typename InstantiatedContainer::value_type;
using Alloc = std::allocator<T>;
using Iter = T*;
struct BadAlloc {};
// Note: the only requirement in the Standard is that integral types cannot be
// considered input iterators; however, this doesn't work for sequence
// containers because they have constructors of the form `(size_type count,
@ -70,6 +92,20 @@ constexpr void SequenceContainerDeductionGuidesSfinaeAway() {
//
// Cannot deduce from (alloc)
static_assert(SFINAEs_away<Container, Alloc>);
#if TEST_STD_VER >= 23
using BadRange = BadRangeT<T>;
// (from_range, range)
//
// Cannot deduce from (BAD_range)
static_assert(SFINAEs_away<Container, std::from_range_t, BadRange>);
// (from_range, range, alloc)
//
// Cannot deduce from (range, BAD_alloc)
static_assert(SFINAEs_away<Container, std::from_range_t, RangeT<int>, BadAlloc>);
#endif
}
// For associative containers the deduction guides should be SFINAE'd away when