[libc++][ranges] Implement the changes to container adaptors from P1206 (ranges::to):
- add the `from_range_t` constructors and the related deduction guides; - add the `push_range` member function. (Note: this patch is split from https://reviews.llvm.org/D142335) Reviewed By: #libc, ldionne Differential Revision: https://reviews.llvm.org/D149829
This commit is contained in:
@@ -43,6 +43,7 @@ public:
|
||||
explicit queue(container_type&& c)
|
||||
template<class InputIterator>
|
||||
queue(InputIterator first, InputIterator last); // since C++23
|
||||
template<container-compatible-range<T> R> queue(from_range_t, R&& rg); // since C++23
|
||||
template <class Alloc>
|
||||
explicit queue(const Alloc& a);
|
||||
template <class Alloc>
|
||||
@@ -55,6 +56,8 @@ public:
|
||||
queue(queue&& q, const Alloc& a);
|
||||
template <class InputIterator, class Alloc>
|
||||
queue(InputIterator first, InputIterator last, const Alloc&); // since C++23
|
||||
template<container-compatible-range<T> R, class Alloc>
|
||||
queue(from_range_t, R&& rg, const Alloc&); // since C++23
|
||||
|
||||
bool empty() const;
|
||||
size_type size() const;
|
||||
@@ -66,6 +69,8 @@ public:
|
||||
|
||||
void push(const value_type& v);
|
||||
void push(value_type&& v);
|
||||
template<container-compatible-range<T> R>
|
||||
void push_range(R&& rg); // C++23
|
||||
template <class... Args> reference emplace(Args&&... args); // reference in C++17
|
||||
void pop();
|
||||
|
||||
@@ -78,6 +83,9 @@ template<class Container>
|
||||
template<class InputIterator>
|
||||
queue(InputIterator, InputIterator) -> queue<iter-value-type<InputIterator>>; // since C++23
|
||||
|
||||
template<ranges::input_range R>
|
||||
queue(from_range_t, R&&) -> queue<ranges::range_value_t<R>>; // since C++23
|
||||
|
||||
template<class Container, class Allocator>
|
||||
queue(Container, Allocator) -> queue<typename Container::value_type, Container>; // C++17
|
||||
|
||||
@@ -86,6 +94,10 @@ template<class InputIterator, class Allocator>
|
||||
-> queue<iter-value-type<InputIterator>,
|
||||
deque<iter-value-type<InputIterator>, Allocator>>; // since C++23
|
||||
|
||||
template<ranges::input_range R, class Allocator>
|
||||
queue(from_range_t, R&&, Allocator)
|
||||
-> queue<ranges::range_value_t<R>, deque<ranges::range_value_t<R>, Allocator>>; // since C++23
|
||||
|
||||
template <class T, class Container>
|
||||
bool operator==(const queue<T, Container>& x,const queue<T, Container>& y);
|
||||
|
||||
@@ -138,6 +150,8 @@ public:
|
||||
template <class InputIterator>
|
||||
priority_queue(InputIterator first, InputIterator last,
|
||||
const Compare& comp, Container&& c);
|
||||
template <container-compatible-range<T> R>
|
||||
priority_queue(from_range_t, R&& rg, const Compare& x = Compare()); // since C++23
|
||||
template <class Alloc>
|
||||
explicit priority_queue(const Alloc& a);
|
||||
template <class Alloc>
|
||||
@@ -160,6 +174,10 @@ public:
|
||||
template <class InputIterator>
|
||||
priority_queue(InputIterator first, InputIterator last,
|
||||
const Compare& comp, Container&& c, const Alloc& a);
|
||||
template <container-compatible-range<T> R, class Alloc>
|
||||
priority_queue(from_range_t, R&& rg, const Compare&, const Alloc&); // since C++23
|
||||
template <container-compatible-range<T> R, class Alloc>
|
||||
priority_queue(from_range_t, R&& rg, const Alloc&); // since C++23
|
||||
template <class Alloc>
|
||||
priority_queue(const priority_queue& q, const Alloc& a);
|
||||
template <class Alloc>
|
||||
@@ -171,6 +189,8 @@ public:
|
||||
|
||||
void push(const value_type& v);
|
||||
void push(value_type&& v);
|
||||
template<container-compatible-range<T> R>
|
||||
void push_range(R&& rg); // C++23
|
||||
template <class... Args> void emplace(Args&&... args);
|
||||
void pop();
|
||||
|
||||
@@ -189,6 +209,10 @@ template<class InputIterator,
|
||||
priority_queue(InputIterator, InputIterator, Compare = Compare(), Container = Container())
|
||||
-> priority_queue<iter-value-type<InputIterator>, Container, Compare>; // C++17
|
||||
|
||||
template<ranges::input_range R, class Compare = less<ranges::range_value_t<R>>>
|
||||
priority_queue(from_range_t, R&&, Compare = Compare())
|
||||
-> priority_queue<ranges::range_value_t<R>, vector<ranges::range_value_t<R>>, Compare>; // C++23
|
||||
|
||||
template<class Compare, class Container, class Allocator>
|
||||
priority_queue(Compare, Container, Allocator)
|
||||
-> priority_queue<typename Container::value_type, Container, Compare>; // C++17
|
||||
@@ -208,6 +232,15 @@ template<class InputIterator, class Compare, class Container, class Allocator>
|
||||
priority_queue(InputIterator, InputIterator, Compare, Container, Allocator)
|
||||
-> priority_queue<typename Container::value_type, Container, Compare>; // C++17
|
||||
|
||||
template<ranges::input_range R, class Compare, class Allocator>
|
||||
priority_queue(from_range_t, R&&, Compare, Allocator)
|
||||
-> priority_queue<ranges::range_value_t<R>, vector<ranges::range_value_t<R>, Allocator>,
|
||||
Compare>; // C++23
|
||||
|
||||
template<ranges::input_range R, class Allocator>
|
||||
priority_queue(from_range_t, R&&, Allocator)
|
||||
-> priority_queue<ranges::range_value_t<R>, vector<ranges::range_value_t<R>, Allocator>>; // C++23
|
||||
|
||||
template <class T, class Container, class Compare>
|
||||
void swap(priority_queue<T, Container, Compare>& x,
|
||||
priority_queue<T, Container, Compare>& y)
|
||||
@@ -220,11 +253,17 @@ template <class T, class Container, class Compare>
|
||||
#include <__algorithm/make_heap.h>
|
||||
#include <__algorithm/pop_heap.h>
|
||||
#include <__algorithm/push_heap.h>
|
||||
#include <__algorithm/ranges_copy.h>
|
||||
#include <__assert> // all public C++ headers provide the assertion handler
|
||||
#include <__config>
|
||||
#include <__functional/operations.h>
|
||||
#include <__iterator/back_insert_iterator.h>
|
||||
#include <__iterator/iterator_traits.h>
|
||||
#include <__memory/uses_allocator.h>
|
||||
#include <__ranges/access.h>
|
||||
#include <__ranges/concepts.h>
|
||||
#include <__ranges/container_compatible_range.h>
|
||||
#include <__ranges/from_range.h>
|
||||
#include <__utility/forward.h>
|
||||
#include <deque>
|
||||
#include <vector>
|
||||
@@ -283,12 +322,24 @@ public:
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
queue(_InputIterator __first, _InputIterator __last) : c(__first, __last) {}
|
||||
|
||||
template <_ContainerCompatibleRange<_Tp> _Range>
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
queue(from_range_t, _Range&& __range) : c(from_range, std::forward<_Range>(__range)) {}
|
||||
|
||||
template <class _InputIterator,
|
||||
class _Alloc,
|
||||
class = __enable_if_t<__has_input_iterator_category<_InputIterator>::value>,
|
||||
class = __enable_if_t<uses_allocator<container_type, _Alloc>::value>>
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
queue(_InputIterator __first, _InputIterator __second, const _Alloc& __alloc) : c(__first, __second, __alloc) {}
|
||||
|
||||
template <_ContainerCompatibleRange<_Tp> _Range,
|
||||
class _Alloc,
|
||||
class = __enable_if_t<uses_allocator<container_type, _Alloc>::value>>
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
queue(from_range_t, _Range&& __range, const _Alloc& __alloc)
|
||||
: c(from_range, std::forward<_Range>(__range), __alloc) {}
|
||||
|
||||
#endif
|
||||
|
||||
_LIBCPP_INLINE_VISIBILITY
|
||||
@@ -360,6 +411,21 @@ public:
|
||||
#ifndef _LIBCPP_CXX03_LANG
|
||||
_LIBCPP_INLINE_VISIBILITY
|
||||
void push(value_type&& __v) {c.push_back(_VSTD::move(__v));}
|
||||
|
||||
#if _LIBCPP_STD_VER >= 23
|
||||
template <_ContainerCompatibleRange<_Tp> _Range>
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
void push_range(_Range&& __range) {
|
||||
if constexpr (requires (container_type& __c) {
|
||||
__c.append_range(std::forward<_Range>(__range));
|
||||
}) {
|
||||
c.append_range(std::forward<_Range>(__range));
|
||||
} else {
|
||||
ranges::copy(std::forward<_Range>(__range), std::back_inserter(c));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
template <class... _Args>
|
||||
_LIBCPP_INLINE_VISIBILITY
|
||||
#if _LIBCPP_STD_VER >= 17
|
||||
@@ -418,12 +484,22 @@ template <class _InputIterator,
|
||||
queue(_InputIterator, _InputIterator)
|
||||
-> queue<__iter_value_type<_InputIterator>>;
|
||||
|
||||
template <ranges::input_range _Range>
|
||||
queue(from_range_t, _Range&&)
|
||||
-> queue<ranges::range_value_t<_Range>>;
|
||||
|
||||
template <class _InputIterator,
|
||||
class _Alloc,
|
||||
class = __enable_if_t<__has_input_iterator_category<_InputIterator>::value>,
|
||||
class = __enable_if_t<__is_allocator<_Alloc>::value>>
|
||||
queue(_InputIterator, _InputIterator, _Alloc)
|
||||
-> queue<__iter_value_type<_InputIterator>, deque<__iter_value_type<_InputIterator>, _Alloc>>;
|
||||
|
||||
template <ranges::input_range _Range,
|
||||
class _Alloc,
|
||||
class = __enable_if_t<__is_allocator<_Alloc>::value>>
|
||||
queue(from_range_t, _Range&&, _Alloc)
|
||||
-> queue<ranges::range_value_t<_Range>, deque<ranges::range_value_t<_Range>, _Alloc>>;
|
||||
#endif
|
||||
|
||||
template <class _Tp, class _Container>
|
||||
@@ -557,6 +633,17 @@ public:
|
||||
priority_queue(_InputIter __f, _InputIter __l,
|
||||
const value_compare& __comp, container_type&& __c);
|
||||
#endif // _LIBCPP_CXX03_LANG
|
||||
|
||||
#if _LIBCPP_STD_VER >= 23
|
||||
template <_ContainerCompatibleRange<_Tp> _Range>
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
priority_queue(from_range_t, _Range&& __range, const value_compare& __comp = value_compare())
|
||||
: c(from_range, std::forward<_Range>(__range)),
|
||||
comp(__comp) {
|
||||
std::make_heap(c.begin(), c.end(), comp);
|
||||
}
|
||||
#endif
|
||||
|
||||
template <class _Alloc>
|
||||
_LIBCPP_INLINE_VISIBILITY
|
||||
explicit priority_queue(const _Alloc& __a,
|
||||
@@ -611,6 +698,30 @@ public:
|
||||
__enable_if_t<uses_allocator<container_type, _Alloc>::value>* = 0);
|
||||
#endif // _LIBCPP_CXX03_LANG
|
||||
|
||||
#if _LIBCPP_STD_VER >= 23
|
||||
|
||||
template <_ContainerCompatibleRange<_Tp> _Range,
|
||||
class _Alloc,
|
||||
class = enable_if_t<uses_allocator<_Container, _Alloc>::value>>
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
priority_queue(from_range_t, _Range&& __range, const value_compare& __comp, const _Alloc& __a)
|
||||
: c(from_range, std::forward<_Range>(__range), __a),
|
||||
comp(__comp) {
|
||||
std::make_heap(c.begin(), c.end(), comp);
|
||||
}
|
||||
|
||||
template <_ContainerCompatibleRange<_Tp> _Range,
|
||||
class _Alloc,
|
||||
class = enable_if_t<uses_allocator<_Container, _Alloc>::value>>
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
priority_queue(from_range_t, _Range&& __range, const _Alloc& __a)
|
||||
: c(from_range, std::forward<_Range>(__range), __a),
|
||||
comp() {
|
||||
std::make_heap(c.begin(), c.end(), comp);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
_LIBCPP_NODISCARD_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY
|
||||
bool empty() const {return c.empty();}
|
||||
_LIBCPP_INLINE_VISIBILITY
|
||||
@@ -623,6 +734,23 @@ public:
|
||||
#ifndef _LIBCPP_CXX03_LANG
|
||||
_LIBCPP_INLINE_VISIBILITY
|
||||
void push(value_type&& __v);
|
||||
|
||||
#if _LIBCPP_STD_VER >= 23
|
||||
template <_ContainerCompatibleRange<_Tp> _Range>
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
void push_range(_Range&& __range) {
|
||||
if constexpr (requires (container_type& __c) {
|
||||
__c.append_range(std::forward<_Range>(__range));
|
||||
}) {
|
||||
c.append_range(std::forward<_Range>(__range));
|
||||
} else {
|
||||
ranges::copy(std::forward<_Range>(__range), std::back_inserter(c));
|
||||
}
|
||||
|
||||
std::make_heap(c.begin(), c.end(), comp);
|
||||
}
|
||||
#endif
|
||||
|
||||
template <class... _Args>
|
||||
_LIBCPP_INLINE_VISIBILITY
|
||||
void emplace(_Args&&... __args);
|
||||
@@ -695,6 +823,31 @@ priority_queue(_InputIterator, _InputIterator, _Compare, _Container, _Alloc)
|
||||
-> priority_queue<typename _Container::value_type, _Container, _Compare>;
|
||||
#endif
|
||||
|
||||
#if _LIBCPP_STD_VER >= 23
|
||||
|
||||
template <ranges::input_range _Range,
|
||||
class _Compare = less<ranges::range_value_t<_Range>>,
|
||||
class = enable_if_t<!__is_allocator<_Compare>::value>>
|
||||
priority_queue(from_range_t, _Range&&, _Compare = _Compare())
|
||||
-> priority_queue<ranges::range_value_t<_Range>, vector<ranges::range_value_t<_Range>>, _Compare>;
|
||||
|
||||
template <ranges::input_range _Range,
|
||||
class _Compare,
|
||||
class _Alloc,
|
||||
class = enable_if_t<!__is_allocator<_Compare>::value>,
|
||||
class = enable_if_t<__is_allocator<_Alloc>::value>>
|
||||
priority_queue(from_range_t, _Range&&, _Compare, _Alloc)
|
||||
-> priority_queue<ranges::range_value_t<_Range>, vector<ranges::range_value_t<_Range>, _Alloc>,
|
||||
_Compare>;
|
||||
|
||||
template <ranges::input_range _Range,
|
||||
class _Alloc,
|
||||
class = enable_if_t<__is_allocator<_Alloc>::value>>
|
||||
priority_queue(from_range_t, _Range&&, _Alloc)
|
||||
-> priority_queue<ranges::range_value_t<_Range>, vector<ranges::range_value_t<_Range>, _Alloc>>;
|
||||
|
||||
#endif
|
||||
|
||||
template <class _Tp, class _Container, class _Compare>
|
||||
inline
|
||||
priority_queue<_Tp, _Container, _Compare>::priority_queue(const _Compare& __comp,
|
||||
|
||||
@@ -42,6 +42,7 @@ public:
|
||||
explicit stack(const container_type& c);
|
||||
explicit stack(container_type&& c);
|
||||
template <class InputIterator> stack(InputIterator first, InputIterator last); // since C++23
|
||||
template<container-compatible-range<T> R> stack(from_range_t, R&& rg); // since C++23
|
||||
template <class Alloc> explicit stack(const Alloc& a);
|
||||
template <class Alloc> stack(const container_type& c, const Alloc& a);
|
||||
template <class Alloc> stack(container_type&& c, const Alloc& a);
|
||||
@@ -49,6 +50,8 @@ public:
|
||||
template <class Alloc> stack(stack&& c, const Alloc& a);
|
||||
template<class InputIterator, class Alloc>
|
||||
stack(InputIterator first, InputIterator last, const Alloc&); // since C++23
|
||||
template<container-compatible-range<T> R, class Alloc>
|
||||
stack(from_range_t, R&& rg, const Alloc&); // since C++23
|
||||
|
||||
bool empty() const;
|
||||
size_type size() const;
|
||||
@@ -57,6 +60,8 @@ public:
|
||||
|
||||
void push(const value_type& x);
|
||||
void push(value_type&& x);
|
||||
template<container-compatible-range<T> R>
|
||||
void push_range(R&& rg); // C++23
|
||||
template <class... Args> reference emplace(Args&&... args); // reference in C++17
|
||||
void pop();
|
||||
|
||||
@@ -69,6 +74,9 @@ template<class Container>
|
||||
template<class InputIterator>
|
||||
stack(InputIterator, InputIterator) -> stack<iter-value-type<InputIterator>>; // since C++23
|
||||
|
||||
template<ranges::input_range R>
|
||||
stack(from_range_t, R&&) -> stack<ranges::range_value_t<R>>; // since C++23
|
||||
|
||||
template<class Container, class Allocator>
|
||||
stack(Container, Allocator) -> stack<typename Container::value_type, Container>; // C++17
|
||||
|
||||
@@ -77,6 +85,10 @@ template<class InputIterator, class Allocator>
|
||||
-> stack<iter-value-type<InputIterator>,
|
||||
deque<iter-value-type<InputIterator>, Allocator>>; // since C++23
|
||||
|
||||
template<ranges::input_range R, class Allocator>
|
||||
stack(from_range_t, R&&, Allocator)
|
||||
-> stack<ranges::range_value_t<R>, deque<ranges::range_value_t<R>, Allocator>>; // since C++23
|
||||
|
||||
template <class T, class Container>
|
||||
bool operator==(const stack<T, Container>& x, const stack<T, Container>& y);
|
||||
template <class T, class Container>
|
||||
@@ -98,10 +110,16 @@ template <class T, class Container>
|
||||
|
||||
*/
|
||||
|
||||
#include <__algorithm/ranges_copy.h>
|
||||
#include <__assert> // all public C++ headers provide the assertion handler
|
||||
#include <__config>
|
||||
#include <__iterator/back_insert_iterator.h>
|
||||
#include <__iterator/iterator_traits.h>
|
||||
#include <__memory/uses_allocator.h>
|
||||
#include <__ranges/access.h>
|
||||
#include <__ranges/concepts.h>
|
||||
#include <__ranges/container_compatible_range.h>
|
||||
#include <__ranges/from_range.h>
|
||||
#include <__type_traits/is_same.h>
|
||||
#include <__utility/forward.h>
|
||||
#include <deque>
|
||||
@@ -210,12 +228,24 @@ public:
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
stack(_InputIterator __first, _InputIterator __last) : c(__first, __last) {}
|
||||
|
||||
template <_ContainerCompatibleRange<_Tp> _Range>
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
stack(from_range_t, _Range&& __range) : c(from_range, std::forward<_Range>(__range)) {}
|
||||
|
||||
template <class _InputIterator,
|
||||
class _Alloc,
|
||||
class = __enable_if_t<__has_input_iterator_category<_InputIterator>::value>,
|
||||
class = __enable_if_t<uses_allocator<container_type, _Alloc>::value>>
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
stack(_InputIterator __first, _InputIterator __last, const _Alloc& __alloc) : c(__first, __last, __alloc) {}
|
||||
|
||||
template <_ContainerCompatibleRange<_Tp> _Range,
|
||||
class _Alloc,
|
||||
class = __enable_if_t<uses_allocator<container_type, _Alloc>::value>>
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
stack(from_range_t, _Range&& __range, const _Alloc& __alloc)
|
||||
: c(from_range, std::forward<_Range>(__range), __alloc) {}
|
||||
|
||||
#endif
|
||||
|
||||
_LIBCPP_NODISCARD_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY
|
||||
@@ -233,6 +263,20 @@ public:
|
||||
_LIBCPP_INLINE_VISIBILITY
|
||||
void push(value_type&& __v) {c.push_back(_VSTD::move(__v));}
|
||||
|
||||
#if _LIBCPP_STD_VER >= 23
|
||||
template <_ContainerCompatibleRange<_Tp> _Range>
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
void push_range(_Range&& __range) {
|
||||
if constexpr (requires (container_type& __c) {
|
||||
__c.append_range(std::forward<_Range>(__range));
|
||||
}) {
|
||||
c.append_range(std::forward<_Range>(__range));
|
||||
} else {
|
||||
ranges::copy(std::forward<_Range>(__range), std::back_inserter(c));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
template <class... _Args>
|
||||
_LIBCPP_INLINE_VISIBILITY
|
||||
#if _LIBCPP_STD_VER >= 17
|
||||
@@ -290,12 +334,22 @@ template<class _InputIterator,
|
||||
stack(_InputIterator, _InputIterator)
|
||||
-> stack<__iter_value_type<_InputIterator>>;
|
||||
|
||||
template <ranges::input_range _Range>
|
||||
stack(from_range_t, _Range&&) -> stack<ranges::range_value_t<_Range>>;
|
||||
|
||||
template<class _InputIterator,
|
||||
class _Alloc,
|
||||
class = __enable_if_t<__has_input_iterator_category<_InputIterator>::value>,
|
||||
class = __enable_if_t<__is_allocator<_Alloc>::value>>
|
||||
stack(_InputIterator, _InputIterator, _Alloc)
|
||||
-> stack<__iter_value_type<_InputIterator>, deque<__iter_value_type<_InputIterator>, _Alloc>>;
|
||||
|
||||
template <ranges::input_range _Range,
|
||||
class _Alloc,
|
||||
class = __enable_if_t<__is_allocator<_Alloc>::value>>
|
||||
stack(from_range_t, _Range&&, _Alloc)
|
||||
-> stack<ranges::range_value_t<_Range>, deque<ranges::range_value_t<_Range>, _Alloc>>;
|
||||
|
||||
#endif
|
||||
|
||||
template <class _Tp, class _Container>
|
||||
|
||||
@@ -777,6 +777,7 @@ stack cstddef
|
||||
stack deque
|
||||
stack functional
|
||||
stack initializer_list
|
||||
stack limits
|
||||
stack type_traits
|
||||
stack version
|
||||
stdexcept cstdlib
|
||||
|
||||
|
@@ -778,6 +778,7 @@ stack cstddef
|
||||
stack deque
|
||||
stack functional
|
||||
stack initializer_list
|
||||
stack limits
|
||||
stack type_traits
|
||||
stack version
|
||||
stdexcept cstdlib
|
||||
|
||||
|
@@ -780,6 +780,7 @@ stack cstddef
|
||||
stack deque
|
||||
stack functional
|
||||
stack initializer_list
|
||||
stack limits
|
||||
stack type_traits
|
||||
stack version
|
||||
stdexcept cstdlib
|
||||
|
||||
|
@@ -780,6 +780,7 @@ stack cstddef
|
||||
stack deque
|
||||
stack functional
|
||||
stack initializer_list
|
||||
stack limits
|
||||
stack type_traits
|
||||
stack version
|
||||
stdexcept cstdlib
|
||||
|
||||
|
@@ -786,6 +786,7 @@ stack cstddef
|
||||
stack deque
|
||||
stack functional
|
||||
stack initializer_list
|
||||
stack limits
|
||||
stack type_traits
|
||||
stack version
|
||||
stdexcept cstdlib
|
||||
|
||||
|
@@ -437,6 +437,7 @@ ostream typeinfo
|
||||
ostream version
|
||||
queue compare
|
||||
queue cstddef
|
||||
queue cstdint
|
||||
queue deque
|
||||
queue initializer_list
|
||||
queue limits
|
||||
@@ -529,8 +530,10 @@ sstream string
|
||||
sstream version
|
||||
stack compare
|
||||
stack cstddef
|
||||
stack cstdint
|
||||
stack deque
|
||||
stack initializer_list
|
||||
stack limits
|
||||
stack version
|
||||
stdexcept iosfwd
|
||||
stop_token atomic
|
||||
|
||||
|
@@ -0,0 +1,229 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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_CONTAINER_ADAPTORS_H
|
||||
#define SUPPORT_FROM_RANGE_CONTAINER_ADAPTORS_H
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <queue>
|
||||
#include <ranges>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "../from_range_helpers.h"
|
||||
#include "MoveOnly.h"
|
||||
#include "almost_satisfies_types.h"
|
||||
#include "count_new.h"
|
||||
#include "test_macros.h"
|
||||
#include "unwrap_container_adaptor.h"
|
||||
|
||||
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>);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <template <class ...> class Adaptor,
|
||||
template <class ...> class UnderlyingContainer,
|
||||
class T,
|
||||
class Iter,
|
||||
class Sent,
|
||||
class Alloc>
|
||||
constexpr void test_container_adaptor_with_input(std::vector<T>&& input) {
|
||||
auto b = Iter(input.data());
|
||||
auto e = Iter(input.data() + input.size());
|
||||
std::ranges::subrange in(std::move(b), Sent(std::move(e)));
|
||||
|
||||
{ // (range)
|
||||
Adaptor<T> adaptor(std::from_range, in);
|
||||
UnwrapAdaptor<Adaptor<T>> unwrap_adaptor(std::move(adaptor));
|
||||
auto& c = unwrap_adaptor.get_container();
|
||||
|
||||
assert(c.size() == static_cast<std::size_t>(std::distance(c.begin(), c.end())));
|
||||
assert(std::ranges::equal(in, c));
|
||||
LIBCPP_ASSERT(c.__invariants());
|
||||
}
|
||||
|
||||
{ // (range, allocator)
|
||||
using C = UnderlyingContainer<T, Alloc>;
|
||||
Alloc alloc;
|
||||
Adaptor<T, C> adaptor(std::from_range, in, alloc);
|
||||
UnwrapAdaptor<Adaptor<T, C>> unwrap_adaptor(std::move(adaptor));
|
||||
auto& c = unwrap_adaptor.get_container();
|
||||
|
||||
assert(c.get_allocator() == alloc);
|
||||
assert(c.size() == static_cast<std::size_t>(std::distance(c.begin(), c.end())));
|
||||
assert(std::ranges::equal(in, c));
|
||||
LIBCPP_ASSERT(c.__invariants());
|
||||
}
|
||||
}
|
||||
|
||||
template <template <class ...> class UnderlyingContainer,
|
||||
class T,
|
||||
class Iter,
|
||||
class Sent,
|
||||
class Comp,
|
||||
class Alloc>
|
||||
constexpr void test_priority_queue_with_input(std::vector<T>&& input) {
|
||||
auto b = Iter(input.data());
|
||||
auto e = Iter(input.data() + input.size());
|
||||
std::ranges::subrange in(std::move(b), Sent(std::move(e)));
|
||||
|
||||
{ // (range)
|
||||
std::priority_queue<T> adaptor(std::from_range, in);
|
||||
UnwrapAdaptor<std::priority_queue<T>> unwrap_adaptor(std::move(adaptor));
|
||||
auto& c = unwrap_adaptor.get_container();
|
||||
|
||||
assert(c.size() == static_cast<std::size_t>(std::distance(c.begin(), c.end())));
|
||||
assert(std::ranges::is_permutation(input, c));
|
||||
LIBCPP_ASSERT(c.__invariants());
|
||||
}
|
||||
|
||||
{ // (range, comp)
|
||||
using C = UnderlyingContainer<T>;
|
||||
Comp comp;
|
||||
|
||||
std::priority_queue<T, C, Comp> adaptor(std::from_range, in, comp);
|
||||
UnwrapAdaptor<std::priority_queue<T, C, Comp>> unwrap_adaptor(std::move(adaptor));
|
||||
auto& c = unwrap_adaptor.get_container();
|
||||
|
||||
assert(c.size() == static_cast<std::size_t>(std::distance(c.begin(), c.end())));
|
||||
assert(std::ranges::is_permutation(input, c));
|
||||
LIBCPP_ASSERT(c.__invariants());
|
||||
assert(unwrap_adaptor.get_comparator() == comp);
|
||||
}
|
||||
|
||||
{ // (range, allocator)
|
||||
using C = UnderlyingContainer<T, Alloc>;
|
||||
Alloc alloc;
|
||||
|
||||
std::priority_queue<T, C> adaptor(std::from_range, in, alloc);
|
||||
UnwrapAdaptor<std::priority_queue<T, C>> unwrap_adaptor(std::move(adaptor));
|
||||
auto& c = unwrap_adaptor.get_container();
|
||||
|
||||
assert(c.get_allocator() == alloc);
|
||||
assert(c.size() == static_cast<std::size_t>(std::distance(c.begin(), c.end())));
|
||||
assert(std::ranges::is_permutation(input, c));
|
||||
LIBCPP_ASSERT(c.__invariants());
|
||||
}
|
||||
|
||||
{ // (range, comp, alloc)
|
||||
using C = UnderlyingContainer<T, Alloc>;
|
||||
Comp comp;
|
||||
Alloc alloc;
|
||||
|
||||
std::priority_queue<T, C, Comp> adaptor(std::from_range, in, comp, alloc);
|
||||
UnwrapAdaptor<std::priority_queue<T, C, Comp>> unwrap_adaptor(std::move(adaptor));
|
||||
auto& c = unwrap_adaptor.get_container();
|
||||
|
||||
assert(c.get_allocator() == alloc);
|
||||
assert(c.size() == static_cast<std::size_t>(std::distance(c.begin(), c.end())));
|
||||
assert(std::ranges::is_permutation(input, c));
|
||||
LIBCPP_ASSERT(c.__invariants());
|
||||
assert(unwrap_adaptor.get_comparator() == comp);
|
||||
}
|
||||
}
|
||||
|
||||
template <template <class ...> class Adaptor,
|
||||
template <class ...> class UnderlyingContainer,
|
||||
class T,
|
||||
class Iter,
|
||||
class Sent,
|
||||
class Alloc>
|
||||
constexpr void test_container_adaptor() {
|
||||
auto test_with_input = &test_container_adaptor_with_input<Adaptor, UnderlyingContainer, T, Iter, Sent, Alloc>;
|
||||
|
||||
// Normal input.
|
||||
test_with_input({0, 5, 12, 7, -1, 8, 26});
|
||||
// Empty input.
|
||||
test_with_input({});
|
||||
// Single-element input.
|
||||
test_with_input({5});
|
||||
}
|
||||
|
||||
template <template <class ...> class UnderlyingContainer,
|
||||
class T,
|
||||
class Iter,
|
||||
class Sent,
|
||||
class Comp,
|
||||
class Alloc>
|
||||
constexpr void test_priority_queue() {
|
||||
auto test_with_input = &test_priority_queue_with_input<UnderlyingContainer, T, Iter, Sent, Comp, Alloc>;
|
||||
|
||||
// Normal input.
|
||||
test_with_input({0, 5, 12, 7, -1, 8, 26});
|
||||
// Empty input.
|
||||
test_with_input({});
|
||||
// Single-element input.
|
||||
test_with_input({5});
|
||||
}
|
||||
|
||||
template <template <class ...> class Container>
|
||||
constexpr void test_container_adaptor_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 <template <class ...> class Adaptor>
|
||||
void test_exception_safety_throwing_copy() {
|
||||
#if !defined(TEST_HAS_NO_EXCEPTIONS)
|
||||
using T = ThrowingCopy<3>;
|
||||
T::reset();
|
||||
T in[5];
|
||||
|
||||
try {
|
||||
Adaptor<T, std::vector<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 Adaptor, class T>
|
||||
void test_exception_safety_throwing_allocator() {
|
||||
#if !defined(TEST_HAS_NO_EXCEPTIONS)
|
||||
T in[] = {0, 1};
|
||||
|
||||
try {
|
||||
using C = std::vector<T, ThrowingAllocator<T>>;
|
||||
ThrowingAllocator<T> alloc;
|
||||
|
||||
globalMemCounter.reset();
|
||||
Adaptor<T, C> c(std::from_range, in, alloc);
|
||||
assert(false); // The constructor call should throw.
|
||||
|
||||
} catch (int) {
|
||||
assert(globalMemCounter.new_called == globalMemCounter.delete_called);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif // SUPPORT_FROM_RANGE_CONTAINER_ADAPTORS_H
|
||||
@@ -22,14 +22,26 @@
|
||||
// template<class Compare, class Container, class Allocator>
|
||||
// priority_queue(Compare, Container, Allocator)
|
||||
// -> priority_queue<typename Container::value_type, Container, Compare>;
|
||||
//
|
||||
// template<ranges::input_range R, class Compare = less<ranges::range_value_t<R>>>
|
||||
// priority_queue(from_range_t, R&&, Compare = Compare())
|
||||
// -> priority_queue<ranges::range_value_t<R>, vector<ranges::range_value_t<R>>, Compare>; // C++23
|
||||
//
|
||||
// template<ranges::input_range R, class Compare, class Allocator>
|
||||
// priority_queue(from_range_t, R&&, Compare, Allocator)
|
||||
// -> priority_queue<ranges::range_value_t<R>, vector<ranges::range_value_t<R>, Allocator>,
|
||||
// Compare>; // C++23
|
||||
//
|
||||
// template<ranges::input_range R, class Allocator>
|
||||
// priority_queue(from_range_t, R&&, Allocator)
|
||||
// -> priority_queue<ranges::range_value_t<R>, vector<ranges::range_value_t<R>, Allocator>>; // C++23
|
||||
|
||||
|
||||
#include <cassert>
|
||||
#include <climits> // INT_MAX
|
||||
#include <cstddef>
|
||||
#include <iterator>
|
||||
#include <queue>
|
||||
#include <vector>
|
||||
#include <iterator>
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <climits> // INT_MAX
|
||||
|
||||
#include "deduction_guides_sfinae_checks.h"
|
||||
#include "test_macros.h"
|
||||
@@ -238,6 +250,28 @@ int main(int, char**)
|
||||
std::priority_queue pri(a, a+2, Comp(), std::move(cont), ConvertibleToAlloc(2));
|
||||
static_assert(std::is_same_v<decltype(pri), std::priority_queue<T, Cont, Comp>>);
|
||||
}
|
||||
|
||||
#if TEST_STD_VER >= 23
|
||||
{ // (from_range, range)
|
||||
std::priority_queue c(std::from_range, Cont());
|
||||
static_assert(std::is_same_v<decltype(c), std::priority_queue<T>>);
|
||||
}
|
||||
|
||||
{ // (from_range, range, compare)
|
||||
std::priority_queue c(std::from_range, Cont(), Comp());
|
||||
static_assert(std::is_same_v<decltype(c), std::priority_queue<T, std::vector<T>, Comp>>);
|
||||
}
|
||||
|
||||
{ // (from_range, range, compare, alloc)
|
||||
std::priority_queue c(std::from_range, Cont(), Comp(), Alloc(2));
|
||||
static_assert(std::is_same_v<decltype(c), std::priority_queue<T, std::vector<T, Alloc>, Comp>>);
|
||||
}
|
||||
|
||||
{ // (from_range, range, alloc)
|
||||
std::priority_queue c(std::from_range, Cont(), Alloc(2));
|
||||
static_assert(std::is_same_v<decltype(c), std::priority_queue<T, std::vector<T, Alloc>>>);
|
||||
}
|
||||
#endif // TEST_STD_VER >= 23
|
||||
}
|
||||
|
||||
// Deduction guides should be SFINAE'd away when given:
|
||||
@@ -354,6 +388,39 @@ int main(int, char**)
|
||||
static_assert(SFINAEs_away<std::priority_queue, AllocAsComp, Cont>);
|
||||
// Cannot deduce from (comp, ALLOC_as_cont)
|
||||
static_assert(SFINAEs_away<std::priority_queue, Comp, AllocAsCont>);
|
||||
|
||||
#if TEST_STD_VER >= 23
|
||||
using Range = RangeT<int>;
|
||||
using BadRange = BadRangeT<int>;
|
||||
|
||||
// (from_range, range)
|
||||
//
|
||||
// Cannot deduce from (from_range, BAD_range)
|
||||
static_assert(SFINAEs_away<std::priority_queue, BadRange>);
|
||||
|
||||
// (from_range, range, compare)
|
||||
//
|
||||
// Cannot deduce from (from_range, BAD_range, compare)
|
||||
static_assert(SFINAEs_away<std::priority_queue, BadRange, Comp>);
|
||||
|
||||
// (from_range, range, compare, alloc)
|
||||
//
|
||||
// Cannot deduce from (from_range, BAD_range, compare, alloc)
|
||||
static_assert(SFINAEs_away<std::priority_queue, BadRange, Comp, Alloc>);
|
||||
// Cannot deduce from (from_range, range, compare, BAD_alloc)
|
||||
static_assert(SFINAEs_away<std::priority_queue, Range, Comp, BadAlloc>);
|
||||
// Cannot deduce from (from_range, range, compare, DIFFERENT_alloc)
|
||||
static_assert(SFINAEs_away<std::priority_queue, Range, Comp, DiffAlloc>);
|
||||
|
||||
// (from_range, range, alloc)
|
||||
//
|
||||
// Cannot deduce from (from_range, BAD_range, alloc)
|
||||
static_assert(SFINAEs_away<std::priority_queue, BadRange, Alloc>);
|
||||
// Cannot deduce from (from_range, range, BAD_alloc)
|
||||
static_assert(SFINAEs_away<std::priority_queue, Range, BadAlloc>);
|
||||
// Cannot deduce from (from_range, range, DIFFERENT_alloc)
|
||||
static_assert(SFINAEs_away<std::priority_queue, Range, DiffAlloc>);
|
||||
#endif // TEST_STD_VER >= 23
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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 <queue>
|
||||
|
||||
#include "../../from_range_container_adaptors.h"
|
||||
#include "../../../test_compare.h"
|
||||
#include "test_macros.h"
|
||||
|
||||
// template <container-compatible-range<T> R>
|
||||
// priority_queue(from_range_t, R&& rg, const Compare& x = Compare()); // since C++23
|
||||
// template <container-compatible-range<T> R, class Alloc>
|
||||
// priority_queue(from_range_t, R&& rg, const Compare&, const Alloc&); // since C++23
|
||||
// template <container-compatible-range<T> R, class Alloc>
|
||||
// priority_queue(from_range_t, R&& rg, const Alloc&); // since C++23
|
||||
|
||||
template <class Range>
|
||||
concept PriorityQueueHasFromRangeCtr = requires (Range&& range) {
|
||||
std::priority_queue<int>(std::from_range, std::forward<Range>(range));
|
||||
std::priority_queue<int>(std::from_range, std::forward<Range>(range), std::less<int>());
|
||||
std::priority_queue<int>(std::from_range, std::forward<Range>(range), std::less<int>(), std::allocator<int>());
|
||||
std::priority_queue<int>(std::from_range, std::forward<Range>(range), std::allocator<int>());
|
||||
};
|
||||
|
||||
constexpr bool test_constraints_priority_queue() {
|
||||
// Input range with the same value type.
|
||||
static_assert(PriorityQueueHasFromRangeCtr<InputRange<int>>);
|
||||
// Input range with a convertible value type.
|
||||
static_assert(PriorityQueueHasFromRangeCtr<InputRange<double>>);
|
||||
// Input range with a non-convertible value type.
|
||||
static_assert(!PriorityQueueHasFromRangeCtr<InputRange<Empty>>);
|
||||
// Not an input range.
|
||||
static_assert(!PriorityQueueHasFromRangeCtr<InputRangeNotDerivedFrom>);
|
||||
static_assert(!PriorityQueueHasFromRangeCtr<InputRangeNotIndirectlyReadable>);
|
||||
static_assert(!PriorityQueueHasFromRangeCtr<InputRangeNotInputOrOutputIterator>);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
for_all_iterators_and_allocators<int>([]<class Iter, class Sent, class Alloc>() {
|
||||
test_priority_queue<std::vector, int, Iter, Sent, test_less<int>, Alloc>();
|
||||
});
|
||||
test_container_adaptor_move_only<std::priority_queue>();
|
||||
|
||||
static_assert(test_constraints_priority_queue());
|
||||
|
||||
test_exception_safety_throwing_copy<std::priority_queue>();
|
||||
test_exception_safety_throwing_allocator<std::priority_queue, int>();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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>
|
||||
// void push_range(R&& rg); // C++23
|
||||
|
||||
#include <queue>
|
||||
|
||||
#include "../../push_range_container_adaptors.h"
|
||||
#include "test_macros.h"
|
||||
|
||||
int main(int, char**) {
|
||||
for_all_iterators_and_allocators<int, const int*>([]<class Iter, class Sent, class Alloc>() {
|
||||
test_push_range<std::priority_queue<int, std::vector<int, Alloc>>, Iter, Sent>(/*is_result_heapified=*/true);
|
||||
});
|
||||
test_push_range_move_only<std::priority_queue>();
|
||||
test_push_range_inserter_choice<std::priority_queue, int>(/*is_result_heapified=*/true);
|
||||
|
||||
static_assert(test_constraints_push_range<std::priority_queue, int, double>());
|
||||
|
||||
test_push_range_exception_safety_throwing_copy<std::priority_queue>();
|
||||
test_push_range_exception_safety_throwing_allocator<std::priority_queue, std::vector, int>();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,299 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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_PUSH_RANGE_CONTAINER_ADAPTORS_H
|
||||
#define SUPPORT_PUSH_RANGE_CONTAINER_ADAPTORS_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"
|
||||
#include "unwrap_container_adaptor.h"
|
||||
|
||||
template <class Container, class Range>
|
||||
concept HasPushRange = requires (Container& c, Range&& range) {
|
||||
c.push_range(range);
|
||||
};
|
||||
|
||||
template <template <class...> class Container, class T, class U>
|
||||
constexpr bool test_constraints_push_range() {
|
||||
// Input range with the same value type.
|
||||
static_assert(HasPushRange<Container<T>, InputRange<T>>);
|
||||
// Input range with a convertible value type.
|
||||
static_assert(HasPushRange<Container<T>, InputRange<U>>);
|
||||
// Input range with a non-convertible value type.
|
||||
static_assert(!HasPushRange<Container<T>, InputRange<Empty>>);
|
||||
// Not an input range.
|
||||
static_assert(!HasPushRange<Container<T>, InputRangeNotDerivedFrom>);
|
||||
static_assert(!HasPushRange<Container<T>, InputRangeNotIndirectlyReadable>);
|
||||
static_assert(!HasPushRange<Container<T>, InputRangeNotInputOrOutputIterator>);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Empty container.
|
||||
|
||||
template <class T>
|
||||
TestCase<T> constexpr EmptyContainer_EmptyRange {
|
||||
.initial = {}, .input = {}, .expected = {}
|
||||
};
|
||||
|
||||
template <class T> constexpr TestCase<T> EmptyContainer_OneElementRange {
|
||||
.initial = {}, .input = {5}, .expected = {5}
|
||||
};
|
||||
|
||||
template <class T> constexpr TestCase<T> EmptyContainer_MidRange {
|
||||
.initial = {}, .input = {5, 3, 1, 7, 9}, .expected = {5, 3, 1, 7, 9}
|
||||
};
|
||||
|
||||
// One-element container.
|
||||
|
||||
template <class T> constexpr TestCase<T> OneElementContainer_EmptyRange {
|
||||
.initial = {3}, .input = {}, .expected = {3}
|
||||
};
|
||||
|
||||
template <class T> constexpr TestCase<T> OneElementContainer_OneElementRange {
|
||||
.initial = {3}, .input = {-5}, .expected = {3, -5}
|
||||
};
|
||||
|
||||
template <class T> constexpr TestCase<T> OneElementContainer_MidRange {
|
||||
.initial = {3}, .input = {-5, -3, -1, -7, -9}, .expected = {3, -5, -3, -1, -7, -9}
|
||||
};
|
||||
|
||||
// Full container.
|
||||
|
||||
template <class T> constexpr TestCase<T> FullContainer_EmptyRange {
|
||||
.initial = {11, 29, 35, 14, 84}, .input = {}, .expected = {11, 29, 35, 14, 84}
|
||||
};
|
||||
|
||||
template <class T> constexpr TestCase<T> FullContainer_OneElementRange {
|
||||
.initial = {11, 29, 35, 14, 84}, .input = {-5}, .expected = {11, 29, 35, 14, 84, -5}
|
||||
};
|
||||
|
||||
template <class T> constexpr TestCase<T> FullContainer_MidRange {
|
||||
.initial = {11, 29, 35, 14, 84},
|
||||
.input = {-5, -3, -1, -7, -9},
|
||||
.expected = {11, 29, 35, 14, 84, -5, -3, -1, -7, -9}
|
||||
};
|
||||
|
||||
template <class T> constexpr TestCase<T> FullContainer_LongRange {
|
||||
.initial = {11, 29, 35, 14, 84},
|
||||
.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
|
||||
}
|
||||
};
|
||||
|
||||
// Container adaptors tests.
|
||||
|
||||
template <class Adaptor, class Iter, class Sent>
|
||||
constexpr void test_push_range(bool is_result_heapified = false) {
|
||||
using T = typename Adaptor::value_type;
|
||||
|
||||
auto test = [&](auto& test_case) {
|
||||
Adaptor adaptor(test_case.initial.begin(), test_case.initial.end());
|
||||
auto in = wrap_input<Iter, Sent>(test_case.input);
|
||||
|
||||
adaptor.push_range(in);
|
||||
UnwrapAdaptor<Adaptor> unwrap_adaptor(std::move(adaptor));
|
||||
auto& c = unwrap_adaptor.get_container();
|
||||
|
||||
if (is_result_heapified) {
|
||||
assert(std::ranges::is_heap(c));
|
||||
return std::ranges::is_permutation(c, test_case.expected);
|
||||
} else {
|
||||
return std::ranges::equal(c, test_case.expected);
|
||||
}
|
||||
};
|
||||
|
||||
{ // Empty container.
|
||||
// empty_c.push_range(empty_range)
|
||||
assert(test(EmptyContainer_EmptyRange<T>));
|
||||
// empty_c.push_range(one_element_range)
|
||||
assert(test(EmptyContainer_OneElementRange<T>));
|
||||
// empty_c.push_range(mid_range)
|
||||
assert(test(EmptyContainer_MidRange<T>));
|
||||
}
|
||||
|
||||
{ // One-element container.
|
||||
// one_element_c.push_range(empty_range)
|
||||
assert(test(OneElementContainer_EmptyRange<T>));
|
||||
// one_element_c.push_range(one_element_range)
|
||||
assert(test(OneElementContainer_OneElementRange<T>));
|
||||
// one_element_c.push_range(mid_range)
|
||||
assert(test(OneElementContainer_MidRange<T>));
|
||||
}
|
||||
|
||||
{ // Full container.
|
||||
// full_container.push_range(empty_range)
|
||||
assert(test(FullContainer_EmptyRange<T>));
|
||||
// full_container.push_range(one_element_range)
|
||||
assert(test(FullContainer_OneElementRange<T>));
|
||||
// full_container.push_range(mid_range)
|
||||
assert(test(FullContainer_MidRange<T>));
|
||||
// full_container.push_range(long_range)
|
||||
assert(test(FullContainer_LongRange<T>));
|
||||
}
|
||||
}
|
||||
|
||||
// Move-only types.
|
||||
|
||||
template <template <class ...> class Container>
|
||||
constexpr void test_push_range_move_only() {
|
||||
MoveOnly input[5];
|
||||
std::ranges::subrange in(std::move_iterator{input}, std::move_iterator{input + 5});
|
||||
|
||||
Container<MoveOnly> c;
|
||||
c.push_range(in);
|
||||
}
|
||||
|
||||
// Check that `append_range` is preferred if available and `push_back` is used as a fallback.
|
||||
|
||||
enum class InserterChoice {
|
||||
Invalid,
|
||||
PushBack,
|
||||
AppendRange
|
||||
};
|
||||
|
||||
template <class T, InserterChoice Inserter>
|
||||
struct Container {
|
||||
InserterChoice inserter_choice = InserterChoice::Invalid;
|
||||
|
||||
using value_type = T;
|
||||
using iterator = T*;
|
||||
using reference = T&;
|
||||
using const_reference = const T&;
|
||||
using size_type = std::size_t;
|
||||
|
||||
static constexpr int Capacity = 8;
|
||||
int size_ = 0;
|
||||
value_type buffer_[Capacity] = {};
|
||||
|
||||
iterator begin() { return buffer_; }
|
||||
iterator end() { return buffer_ + size_; }
|
||||
size_type size() const { return size_; }
|
||||
|
||||
template <class U>
|
||||
void push_back(U val)
|
||||
requires (Inserter >= InserterChoice::PushBack) {
|
||||
inserter_choice = InserterChoice::PushBack;
|
||||
buffer_[size_] = val;
|
||||
++size_;
|
||||
}
|
||||
|
||||
template <std::ranges::input_range Range>
|
||||
void append_range(Range&& range)
|
||||
requires (Inserter >= InserterChoice::AppendRange) {
|
||||
assert(size() + std::ranges::distance(range) <= Capacity);
|
||||
|
||||
inserter_choice = InserterChoice::AppendRange;
|
||||
|
||||
for (auto&& e : range) {
|
||||
buffer_[size_] = e;
|
||||
++size_;
|
||||
}
|
||||
}
|
||||
|
||||
friend bool operator==(const Container&, const Container&) = default;
|
||||
};
|
||||
|
||||
template <template <class ...> class AdaptorT, class T>
|
||||
void test_push_range_inserter_choice(bool is_result_heapified = false) {
|
||||
{ // `append_range` is preferred if available.
|
||||
using BaseContainer = Container<T, InserterChoice::AppendRange>;
|
||||
using Adaptor = AdaptorT<T, BaseContainer>;
|
||||
T in[] = {1, 2, 3, 4, 5};
|
||||
|
||||
Adaptor adaptor;
|
||||
adaptor.push_range(in);
|
||||
|
||||
UnwrapAdaptor<Adaptor> unwrap_adaptor(std::move(adaptor));
|
||||
auto& c = unwrap_adaptor.get_container();
|
||||
assert(c.inserter_choice == InserterChoice::AppendRange);
|
||||
if (is_result_heapified) {
|
||||
assert(std::ranges::is_heap(c));
|
||||
assert(std::ranges::is_permutation(c, in));
|
||||
} else {
|
||||
assert(std::ranges::equal(c, in));
|
||||
}
|
||||
}
|
||||
|
||||
{ // `push_back` is used as a fallback (via `back_inserter`).
|
||||
using BaseContainer = Container<T, InserterChoice::PushBack>;
|
||||
using Adaptor = AdaptorT<T, BaseContainer>;
|
||||
T in[] = {1, 2, 3, 4, 5};
|
||||
|
||||
Adaptor adaptor;
|
||||
adaptor.push_range(in);
|
||||
|
||||
UnwrapAdaptor<Adaptor> unwrap_adaptor(std::move(adaptor));
|
||||
auto& c = unwrap_adaptor.get_container();
|
||||
assert(c.inserter_choice == InserterChoice::PushBack);
|
||||
if (is_result_heapified) {
|
||||
assert(std::ranges::is_heap(c));
|
||||
assert(std::ranges::is_permutation(c, in));
|
||||
} else {
|
||||
assert(std::ranges::equal(c, in));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Exception safety.
|
||||
|
||||
template <template <class ...> class Container>
|
||||
void test_push_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.push_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 Adaptor, template <class ...> class BaseContainer, class T>
|
||||
void test_push_range_exception_safety_throwing_allocator() {
|
||||
#if !defined(TEST_HAS_NO_EXCEPTIONS)
|
||||
T in[] = {0, 1};
|
||||
|
||||
try {
|
||||
globalMemCounter.reset();
|
||||
Adaptor<T, BaseContainer<T, ThrowingAllocator<T>>> c;
|
||||
c.push_range(in);
|
||||
assert(false); // The function call above should throw.
|
||||
|
||||
} catch (int) {
|
||||
assert(globalMemCounter.new_called == globalMemCounter.delete_called);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif // SUPPORT_PUSH_RANGE_CONTAINER_ADAPTORS_H
|
||||
@@ -14,7 +14,13 @@
|
||||
//
|
||||
// template<class Container, class Allocator>
|
||||
// queue(Container, Allocator) -> queue<typename Container::value_type, Container>;
|
||||
|
||||
//
|
||||
// template<ranges::input_range R>
|
||||
// queue(from_range_t, R&&) -> queue<ranges::range_value_t<R>>; // since C++23
|
||||
//
|
||||
// template<ranges::input_range R, class Allocator>
|
||||
// queue(from_range_t, R&&, Allocator)
|
||||
// -> queue<ranges::range_value_t<R>, deque<ranges::range_value_t<R>, Allocator>>; // since C++23
|
||||
|
||||
#include <array>
|
||||
#include <queue>
|
||||
@@ -134,29 +140,7 @@ int main(int, char**)
|
||||
}
|
||||
}
|
||||
|
||||
// Deduction guides should be SFINAE'd away when given:
|
||||
// - a "bad" allocator (that is, a type not qualifying as an allocator);
|
||||
// - an allocator instead of a container;
|
||||
// - an allocator and a container that uses a different allocator.
|
||||
{
|
||||
using Cont = std::list<int>;
|
||||
using Alloc = std::allocator<int>;
|
||||
using DiffAlloc = test_allocator<int>;
|
||||
using Iter = int*;
|
||||
|
||||
struct NotIter{};
|
||||
struct NotAlloc {};
|
||||
|
||||
static_assert(SFINAEs_away<std::queue, Alloc, NotAlloc>);
|
||||
static_assert(SFINAEs_away<std::queue, Cont, NotAlloc>);
|
||||
static_assert(SFINAEs_away<std::queue, Cont, DiffAlloc>);
|
||||
static_assert(SFINAEs_away<std::queue, Iter, NotIter>);
|
||||
#if TEST_STD_VER > 20
|
||||
static_assert(SFINAEs_away<std::queue, Iter, NotIter, Alloc>);
|
||||
static_assert(SFINAEs_away<std::queue, Iter, Iter, NotAlloc>);
|
||||
#endif
|
||||
}
|
||||
#if TEST_STD_VER > 20
|
||||
#if TEST_STD_VER >= 23
|
||||
{
|
||||
typedef short T;
|
||||
typedef test_allocator<T> Alloc;
|
||||
@@ -170,6 +154,22 @@ int main(int, char**)
|
||||
static_assert(std::is_same_v<decltype(q), std::queue<T, std::deque<T, Alloc>>>);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
{
|
||||
std::queue c(std::from_range, std::array<int, 0>());
|
||||
static_assert(std::is_same_v<decltype(c), std::queue<int>>);
|
||||
}
|
||||
|
||||
{
|
||||
using Alloc = test_allocator<int>;
|
||||
std::queue c(std::from_range, std::array<int, 0>(), Alloc());
|
||||
static_assert(std::is_same_v<decltype(c), std::queue<int, std::deque<int, Alloc>>>);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
ContainerAdaptorDeductionGuidesSfinaeAway<std::queue, std::queue<int>>();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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 <queue>
|
||||
|
||||
#include "../../from_range_container_adaptors.h"
|
||||
#include "test_macros.h"
|
||||
|
||||
// template<container-compatible-range<T> R> queue(from_range_t, R&& rg); // since C++23
|
||||
// template<container-compatible-range<T> R, class Alloc>
|
||||
// queue(from_range_t, R&& rg, const Alloc&); // since C++23
|
||||
|
||||
int main(int, char**) {
|
||||
for_all_iterators_and_allocators<int>([]<class Iter, class Sent, class Alloc>() {
|
||||
test_container_adaptor<std::queue, std::deque, int, Iter, Sent, Alloc>();
|
||||
});
|
||||
test_container_adaptor_move_only<std::queue>();
|
||||
|
||||
static_assert(test_constraints<std::queue, int, double>());
|
||||
|
||||
test_exception_safety_throwing_copy<std::queue>();
|
||||
test_exception_safety_throwing_allocator<std::queue, int>();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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>
|
||||
// void push_range(R&& rg); // C++23
|
||||
|
||||
#include <queue>
|
||||
|
||||
#include "../../push_range_container_adaptors.h"
|
||||
#include "test_macros.h"
|
||||
|
||||
int main(int, char**) {
|
||||
for_all_iterators_and_allocators<int, const int*>([]<class Iter, class Sent, class Alloc>() {
|
||||
test_push_range<std::queue<int, std::deque<int, Alloc>>, Iter, Sent>();
|
||||
});
|
||||
test_push_range_move_only<std::queue>();
|
||||
test_push_range_inserter_choice<std::queue, int>();
|
||||
|
||||
static_assert(test_constraints_push_range<std::queue, int, double>());
|
||||
|
||||
test_push_range_exception_safety_throwing_copy<std::queue>();
|
||||
test_push_range_exception_safety_throwing_allocator<std::queue, std::deque, int>();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -14,7 +14,13 @@
|
||||
//
|
||||
// template<class Container, class Allocator>
|
||||
// stack(Container, Allocator) -> stack<typename Container::value_type, Container>;
|
||||
|
||||
//
|
||||
// template<ranges::input_range R>
|
||||
// stack(from_range_t, R&&) -> stack<ranges::range_value_t<R>>; // since C++23
|
||||
//
|
||||
// template<ranges::input_range R, class Allocator>
|
||||
// stack(from_range_t, R&&, Allocator)
|
||||
// -> stack<ranges::range_value_t<R>, deque<ranges::range_value_t<R>, Allocator>>; // since C++23
|
||||
|
||||
#include <array>
|
||||
#include <stack>
|
||||
@@ -138,30 +144,7 @@ int main(int, char**)
|
||||
}
|
||||
}
|
||||
|
||||
// Deduction guides should be SFINAE'd away when given:
|
||||
// - a "bad" allocator (that is, a type not qualifying as an allocator);
|
||||
// - an allocator instead of a container;
|
||||
// - an allocator and a container that uses a different allocator.
|
||||
{
|
||||
using Cont = std::list<int>;
|
||||
using Alloc = std::allocator<int>;
|
||||
using DiffAlloc = test_allocator<int>;
|
||||
using Iter = int;
|
||||
|
||||
struct NotIter {};
|
||||
struct NotAlloc {};
|
||||
|
||||
static_assert(SFINAEs_away<std::stack, Alloc, Alloc>);
|
||||
static_assert(SFINAEs_away<std::stack, Cont, NotAlloc>);
|
||||
static_assert(SFINAEs_away<std::stack, Cont, DiffAlloc>);
|
||||
static_assert(SFINAEs_away<std::stack, Iter, NotIter>);
|
||||
#if TEST_STD_VER > 20
|
||||
static_assert(SFINAEs_away<std::stack, Iter, NotIter, Alloc>);
|
||||
static_assert(SFINAEs_away<std::stack, Iter, Iter, NotAlloc>);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if TEST_STD_VER > 20
|
||||
#if TEST_STD_VER >= 23
|
||||
{
|
||||
typedef short T;
|
||||
typedef test_allocator<T> Alloc;
|
||||
@@ -175,7 +158,22 @@ int main(int, char**)
|
||||
static_assert(std::is_same_v<decltype(s), std::stack<T, std::deque<T, Alloc>>>);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
{
|
||||
std::stack c(std::from_range, std::array<int, 0>());
|
||||
static_assert(std::is_same_v<decltype(c), std::stack<int>>);
|
||||
}
|
||||
|
||||
{
|
||||
using Alloc = test_allocator<int>;
|
||||
std::stack c(std::from_range, std::array<int, 0>(), Alloc());
|
||||
static_assert(std::is_same_v<decltype(c), std::stack<int, std::deque<int, Alloc>>>);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
ContainerAdaptorDeductionGuidesSfinaeAway<std::stack, std::stack<int>>();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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 <stack>
|
||||
|
||||
#include "../../from_range_container_adaptors.h"
|
||||
#include "test_macros.h"
|
||||
|
||||
// template<container-compatible-range<T> R> stack(from_range_t, R&& rg); // since C++23
|
||||
// template<container-compatible-range<T> R, class Alloc>
|
||||
// stack(from_range_t, R&& rg, const Alloc&); // since C++23
|
||||
|
||||
int main(int, char**) {
|
||||
for_all_iterators_and_allocators<int>([]<class Iter, class Sent, class Alloc>() {
|
||||
test_container_adaptor<std::stack, std::deque, int, Iter, Sent, Alloc>();
|
||||
});
|
||||
test_container_adaptor_move_only<std::stack>();
|
||||
|
||||
static_assert(test_constraints<std::stack, int, double>());
|
||||
|
||||
test_exception_safety_throwing_copy<std::stack>();
|
||||
test_exception_safety_throwing_allocator<std::stack, int>();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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>
|
||||
// void push_range(R&& rg); // C++23
|
||||
|
||||
#include <stack>
|
||||
|
||||
#include "../../push_range_container_adaptors.h"
|
||||
#include "test_macros.h"
|
||||
|
||||
int main(int, char**) {
|
||||
for_all_iterators_and_allocators<int, const int*>([]<class Iter, class Sent, class Alloc>() {
|
||||
test_push_range<std::stack<int, std::deque<int, Alloc>>, Iter, Sent>();
|
||||
});
|
||||
test_push_range_move_only<std::stack>();
|
||||
test_push_range_inserter_choice<std::stack, int>();
|
||||
|
||||
static_assert(test_constraints_push_range<std::stack, int, double>());
|
||||
|
||||
test_push_range_exception_safety_throwing_copy<std::stack>();
|
||||
test_push_range_exception_safety_throwing_allocator<std::stack, std::deque, int>();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -108,6 +108,54 @@ constexpr void SequenceContainerDeductionGuidesSfinaeAway() {
|
||||
#endif
|
||||
}
|
||||
|
||||
// Deduction guides should be SFINAE'd away when given:
|
||||
// - a "bad" allocator (that is, a type not qualifying as an allocator);
|
||||
// - an allocator instead of a container;
|
||||
// - an allocator and a container that uses a different allocator;
|
||||
// - a range not satisfying the `input_range` concept.
|
||||
template<template<typename ...> class Container, typename InstantiatedContainer>
|
||||
constexpr void ContainerAdaptorDeductionGuidesSfinaeAway() {
|
||||
using T = typename InstantiatedContainer::value_type;
|
||||
using Alloc = std::allocator<T>;
|
||||
using Iter = T*;
|
||||
|
||||
using BadIter = int;
|
||||
using BadAlloc = Empty;
|
||||
|
||||
// (container) -- no constraints.
|
||||
|
||||
// (container, alloc)
|
||||
//
|
||||
// Cannot deduce from (container, BAD_alloc)
|
||||
static_assert(SFINAEs_away<Container, std::vector<T>, BadAlloc>);
|
||||
|
||||
// (iter, iter)
|
||||
//
|
||||
// Cannot deduce from (BAD_iter, BAD_iter)
|
||||
LIBCPP_STATIC_ASSERT(SFINAEs_away<Container, BadIter, BadIter>);
|
||||
|
||||
#if TEST_STD_VER >= 23
|
||||
using BadRange = BadRangeT<T>;
|
||||
|
||||
// (iter, iter, alloc)
|
||||
//
|
||||
// Cannot deduce from (BAD_iter, BAD_iter, alloc)
|
||||
LIBCPP_STATIC_ASSERT(SFINAEs_away<Container, BadIter, BadIter, Alloc>);
|
||||
// Cannot deduce from (iter, iter, BAD_alloc)
|
||||
static_assert(SFINAEs_away<Container, Iter, Iter, BadAlloc>);
|
||||
|
||||
// (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
|
||||
// given:
|
||||
// - "bad" input iterators (that is, a type not qualifying as an input
|
||||
|
||||
32
libcxx/test/support/unwrap_container_adaptor.h
Normal file
32
libcxx/test/support/unwrap_container_adaptor.h
Normal file
@@ -0,0 +1,32 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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_UNWRAP_CONTAINER_ADAPTOR_H
|
||||
#define SUPPORT_UNWRAP_CONTAINER_ADAPTOR_H
|
||||
|
||||
// Allows accessing the underlying container of the given adaptor.
|
||||
template <class Adaptor>
|
||||
struct UnwrapAdaptor : Adaptor {
|
||||
UnwrapAdaptor() = default;
|
||||
|
||||
UnwrapAdaptor(Adaptor&& adaptor) : Adaptor(std::move(adaptor)) {}
|
||||
// `c` is a protected member variable of the base class.
|
||||
decltype(auto) get_container() {
|
||||
return (UnwrapAdaptor::c); // Put into parentheses to make sure the function returns a reference.
|
||||
}
|
||||
|
||||
// TODO: make this work pre-C++20.
|
||||
decltype(auto) get_comparator()
|
||||
requires requires {
|
||||
UnwrapAdaptor::c;
|
||||
} {
|
||||
return (UnwrapAdaptor::comp); // Put into parentheses to make sure the function returns a reference.
|
||||
}
|
||||
};
|
||||
|
||||
#endif // SUPPORT_UNWRAP_CONTAINER_ADAPTOR_H
|
||||
Reference in New Issue
Block a user