Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions libcxx/include/deque
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ template <class T, class Allocator, class Predicate>
# include <__algorithm/copy_n.h>
# include <__algorithm/equal.h>
# include <__algorithm/fill_n.h>
# include <__algorithm/iterator_operations.h>
# include <__algorithm/lexicographical_compare.h>
# include <__algorithm/lexicographical_compare_three_way.h>
# include <__algorithm/max.h>
Expand Down Expand Up @@ -1916,6 +1917,12 @@ template <class _Tp, class _Allocator>
template <class _BiIter>
_LIBCPP_HIDE_FROM_ABI typename deque<_Tp, _Allocator>::iterator
deque<_Tp, _Allocator>::__insert_bidirectional(const_iterator __p, _BiIter __f, _BiIter __l, size_type __n) {
# if _LIBCPP_STD_VER >= 20
using _Ops = _IterOps<
conditional_t<__has_bidirectional_iterator_category<_BiIter>::value, _ClassicAlgPolicy, _RangeAlgPolicy>>;
# else
using _Ops = _IterOps<_ClassicAlgPolicy>;
# endif
size_type __pos = __p - begin();
size_type __to_end = size() - __pos;
allocator_type& __a = __alloc();
Expand All @@ -1928,7 +1935,7 @@ deque<_Tp, _Allocator>::__insert_bidirectional(const_iterator __p, _BiIter __f,
iterator __i = __old_begin;
_BiIter __m = __f;
if (__n > __pos) {
__m = __pos < __n / 2 ? std::prev(__l, __pos) : std::next(__f, __n - __pos);
__m = __pos < __n / 2 ? _Ops::prev(__l, __pos) : _Ops::next(__f, __n - __pos);
for (_BiIter __j = __m; __j != __f; --__start_, ++__size())
__alloc_traits::construct(__a, std::addressof(*--__i), *--__j);
__n = __pos;
Expand All @@ -1955,7 +1962,7 @@ deque<_Tp, _Allocator>::__insert_bidirectional(const_iterator __p, _BiIter __f,
_BiIter __m = __l;
size_type __de = size() - __pos;
if (__n > __de) {
__m = __de < __n / 2 ? std::next(__f, __de) : std::prev(__l, __n - __de);
__m = __de < __n / 2 ? _Ops::next(__f, __de) : _Ops::prev(__l, __n - __de);
for (_BiIter __j = __m; __j != __l; ++__i, (void)++__j, ++__size())
__alloc_traits::construct(__a, std::addressof(*__i), *__j);
__n = __de;
Expand Down
36 changes: 36 additions & 0 deletions libcxx/test/std/containers/from_range_helpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,12 @@
#define SUPPORT_FROM_RANGE_HELPERS_H

#include <array>
#include <concepts>
#include <cstddef>
#include <iterator>
#include <ranges>
#include <type_traits>
#include <utility>
#include <vector>

#include "min_allocator.h"
Expand Down Expand Up @@ -50,6 +53,39 @@ constexpr auto wrap_input(std::vector<T>& input) {
return std::ranges::subrange(std::move(b), std::move(e));
}

// https://llvm.org/PR159943
struct DecayCopy {
template <class T>
requires std::convertible_to<T, std::decay_t<T>>
static constexpr std::decay_t<T> operator()(T&& t) {
return std::forward<T>(t);
}
};

template <class Iter, class Sent, std::ranges::input_range Range>
constexpr auto wrap_input_decay(Range&& input) {
auto b = Iter(std::ranges::begin(input));
auto e = Sent(Iter(std::ranges::end(input)));
if constexpr (std::is_reference_v<std::iter_reference_t<Iter>>)
return std::ranges::subrange(std::move(b), std::move(e)) | std::views::transform(DecayCopy{});
else
return std::ranges::subrange(std::move(b), std::move(e));
}

template <class Iter, class Sent, class T, std::size_t N>
constexpr auto wrap_input_decay(std::array<T, N>& input) {
auto b = Iter(input.data());
auto e = Sent(Iter(input.data() + input.size()));
return std::ranges::subrange(std::move(b), std::move(e)) | std::views::transform(DecayCopy{});
}

template <class Iter, class Sent, class T>
constexpr auto wrap_input_decay(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)) | std::views::transform(DecayCopy{});
}

struct KeyValue {
int key; // Only the key is considered for equality comparison.
char value; // Allows distinguishing equivalent instances.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ int main(int, char**) {
test_sequence_append_range<std::deque<int, Alloc>, Iter, Sent>([]([[maybe_unused]] auto&& c) {
LIBCPP_ASSERT(c.__invariants());
});
test_sequence_append_range_decay<std::deque<int, Alloc>, Iter, Sent>([]([[maybe_unused]] auto&& c) {
LIBCPP_ASSERT(c.__invariants());
});
});
test_sequence_append_range_move_only<std::deque>();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ int main(int, char**) {
test_sequence_assign_range<std::deque<int, Alloc>, Iter, Sent>([]([[maybe_unused]] auto&& c) {
LIBCPP_ASSERT(c.__invariants());
});
test_sequence_assign_range_decay<std::deque<int, Alloc>, Iter, Sent>([]([[maybe_unused]] auto&& c) {
LIBCPP_ASSERT(c.__invariants());
});
});
test_sequence_assign_range_move_only<std::deque>();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ int main(int, char**) {
test_sequence_insert_range<std::deque<int, Alloc>, Iter, Sent>([]([[maybe_unused]] auto&& c) {
LIBCPP_ASSERT(c.__invariants());
});
test_sequence_insert_range_decay<std::deque<int, Alloc>, Iter, Sent>([]([[maybe_unused]] auto&& c) {
LIBCPP_ASSERT(c.__invariants());
});
});
test_sequence_insert_range_move_only<std::deque>();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ int main(int, char**) {
test_sequence_prepend_range<std::deque<int, Alloc>, Iter, Sent>([]([[maybe_unused]] auto&& c) {
LIBCPP_ASSERT(c.__invariants());
});
test_sequence_prepend_range_decay<std::deque<int, Alloc>, Iter, Sent>([]([[maybe_unused]] auto&& c) {
LIBCPP_ASSERT(c.__invariants());
});
});
test_sequence_prepend_range_move_only<std::deque>();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -464,6 +464,76 @@ constexpr void test_sequence_insert_range(Validate validate) {
}
}

