diff --git a/benchmarks/CMakeLists.txt b/benchmarks/CMakeLists.txt index ff6c3ad1651..04e942926d7 100644 --- a/benchmarks/CMakeLists.txt +++ b/benchmarks/CMakeLists.txt @@ -111,6 +111,7 @@ add_benchmark(filesystem src/filesystem.cpp) add_benchmark(fill src/fill.cpp) add_benchmark(find_and_count src/find_and_count.cpp) add_benchmark(find_first_of src/find_first_of.cpp) +add_benchmark(flat_meow_assign src/flat_meow_assign.cpp) add_benchmark(has_single_bit src/has_single_bit.cpp) add_benchmark(includes src/includes.cpp) add_benchmark(integer_to_string src/integer_to_string.cpp) diff --git a/benchmarks/src/flat_meow_assign.cpp b/benchmarks/src/flat_meow_assign.cpp new file mode 100644 index 00000000000..07b718695f5 --- /dev/null +++ b/benchmarks/src/flat_meow_assign.cpp @@ -0,0 +1,52 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include + +using namespace std; + +void flat_map_strings(benchmark::State& state) { + flat_map pieces; + for (auto _ : state) { + pieces = {{"soldier"s, 1}, {"soldier"s, 2}, {"soldier"s, 3}, {"soldier"s, 4}, {"soldier"s, 5}, {"soldier"s, 6}, + {"soldier"s, 7}, {"soldier"s, 8}, {"tower"s, 9}, {"horse"s, 10}, {"elephant"s, 11}, {"vizier"s, 12}, + {"king"s, 13}, {"elephant"s, 14}, {"horse"s, 15}, {"tower"s, 16}}; + benchmark::DoNotOptimize(pieces); + } +} + +void flat_set_strings(benchmark::State& state) { + flat_set pieces; + for (auto _ : state) { + pieces = {"soldier"s, "soldier"s, "soldier"s, "soldier"s, "soldier"s, "soldier"s, "soldier"s, "soldier"s, + "tower"s, "horse"s, "elephant"s, "vizier"s, "king"s, "elephant"s, "horse"s, "tower"s}; + benchmark::DoNotOptimize(pieces); + } +} + +void flat_map_integers(benchmark::State& state) { + flat_map pieces; + for (auto _ : state) { + pieces = {{'s', 1}, {'s', 2}, {'s', 3}, {'s', 4}, {'s', 5}, {'s', 6}, {'s', 7}, {'s', 8}, {'T', 9}, {'H', 10}, + {'E', 11}, {'V', 12}, {'K', 13}, {'E', 14}, {'H', 15}, {'T', 16}}; + benchmark::DoNotOptimize(pieces); + } +} + +void flat_set_integers(benchmark::State& state) { + flat_set pieces; + for (auto _ : state) { + pieces = {'s', 's', 's', 's', 's', 's', 's', 's', 'T', 'H', 'E', 'V', 'K', 'E', 'H', 'T'}; + benchmark::DoNotOptimize(pieces); + } +} + +BENCHMARK(flat_map_strings); +BENCHMARK(flat_set_strings); +BENCHMARK(flat_map_integers); +BENCHMARK(flat_set_integers); + +BENCHMARK_MAIN(); diff --git a/stl/inc/__msvc_string_view.hpp b/stl/inc/__msvc_string_view.hpp index 587f09a142c..303653318e3 100644 --- a/stl/inc/__msvc_string_view.hpp +++ b/stl/inc/__msvc_string_view.hpp @@ -2148,6 +2148,12 @@ inline namespace literals { } // namespace string_view_literals } // namespace literals #endif // _HAS_CXX17 + +#if _HAS_CXX23 +template +constexpr bool _Equivalence_is_equality_impl> = + _Is_implementation_handled_char_traits<_Traits>; +#endif // _HAS_CXX23 _STD_END #pragma pop_macro("new") diff --git a/stl/inc/flat_map b/stl/inc/flat_map index 9593e99bec1..394fa0394ad 100644 --- a/stl/inc/flat_map +++ b/stl/inc/flat_map @@ -1084,12 +1084,21 @@ private: _STL_INTERNAL_CHECK(_Is_sorted_and_unique()); } + auto _Erase_dupes_if_not_multi_pred() { + _STL_INTERNAL_STATIC_ASSERT(_IsUnique); + if constexpr (_Equivalence_is_equality<_Compare, _Key>) { + return [](const_reference _Left, const_reference _Right) + _STATIC_CALL_OPERATOR { return _Left.first == _Right.first; }; + } else { + return + [this](const_reference _Left, const_reference _Right) { return _Key_equal(_Left.first, _Right.first); }; + } + } + void _Erase_dupes_if_not_multi() { if constexpr (_IsUnique) { auto _Sorted_view = _View_to_mutate(); - const auto _New_last = _RANGES unique(_Sorted_view, [this](const_reference _Left, const_reference _Right) { - return this->_Key_equal(_Left.first, _Right.first); - }).begin(); + const auto _New_last = _RANGES unique(_Sorted_view, _Erase_dupes_if_not_multi_pred()).begin(); _Data.keys.erase(_New_last._Key_it, _Data.keys.end()); _Data.values.erase(_New_last._Mapped_it, _Data.values.end()); diff --git a/stl/inc/flat_set b/stl/inc/flat_set index 5491de0dee9..d5de1e9ff2e 100644 --- a/stl/inc/flat_set +++ b/stl/inc/flat_set @@ -705,13 +705,20 @@ private: } } + auto _Erase_dupes_if_not_multi_pred() { + _STL_INTERNAL_STATIC_ASSERT(_IsUnique); + if constexpr (_Equivalence_is_equality<_Keylt, _Kty>) { + return equal_to<>{}; + } else { + return + [this](const _Kty& _Lhs, const _Kty& _Rhs) { return !_Compare(_Lhs, _Rhs) && !_Compare(_Rhs, _Lhs); }; + } + } + void _Erase_dupes_if_not_multi() { if constexpr (_IsUnique) { - const auto _Equivalent = [this](const _Kty& _Lhs, const _Kty& _Rhs) { - return !_Compare(_Lhs, _Rhs) && !_Compare(_Rhs, _Lhs); - }; const auto _End = _Mycont.end(); - _Mycont.erase(_STD unique(_Mycont.begin(), _End, _Equivalent), _End); + _Mycont.erase(_STD unique(_Mycont.begin(), _End, _Erase_dupes_if_not_multi_pred()), _End); } } diff --git a/stl/inc/xstring b/stl/inc/xstring index 1af2f85fe18..1617a4aa381 100644 --- a/stl/inc/xstring +++ b/stl/inc/xstring @@ -3236,6 +3236,12 @@ private: #pragma warning(pop) +#if _HAS_CXX23 +template +constexpr bool _Equivalence_is_equality_impl> = + _Is_implementation_handled_char_traits<_Traits>; +#endif // _HAS_CXX23 + #if _HAS_CXX17 template >, enable_if_t, _Is_allocator<_Alloc>>, int> = 0> diff --git a/stl/inc/xutility b/stl/inc/xutility index 6988002faeb..39e202b8c27 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -7920,6 +7920,16 @@ _NODISCARD constexpr bool _Mul_overflow(const _Int _Left, const _Int _Right, _In } #endif // _HAS_CXX17 +#if _HAS_CXX23 +template +constexpr bool _Equivalence_is_equality_impl = is_integral_v<_Ty> || is_pointer_v<_Ty>; + +// For ranges::less and ranges::greater, see N5032 [range.cmp]/9, [concept.totallyordered]/1.1, [cmp.concept]/1.2. +template +constexpr bool _Equivalence_is_equality = + _Is_any_of_v<_Compare, _RANGES less, _RANGES greater> + || (_Is_any_of_v<_Compare, less<>, less<_Key>, greater<>, greater<_Key>> && _Equivalence_is_equality_impl<_Key>); +#endif // _HAS_CXX23 _STD_END // TRANSITION, non-_Ugly attribute tokens