Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
20 changes: 11 additions & 9 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 @@ -832,7 +833,7 @@ public:
_LIBCPP_HIDE_FROM_ABI iterator insert_range(const_iterator __position, _Range&& __range) {
if constexpr (ranges::bidirectional_range<_Range>) {
auto __n = static_cast<size_type>(ranges::distance(__range));
return __insert_bidirectional(__position, ranges::begin(__range), ranges::end(__range), __n);
return __insert_bidirectional<_RangeAlgPolicy>(__position, ranges::begin(__range), ranges::end(__range), __n);

} else if constexpr (ranges::forward_range<_Range> || ranges::sized_range<_Range>) {
auto __n = static_cast<size_type>(ranges::distance(__range));
Expand Down Expand Up @@ -1202,10 +1203,10 @@ private:
template <class _Iterator>
_LIBCPP_HIDE_FROM_ABI iterator __insert_with_size(const_iterator __p, _Iterator __f, size_type __n);

template <class _BiIter, class _Sentinel>
template <class _AlgPolicy, class _BiIter, class _Sentinel>
_LIBCPP_HIDE_FROM_ABI iterator
__insert_bidirectional(const_iterator __p, _BiIter __f, _Sentinel __sent, size_type __n);
template <class _BiIter>
template <class _AlgPolicy, class _BiIter>
_LIBCPP_HIDE_FROM_ABI iterator __insert_bidirectional(const_iterator __p, _BiIter __f, _BiIter __l, size_type __n);

template <class _InpIter, __enable_if_t<__has_exactly_input_iterator_category<_InpIter>::value, int> = 0>
Expand Down Expand Up @@ -1902,20 +1903,21 @@ deque<_Tp, _Allocator>::__insert_with_size(const_iterator __p, _Iterator __f, si
template <class _Tp, class _Allocator>
template <class _BiIter, __enable_if_t<__has_bidirectional_iterator_category<_BiIter>::value, int> >
typename deque<_Tp, _Allocator>::iterator deque<_Tp, _Allocator>::insert(const_iterator __p, _BiIter __f, _BiIter __l) {
return __insert_bidirectional(__p, __f, __l, std::distance(__f, __l));
return __insert_bidirectional<_ClassicAlgPolicy>(__p, __f, __l, std::distance(__f, __l));
}

template <class _Tp, class _Allocator>
template <class _BiIter, class _Sentinel>
template <class _AlgPolicy, class _BiIter, class _Sentinel>
_LIBCPP_HIDE_FROM_ABI typename deque<_Tp, _Allocator>::iterator
deque<_Tp, _Allocator>::__insert_bidirectional(const_iterator __p, _BiIter __f, _Sentinel, size_type __n) {
return __insert_bidirectional(__p, __f, std::next(__f, __n), __n);
return __insert_bidirectional<_AlgPolicy>(__p, __f, _IterOps<_AlgPolicy>::next(__f, __n), __n);
}

template <class _Tp, class _Allocator>
template <class _BiIter>
template <class _AlgPolicy, 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) {
using _Ops = _IterOps<_AlgPolicy>;
size_type __pos = __p - begin();
size_type __to_end = size() - __pos;
allocator_type& __a = __alloc();
Expand All @@ -1928,7 +1930,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 +1957,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
38 changes: 38 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,41 @@ constexpr auto wrap_input(std::vector<T>& input) {
return std::ranges::subrange(std::move(b), std::move(e));
}

// https://llvm.org/PR159943
// Verify container insertion/assignment from ranges whose iterators dereference to prvalues.
// Especially, `std::prev` should be avoided when inserting such a `bidirectional_range`.
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
Loading
Loading