// https://llvm.org/PR159943
template <class Container, class Iter, class Sent, class Validate>
constexpr void test_sequence_insert_range_decay(Validate validate) {
using T = Container::value_type;
using D = Container::difference_type;
auto get_pos = [](auto& c, auto& test_case) { return std::ranges::next(c.begin(), static_cast<D>(test_case.index)); };

auto test = [&](auto& test_case) {
Container c(test_case.initial.begin(), test_case.initial.end());
auto in = wrap_input_decay<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;
Expand Down Expand Up @@ -507,6 +577,50 @@ constexpr void test_sequence_prepend_range(Validate validate) {
}
}

// https://llvm.org/PR159943
template <class Container, class Iter, class Sent, class Validate>
constexpr void test_sequence_prepend_range_decay(Validate validate) {
using T = Container::value_type;

auto test = [&](auto& test_case) {
Container c(test_case.initial.begin(), test_case.initial.end());
auto in = wrap_input_decay<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;
Expand Down Expand Up @@ -550,6 +664,50 @@ constexpr void test_sequence_append_range(Validate validate) {
}
}

// https://llvm.org/PR159943
template <class Container, class Iter, class Sent, class Validate>
constexpr void test_sequence_append_range_decay(Validate validate) {
using T = Container::value_type;

auto test = [&](auto& test_case) {
Container c(test_case.initial.begin(), test_case.initial.end());
auto in = wrap_input_decay<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;
Expand Down Expand Up @@ -605,6 +763,62 @@ constexpr void test_sequence_assign_range(Validate validate) {
}
}

// https://llvm.org/PR159943
template <class Container, class Iter, class Sent, class Validate>
constexpr void test_sequence_assign_range_decay(Validate validate) {
using T = 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_decay<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>
Expand Down
Loading