diff --git a/libcxx/include/__flat_set/flat_set.h b/libcxx/include/__flat_set/flat_set.h index cc45db7565bd4..dca06c7236e73 100644 --- a/libcxx/include/__flat_set/flat_set.h +++ b/libcxx/include/__flat_set/flat_set.h @@ -11,16 +11,16 @@ #define _LIBCPP___FLAT_SET_FLAT_SET_H #include <__algorithm/lexicographical_compare_three_way.h> +#include <__algorithm/lower_bound.h> #include <__algorithm/min.h> #include <__algorithm/ranges_adjacent_find.h> #include <__algorithm/ranges_equal.h> #include <__algorithm/ranges_inplace_merge.h> -#include <__algorithm/ranges_lower_bound.h> #include <__algorithm/ranges_partition_point.h> #include <__algorithm/ranges_sort.h> #include <__algorithm/ranges_unique.h> -#include <__algorithm/ranges_upper_bound.h> #include <__algorithm/remove_if.h> +#include <__algorithm/upper_bound.h> #include <__assert> #include <__compare/synth_three_way.h> #include <__concepts/swappable.h> @@ -382,7 +382,7 @@ class flat_set { template requires(__is_transparent_v<_Compare> && is_constructible_v) _LIBCPP_HIDE_FROM_ABI pair insert(_Kp&& __x) { - return emplace(std::forward<_Kp>(__x)); + return __emplace(std::forward<_Kp>(__x)); } _LIBCPP_HIDE_FROM_ABI iterator insert(const_iterator __hint, const value_type& __x) { return emplace_hint(__hint, __x); @@ -395,7 +395,7 @@ class flat_set { template requires(__is_transparent_v<_Compare> && is_constructible_v) _LIBCPP_HIDE_FROM_ABI iterator insert(const_iterator __hint, _Kp&& __x) { - return emplace_hint(__hint, std::forward<_Kp>(__x)); + return __emplace_hint(__hint, std::forward<_Kp>(__x)); } template @@ -531,43 +531,47 @@ class flat_set { } _LIBCPP_HIDE_FROM_ABI iterator lower_bound(const key_type& __x) { - return iterator(ranges::lower_bound(std::as_const(__keys_), __x, __compare_)); + const auto& __keys = __keys_; + return iterator(std::lower_bound(__keys.begin(), __keys.end(), __x, __compare_)); } _LIBCPP_HIDE_FROM_ABI const_iterator lower_bound(const key_type& __x) const { - return const_iterator(ranges::lower_bound(__keys_, __x, __compare_)); + return const_iterator(std::lower_bound(__keys_.begin(), __keys_.end(), __x, __compare_)); } template requires __is_transparent_v<_Compare> _LIBCPP_HIDE_FROM_ABI iterator lower_bound(const _Kp& __x) { - return iterator(ranges::lower_bound(std::as_const(__keys_), __x, __compare_)); + const auto& __keys = __keys_; + return iterator(std::lower_bound(__keys.begin(), __keys.end(), __x, __compare_)); } template requires __is_transparent_v<_Compare> _LIBCPP_HIDE_FROM_ABI const_iterator lower_bound(const _Kp& __x) const { - return const_iterator(ranges::lower_bound(__keys_, __x, __compare_)); + return const_iterator(std::lower_bound(__keys_.begin(), __keys_.end(), __x, __compare_)); } _LIBCPP_HIDE_FROM_ABI iterator upper_bound(const key_type& __x) { - return iterator(ranges::upper_bound(std::as_const(__keys_), __x, __compare_)); + const auto& __keys = __keys_; + return iterator(std::upper_bound(__keys.begin(), __keys.end(), __x, __compare_)); } _LIBCPP_HIDE_FROM_ABI const_iterator upper_bound(const key_type& __x) const { - return const_iterator(ranges::upper_bound(__keys_, __x, __compare_)); + return const_iterator(std::upper_bound(__keys_.begin(), __keys_.end(), __x, __compare_)); } template requires __is_transparent_v<_Compare> _LIBCPP_HIDE_FROM_ABI iterator upper_bound(const _Kp& __x) { - return iterator(ranges::upper_bound(std::as_const(__keys_), __x, __compare_)); + const auto& __keys = __keys_; + return iterator(std::upper_bound(__keys.begin(), __keys.end(), __x, __compare_)); } template requires __is_transparent_v<_Compare> _LIBCPP_HIDE_FROM_ABI const_iterator upper_bound(const _Kp& __x) const { - return const_iterator(ranges::upper_bound(__keys_, __x, __compare_)); + return const_iterator(std::upper_bound(__keys_.begin(), __keys_.end(), __x, __compare_)); } _LIBCPP_HIDE_FROM_ABI pair equal_range(const key_type& __x) { @@ -668,7 +672,7 @@ class flat_set { template _LIBCPP_HIDE_FROM_ABI static auto __equal_range_impl(_Self&& __self, const _Kp& __key) { using __iter = _If>, const_iterator, iterator>; - auto __it = ranges::lower_bound(__self.__keys_, __key, __self.__compare_); + auto __it = std::lower_bound(__self.__keys_.begin(), __self.__keys_.end(), __key, __self.__compare_); auto __last = __self.__keys_.end(); if (__it == __last || __self.__compare_(__key, *__it)) { return std::make_pair(__iter(__it), __iter(__it)); diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_transparent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_transparent.pass.cpp index 105d2e31ddc91..f60fd78008a30 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_transparent.pass.cpp +++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_transparent.pass.cpp @@ -10,8 +10,8 @@ // -// template pair insert(P&& x); -// template iterator insert(const_iterator hint, P&& x); +// template pair insert(K&& x); +// template iterator insert(const_iterator hint, K&& x); #include #include @@ -27,113 +27,89 @@ #include "test_iterators.h" #include "min_allocator.h" -// Constraints: is_constructible_v is true. +// Constraints: The qualified-id Compare::is_transparent is valid and denotes a type. is_constructible_v is true. template concept CanInsert = requires(M m, Args&&... args) { m.insert(std::forward(args)...); }; -using Set = std::flat_set; -using Iter = Set::const_iterator; +using TransparentSet = std::flat_set; +using TransparentSetIter = typename TransparentSet::iterator; +static_assert(CanInsert>); +static_assert(CanInsert>); +static_assert(!CanInsert>); +static_assert(!CanInsert>); -static_assert(CanInsert); -static_assert(CanInsert); -static_assert(!CanInsert); -static_assert(!CanInsert); - -static int expensive_comparisons = 0; -static int cheap_comparisons = 0; - -struct CompareCounter { - int i_ = 0; - CompareCounter(int i) : i_(i) {} - friend auto operator<=>(const CompareCounter& x, const CompareCounter& y) { - expensive_comparisons += 1; - return x.i_ <=> y.i_; - } - bool operator==(const CompareCounter&) const = default; - friend auto operator<=>(const CompareCounter& x, int y) { - cheap_comparisons += 1; - return x.i_ <=> y; - } -}; +using NonTransparentSet = std::flat_set; +using NonTransparentSetIter = typename NonTransparentSet::iterator; +static_assert(!CanInsert>); +static_assert(!CanInsert>); +static_assert(!CanInsert>); +static_assert(!CanInsert>); template void test_one() { using Key = typename KeyContainer::value_type; - using M = std::flat_set, KeyContainer>; + using M = std::flat_set; - const int expected[] = {1, 2, 3, 4, 5}; { - // insert(P&&) - // Unlike flat_set, here we can't use key_compare to compare value_type versus P, - // so we must eagerly convert to value_type. - M m = {1, 2, 4, 5}; - expensive_comparisons = 0; - cheap_comparisons = 0; - std::same_as> auto p = m.insert(3); // conversion happens first - assert(expensive_comparisons >= 2); - assert(cheap_comparisons == 0); - assert(p == std::make_pair(m.begin() + 2, true)); - assert(std::ranges::equal(m, expected)); - } - { - // insert(const_iterator, P&&) - M m = {1, 2, 4, 5}; - expensive_comparisons = 0; - cheap_comparisons = 0; - std::same_as auto it = m.insert(m.begin(), 3); - assert(expensive_comparisons >= 2); - assert(cheap_comparisons == 0); - assert(it == m.begin() + 2); - assert(std::ranges::equal(m, expected)); - } - { - // insert(value_type&&) - M m = {1, 2, 4, 5}; - expensive_comparisons = 0; - cheap_comparisons = 0; - std::same_as> auto p = m.insert(3); // conversion happens last - assert(expensive_comparisons >= 2); - assert(cheap_comparisons == 0); - assert(p == std::make_pair(m.begin() + 2, true)); - assert(std::ranges::equal(m, expected)); - } - { - // insert(const_iterator, value_type&&) - M m = {1, 2, 4, 5}; - expensive_comparisons = 0; - cheap_comparisons = 0; - std::same_as auto it = m.insert(m.begin(), 3); - assert(expensive_comparisons >= 2); - assert(cheap_comparisons == 0); - assert(it == m.begin() + 2); - assert(std::ranges::equal(m, expected)); - } - { - // emplace(Args&&...) - M m = {1, 2, 4, 5}; - expensive_comparisons = 0; - cheap_comparisons = 0; - std::same_as> auto p = m.emplace(3); // conversion happens first - assert(expensive_comparisons >= 2); - assert(cheap_comparisons == 0); - assert(p == std::make_pair(m.begin() + 2, true)); - assert(std::ranges::equal(m, expected)); + const int expected[] = {1, 2, 3, 4, 5}; + + { + // insert(K&&) + bool transparent_used = false; + M m{{1, 2, 4, 5}, TransparentComparator{transparent_used}}; + assert(!transparent_used); + std::same_as> decltype(auto) r = + m.insert(ExplicitlyConvertibleTransparent{3}); + assert(transparent_used); + assert(r.first == m.begin() + 2); + assert(r.second); + assert(std::ranges::equal(m, expected)); + } + { + // insert(const_iterator, K&&) + bool transparent_used = false; + M m{{1, 2, 4, 5}, TransparentComparator{transparent_used}}; + assert(!transparent_used); + std::same_as auto it = m.insert(m.begin(), ExplicitlyConvertibleTransparent{3}); + assert(transparent_used); + assert(it == m.begin() + 2); + assert(std::ranges::equal(m, expected)); + } } + { // was empty - M m; - std::same_as> auto p = m.insert(3); - assert(p == std::make_pair(m.begin(), true)); - M expected2 = {3}; - assert(std::ranges::equal(m, expected2)); + const int expected[] = {3}; + { + // insert(K&&) + bool transparent_used = false; + M m{{}, TransparentComparator{transparent_used}}; + assert(!transparent_used); + std::same_as> decltype(auto) r = + m.insert(ExplicitlyConvertibleTransparent{3}); + assert(!transparent_used); // no elements to compare against + assert(r.first == m.begin()); + assert(r.second); + assert(std::ranges::equal(m, expected)); + } + { + // insert(const_iterator, K&&) + bool transparent_used = false; + M m{{}, TransparentComparator{transparent_used}}; + assert(!transparent_used); + std::same_as auto it = m.insert(m.begin(), ExplicitlyConvertibleTransparent{3}); + assert(!transparent_used); // no elements to compare against + assert(it == m.begin()); + assert(std::ranges::equal(m, expected)); + } } } void test() { - test_one>(); - test_one>(); - test_one>(); - test_one>>(); + test_one>(); + test_one>(); + test_one>(); + test_one>>(); { // no ambiguity between insert(pos, P&&) and insert(first, last) @@ -153,26 +129,14 @@ void test_exception() { { auto insert_func = [](auto& m, auto key_arg) { using FlatSet = std::decay_t; - struct T { - typename FlatSet::key_type key_; - T(typename FlatSet::key_type key) : key_(key) {} - operator typename FlatSet::value_type() const { return key_; } - }; - T t(key_arg); - m.insert(t); + m.insert(ExplicitlyConvertibleTransparent{key_arg}); }; test_emplace_exception_guarantee(insert_func); } { auto insert_func_iter = [](auto& m, auto key_arg) { using FlatSet = std::decay_t; - struct T { - typename FlatSet::key_type key_; - T(typename FlatSet::key_type key) : key_(key) {} - operator typename FlatSet::value_type() const { return key_; } - }; - T t(key_arg); - m.insert(m.begin(), t); + m.insert(m.begin(), ExplicitlyConvertibleTransparent{key_arg}); }; test_emplace_exception_guarantee(insert_func_iter); } diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/helpers.h b/libcxx/test/std/containers/container.adaptors/flat.set/helpers.h index d686ef5b9a286..6aed4b1cf131d 100644 --- a/libcxx/test/std/containers/container.adaptors/flat.set/helpers.h +++ b/libcxx/test/std/containers/container.adaptors/flat.set/helpers.h @@ -64,7 +64,7 @@ template struct Transparent { T t; - operator T() const + explicit operator T() const requires ConvertibleToT { return t; @@ -72,7 +72,7 @@ struct Transparent { }; template -using ConvertibleTransparent = Transparent; +using ExplicitlyConvertibleTransparent = Transparent; template using NonConvertibleTransparent = Transparent;