From 06521626503d7e6fccbfcd1a39795f9fbe2e46f9 Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Mon, 6 Nov 2023 00:46:08 +0800 Subject: [PATCH 1/6] Correct allocator-extended allocators for `flat_(multi)set` --- stl/inc/flat_set | 47 +++--- tests/std/tests/P1222R4_flat_set/test.cpp | 169 ++++++++++++++++++++++ 2 files changed, 195 insertions(+), 21 deletions(-) diff --git a/stl/inc/flat_set b/stl/inc/flat_set index d31bf71ce01..df55eb490c3 100644 --- a/stl/inc/flat_set +++ b/stl/inc/flat_set @@ -68,10 +68,12 @@ public: _Base_flat_set() : _Mycont(), _Mycomp() {} template <_Allocator_for _Alloc> - _Base_flat_set(const _Deriv& _Set, const _Alloc& _Al) : _Mycont(_Set._Mycont, _Al), _Mycomp(_Set._Mycomp) {} + _Base_flat_set(const _Deriv& _Set, const _Alloc& _Al) + : _Mycont(_STD make_obj_using_allocator(_Al, _Set._Mycont)), _Mycomp(_Set._Mycomp) {} template <_Allocator_for _Alloc> _Base_flat_set(_Deriv&& _Set, const _Alloc& _Al) - : _Mycont(_STD move(_Set).extract(), _Al), _Mycomp(_Set._Mycomp) // intentionally copy comparator, see LWG-2227 + : _Mycont(_STD make_obj_using_allocator(_Al, _STD move(_Set).extract())), + _Mycomp(_Set._Mycomp) // intentionally copy comparator, see LWG-2227 {} explicit _Base_flat_set(container_type _Cont, const key_compare& _Comp = key_compare()) @@ -79,10 +81,11 @@ public: _Make_invariants_fulfilled(); } template <_Allocator_for _Alloc> - _Base_flat_set(const container_type& _Cont, const _Alloc& _Al) : _Base_flat_set(container_type(_Cont, _Al)) {} + _Base_flat_set(const container_type& _Cont, const _Alloc& _Al) + : _Base_flat_set(_STD make_obj_using_allocator(_Al, _Cont)) {} template <_Allocator_for _Alloc> _Base_flat_set(const container_type& _Cont, const key_compare& _Comp, const _Alloc& _Al) - : _Base_flat_set(container_type(_Cont, _Al), _Comp) {} + : _Base_flat_set(_STD make_obj_using_allocator(_Al, _Cont), _Comp) {} _Base_flat_set(_Tsorted, container_type _Cont, const key_compare& _Comp = key_compare()) : _Mycont(_STD move(_Cont)), _Mycomp(_Comp) { @@ -90,68 +93,70 @@ public: } template <_Allocator_for _Alloc> _Base_flat_set(_Tsorted _Tsort, const container_type& _Cont, const _Alloc& _Al) - : _Base_flat_set(_Tsort, container_type(_Cont, _Al)) {} + : _Base_flat_set(_Tsort, _STD make_obj_using_allocator(_Al, _Cont)) {} template <_Allocator_for _Alloc> _Base_flat_set(_Tsorted _Tsort, const container_type& _Cont, const key_compare& _Comp, const _Alloc& _Al) - : _Base_flat_set(_Tsort, container_type(_Cont, _Al), _Comp) {} + : _Base_flat_set(_Tsort, _STD make_obj_using_allocator(_Al, _Cont), _Comp) {} explicit _Base_flat_set(const key_compare& _Comp) : _Mycont(), _Mycomp(_Comp) {} template <_Allocator_for _Alloc> - _Base_flat_set(const key_compare& _Comp, const _Alloc& _Al) : _Mycont(_Al), _Mycomp(_Comp) {} + _Base_flat_set(const key_compare& _Comp, const _Alloc& _Al) + : _Mycont(_STD make_obj_using_allocator(_Al)), _Mycomp(_Comp) {} template <_Allocator_for _Alloc> - explicit _Base_flat_set(const _Alloc& _Al) : _Mycont(_Al), _Mycomp() {} + explicit _Base_flat_set(const _Alloc& _Al) + : _Mycont(_STD make_obj_using_allocator(_Al)), _Mycomp() {} - // FIXME, an allocator-aware container may not support "C(_First, _Last, _Al)". template _Base_flat_set(_Iter _First, _Iter _Last, const key_compare& _Comp = key_compare()) : _Base_flat_set(container_type(_First, _Last), _Comp) {} template _Alloc> _Base_flat_set(_Iter _First, _Iter _Last, const key_compare& _Comp, const _Alloc& _Al) - : _Base_flat_set(container_type(_First, _Last, _Al), _Comp) {} + : _Base_flat_set(_STD make_obj_using_allocator(_Al, _First, _Last), _Comp) {} template _Alloc> - _Base_flat_set(_Iter _First, _Iter _Last, const _Alloc& _Al) : _Base_flat_set(container_type(_First, _Last, _Al)) {} + _Base_flat_set(_Iter _First, _Iter _Last, const _Alloc& _Al) + : _Base_flat_set(_STD make_obj_using_allocator(_Al, _First, _Last)) {} - // FIXME, an allocator-aware container may not support "C(from_range, _STD forward<_Rng>(_Range), _Al)". template <_Container_compatible_range<_Kty> _Rng> _Base_flat_set(from_range_t, _Rng&& _Range) : _Base_flat_set(container_type(from_range, _STD forward<_Rng>(_Range))) {} template <_Container_compatible_range<_Kty> _Rng, _Allocator_for _Alloc> _Base_flat_set(from_range_t, _Rng&& _Range, const _Alloc& _Al) - : _Base_flat_set(container_type(from_range, _STD forward<_Rng>(_Range), _Al)) {} + : _Base_flat_set(_STD make_obj_using_allocator(_Al, from_range, _STD forward<_Rng>(_Range))) {} template <_Container_compatible_range<_Kty> _Rng> _Base_flat_set(from_range_t, _Rng&& _Range, const key_compare& _Comp) : _Base_flat_set(container_type(from_range, _STD forward<_Rng>(_Range)), _Comp) {} template <_Container_compatible_range<_Kty> _Rng, _Allocator_for _Alloc> _Base_flat_set(from_range_t, _Rng&& _Range, const key_compare& _Comp, const _Alloc& _Al) - : _Base_flat_set(container_type(from_range, _STD forward<_Rng>(_Range), _Al), _Comp) {} + : _Base_flat_set( + _STD make_obj_using_allocator(_Al, from_range, _STD forward<_Rng>(_Range)), _Comp) {} template _Base_flat_set(_Tsorted _Tsort, _Iter _First, _Iter _Last, const key_compare& _Comp = key_compare()) : _Base_flat_set(_Tsort, container_type(_First, _Last), _Comp) {} template _Alloc> _Base_flat_set(_Tsorted _Tsort, _Iter _First, _Iter _Last, const key_compare& _Comp, const _Alloc& _Al) - : _Base_flat_set(_Tsort, container_type(_First, _Last, _Al), _Comp) {} + : _Base_flat_set(_Tsort, _STD make_obj_using_allocator(_Al, _First, _Last), _Comp) {} template _Alloc> _Base_flat_set(_Tsorted _Tsort, _Iter _First, _Iter _Last, const _Alloc& _Al) - : _Base_flat_set(_Tsort, container_type(_First, _Last, _Al)) {} + : _Base_flat_set(_Tsort, _STD make_obj_using_allocator(_Al, _First, _Last)) {} - // FIXME, an allocator-aware container may not support "C(_Ilist, _Al)". _Base_flat_set(initializer_list<_Kty> _Ilist, const key_compare& _Comp = key_compare()) : _Base_flat_set(container_type(_Ilist), _Comp) {} template <_Allocator_for _Alloc> _Base_flat_set(initializer_list<_Kty> _Ilist, const key_compare& _Comp, const _Alloc& _Al) - : _Base_flat_set(container_type(_Ilist, _Al), _Comp) {} + : _Base_flat_set(_STD make_obj_using_allocator(_Al, _Ilist), _Comp) {} template <_Allocator_for _Alloc> - _Base_flat_set(initializer_list<_Kty> _Ilist, const _Alloc& _Al) : _Base_flat_set(container_type(_Ilist, _Al)) {} + _Base_flat_set(initializer_list<_Kty> _Ilist, const _Alloc& _Al) + : _Base_flat_set(_STD make_obj_using_allocator(_Al, _Ilist)) {} _Base_flat_set(_Tsorted _Tsort, initializer_list<_Kty> _Ilist, const key_compare& _Comp = key_compare()) : _Base_flat_set(_Tsort, container_type(_Ilist), _Comp) {} template <_Allocator_for _Alloc> _Base_flat_set(_Tsorted _Tsort, initializer_list<_Kty> _Ilist, const key_compare& _Comp, const _Alloc& _Al) - : _Base_flat_set(_Tsort, container_type(_Ilist, _Al), _Comp) {} + : _Base_flat_set(_Tsort, _STD make_obj_using_allocator(_Al, _Ilist), _Comp) {} template <_Allocator_for _Alloc> _Base_flat_set(_Tsorted _Tsort, initializer_list<_Kty> _Ilist, const _Alloc& _Al) - : _Base_flat_set(_Tsort, container_type(_Ilist, _Al)) {} + : _Base_flat_set(_Tsort, _STD make_obj_using_allocator(_Al, _Ilist)) {} _Base_flat_set(const _Base_flat_set&) = default; _Base_flat_set(_Base_flat_set&& _Other) noexcept( diff --git a/tests/std/tests/P1222R4_flat_set/test.cpp b/tests/std/tests/P1222R4_flat_set/test.cpp index e1976302b37..22512b2e659 100644 --- a/tests/std/tests/P1222R4_flat_set/test.cpp +++ b/tests/std/tests/P1222R4_flat_set/test.cpp @@ -11,13 +11,117 @@ #include #include #include +#include #include #include #include +#define TEST_ASSERT(...) assert((__VA_ARGS__)) + using namespace std; using namespace ranges; +template +concept container_compatible_range = input_range && convertible_to, T>; + +template > +class alternative_vector : private vector { // not allocator-aware, but can be used-allocator constructed +private: + using base_type = vector; + +public: + using base_type::allocator_type; + using base_type::const_iterator; + using base_type::const_pointer; + using base_type::const_reference; + using base_type::const_reverse_iterator; + using base_type::difference_type; + using base_type::iterator; + using base_type::pointer; + using base_type::reference; + using base_type::reverse_iterator; + using base_type::size_type; + using base_type::value_type; + + constexpr alternative_vector() noexcept(noexcept(Alloc())) : base_type(Alloc()) {} + constexpr explicit alternative_vector(allocator_arg_t, const Alloc& a) : base_type(a) {} + constexpr explicit alternative_vector(size_type n) : base_type(n) {} + constexpr explicit alternative_vector(allocator_arg_t, const Alloc& a, size_type n) : base_type(n, a) {} + constexpr alternative_vector(size_type n, const T& v) : base_type(n, v) {} + constexpr alternative_vector(allocator_arg_t, const Alloc& a, size_type n, const T& v) : base_type(n, v, a) {} + template + constexpr alternative_vector(InputIt first, InputIt last) : base_type(first, last) {} + template + constexpr alternative_vector(allocator_arg_t, const Alloc& a, InputIt first, InputIt last) + : base_type(first, last, a) {} + template R> + constexpr alternative_vector(from_range_t, R&& rg) : base_type(from_range, forward(rg)) {} + template R> + constexpr alternative_vector(allocator_arg_t, const Alloc& a, from_range_t, R&& rg) + : base_type(from_range, forward(rg), a) {} + + constexpr alternative_vector(allocator_arg_t, const type_identity_t& a, const alternative_vector& other) + : base_type(other, a) {} + constexpr alternative_vector(allocator_arg_t, const type_identity_t& a, alternative_vector&& other) + : base_type(std::move(other), a) {} + constexpr alternative_vector(initializer_list il) : base_type(il) {} + constexpr alternative_vector(allocator_arg_t, const Alloc& a, initializer_list il) : base_type(il, a) {} + + alternative_vector(const alternative_vector&) = default; + alternative_vector(alternative_vector&&) = default; + + alternative_vector& operator=(const alternative_vector&) = default; + alternative_vector& operator=(alternative_vector&&) = default; + constexpr alternative_vector& operator=(initializer_list il) { + base_type::operator=(il); + return *this; + } + + using base_type::assign; + using base_type::assign_range; + using base_type::get_allocator; + + using base_type::begin; + using base_type::end; + using base_type::rbegin; + using base_type::rend; + + using base_type::cbegin; + using base_type::cend; + using base_type::crbegin; + using base_type::crend; + + using base_type::capacity; + using base_type::empty; + using base_type::max_size; + using base_type::reserve; + using base_type::resize; + using base_type::shrink_to_fit; + using base_type::size; + + using base_type::operator[]; + using base_type::at; + using base_type::back; + using base_type::front; + + using base_type::data; + + using base_type::append_range; + using base_type::emplace_back; + using base_type::pop_back; + using base_type::push_back; + + using base_type::emplace; + using base_type::erase; + using base_type::insert; + using base_type::insert_range; + using base_type::swap; + + using base_type::clear; + + friend auto operator<=>(const alternative_vector&, const alternative_vector&) = default; +}; + template void assert_container_requirements(const T& s) { T m = s; @@ -166,6 +270,70 @@ void test_constructors() { assert_all_requirements_and_equals(flat_multiset(std::move(b), allocator{}), {-1, 1, 2, 7, 7, 7, 100}); } +void test_allocator_extended_constructors() { + constexpr allocator ator; + constexpr std::less comp; + { + using fs = flat_set, alternative_vector>; + + fs s0{1, 1, 2, 3, 5, 8}; + alternative_vector v{1, 1, 2, 3, 5, 8}; + alternative_vector v2{1, 2, 3, 5, 8}; + + TEST_ASSERT(fs{comp, ator} == fs{}); + + TEST_ASSERT(fs{s0, ator} == s0); + TEST_ASSERT(fs{fs{s0}, ator} == s0); + + TEST_ASSERT(fs{v, ator} == s0); + TEST_ASSERT(fs{{1, 1, 2, 3, 5, 8}, ator} == s0); + TEST_ASSERT(fs{v.begin(), v.end(), ator} == s0); + TEST_ASSERT(fs{from_range, v, ator} == s0); + + TEST_ASSERT(fs{v, comp, ator} == s0); + TEST_ASSERT(fs{{1, 1, 2, 3, 5, 8}, comp, ator} == s0); + TEST_ASSERT(fs{v.begin(), v.end(), comp, ator} == s0); + TEST_ASSERT(fs{from_range, v, comp, ator} == s0); + + TEST_ASSERT(fs{sorted_unique, v2, ator} == s0); + TEST_ASSERT(fs{sorted_unique, {1, 2, 3, 5, 8}, ator} == s0); + TEST_ASSERT(fs{sorted_unique, v2.begin(), v2.end(), ator} == s0); + + TEST_ASSERT(fs{sorted_unique, v2, comp, ator} == s0); + TEST_ASSERT(fs{sorted_unique, {1, 2, 3, 5, 8}, comp, ator} == s0); + TEST_ASSERT(fs{sorted_unique, v2.begin(), v2.end(), comp, ator} == s0); + } + { + using fms = flat_multiset, alternative_vector>; + + fms s0{1, 1, 2, 3, 5, 8}; + alternative_vector v{1, 1, 2, 3, 5, 8}; + + TEST_ASSERT(fms{comp, ator} == fms{}); + + TEST_ASSERT(fms{s0, ator} == s0); + TEST_ASSERT(fms{fms{s0}, ator} == s0); + + TEST_ASSERT(fms{v, ator} == s0); + TEST_ASSERT(fms{{1, 1, 2, 3, 5, 8}, ator} == s0); + TEST_ASSERT(fms{v.begin(), v.end(), ator} == s0); + TEST_ASSERT(fms{from_range, v, ator} == s0); + + TEST_ASSERT(fms{v, comp, ator} == s0); + TEST_ASSERT(fms{{1, 1, 2, 3, 5, 8}, comp, ator} == s0); + TEST_ASSERT(fms{v.begin(), v.end(), comp, ator} == s0); + TEST_ASSERT(fms{from_range, v, comp, ator} == s0); + + TEST_ASSERT(fms{sorted_equivalent, v, ator} == s0); + TEST_ASSERT(fms{sorted_equivalent, {1, 1, 2, 3, 5, 8}, ator} == s0); + TEST_ASSERT(fms{sorted_equivalent, v.begin(), v.end(), ator} == s0); + + TEST_ASSERT(fms{sorted_equivalent, v, comp, ator} == s0); + TEST_ASSERT(fms{sorted_equivalent, {1, 1, 2, 3, 5, 8}, comp, ator} == s0); + TEST_ASSERT(fms{sorted_equivalent, v.begin(), v.end(), comp, ator} == s0); + } +} + template