diff --git a/libcxx/benchmarks/CMakeLists.txt b/libcxx/benchmarks/CMakeLists.txt --- a/libcxx/benchmarks/CMakeLists.txt +++ b/libcxx/benchmarks/CMakeLists.txt @@ -108,6 +108,7 @@ target_link_libraries( cxx-benchmarks-flags-libcxx INTERFACE cxx-benchmarks-flags) target_compile_options(cxx-benchmarks-flags-libcxx INTERFACE ${SANITIZER_FLAGS} -Wno-user-defined-literals -Wno-suggest-override) target_link_options( cxx-benchmarks-flags-libcxx INTERFACE -nodefaultlibs "-L${BENCHMARK_LIBCXX_INSTALL}/lib" ${SANITIZER_FLAGS}) +target_link_options( cxx-benchmarks-flags-libcxx INTERFACE -nodefaultlibs "-L${BENCHMARK_LIBCXX_INSTALL}/lib64" ${SANITIZER_FLAGS}) set(libcxx_benchmark_targets) @@ -161,6 +162,7 @@ algorithms/lower_bound.bench.cpp algorithms/make_heap.bench.cpp algorithms/make_heap_then_sort_heap.bench.cpp + algorithms/min.bench.cpp algorithms/min_max_element.bench.cpp algorithms/pop_heap.bench.cpp algorithms/push_heap.bench.cpp diff --git a/libcxx/benchmarks/algorithms/min.bench.cpp b/libcxx/benchmarks/algorithms/min.bench.cpp new file mode 100644 --- /dev/null +++ b/libcxx/benchmarks/algorithms/min.bench.cpp @@ -0,0 +1,70 @@ +#include +#include + +#include + +void run_sizes(auto benchmark) { + benchmark->Arg(1) + ->Arg(2) + ->Arg(3) + ->Arg(4) + ->Arg(5) + ->Arg(6) + ->Arg(7) + ->Arg(8) + ->Arg(9) + ->Arg(10) + ->Arg(11) + ->Arg(12) + ->Arg(13) + ->Arg(14) + ->Arg(15) + ->Arg(16) + ->Arg(17) + ->Arg(18) + ->Arg(19) + ->Arg(20) + ->Arg(21) + ->Arg(22) + ->Arg(23) + ->Arg(24) + ->Arg(25) + ->Arg(26) + ->Arg(27) + ->Arg(28) + ->Arg(29) + ->Arg(30) + ->Arg(31) + ->Arg(32) + ->Arg(64) + ->Arg(512) + ->Arg(1024) + ->Arg(4000) + ->Arg(4096) + ->Arg(5500) + ->Arg(64000) + ->Arg(65536) + ->Arg(70000); +} + +template +static void BM_std_min(benchmark::State& state) { + std::vector vec(state.range(), 3); + + for (auto _ : state) { + benchmark::DoNotOptimize(vec); + benchmark::DoNotOptimize(std::ranges::min(vec)); + } +} +BENCHMARK(BM_std_min)->Apply(run_sizes); +BENCHMARK(BM_std_min)->Apply(run_sizes); +BENCHMARK(BM_std_min)->Apply(run_sizes); +BENCHMARK(BM_std_min)->Apply(run_sizes); +BENCHMARK(BM_std_min<__int128>)->Apply(run_sizes); +BENCHMARK(BM_std_min)->Apply(run_sizes); +BENCHMARK(BM_std_min)->Apply(run_sizes); +BENCHMARK(BM_std_min)->Apply(run_sizes); +BENCHMARK(BM_std_min)->Apply(run_sizes); +BENCHMARK(BM_std_min)->Apply(run_sizes); + +BENCHMARK_MAIN(); diff --git a/libcxx/include/__algorithm/ranges_max.h b/libcxx/include/__algorithm/ranges_max.h --- a/libcxx/include/__algorithm/ranges_max.h +++ b/libcxx/include/__algorithm/ranges_max.h @@ -9,6 +9,7 @@ #ifndef _LIBCPP___ALGORITHM_RANGES_MAX_H #define _LIBCPP___ALGORITHM_RANGES_MAX_H +#include <__algorithm/ranges_min.h> #include <__algorithm/ranges_min_element.h> #include <__assert> #include <__concepts/copyable.h> @@ -67,7 +68,8 @@ _LIBCPP_ASSERT(__first != __last, "range must contain at least one element"); - if constexpr (forward_range<_Rp>) { + if constexpr (forward_range<_Rp> && + (!is_trivially_copyable_v> || sizeof(range_value_t<_Rp>) > 2 * sizeof(size_t))) { auto __comp_lhs_rhs_swapped = [&](auto&& __lhs, auto&& __rhs) { return std::invoke(__comp, __rhs, __lhs); }; return *ranges::__min_element_impl(std::move(__first), std::move(__last), __comp_lhs_rhs_swapped, __proj); } else { diff --git a/libcxx/include/__algorithm/ranges_min.h b/libcxx/include/__algorithm/ranges_min.h --- a/libcxx/include/__algorithm/ranges_min.h +++ b/libcxx/include/__algorithm/ranges_min.h @@ -10,6 +10,7 @@ #define _LIBCPP___ALGORITHM_RANGES_MIN_H #include <__algorithm/ranges_min_element.h> +#include <__algorithm/unwrap_range.h> #include <__assert> #include <__concepts/copyable.h> #include <__config> @@ -20,6 +21,7 @@ #include <__iterator/projected.h> #include <__ranges/access.h> #include <__ranges/concepts.h> +#include <__type_traits/is_trivially_copyable.h> #include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) @@ -61,10 +63,9 @@ range_value_t<_Rp> operator()(_Rp&& __r, _Comp __comp = {}, _Proj __proj = {}) const { auto __first = ranges::begin(__r); auto __last = ranges::end(__r); - _LIBCPP_ASSERT(__first != __last, "range must contain at least one element"); - - if constexpr (forward_range<_Rp>) { + if constexpr (forward_range<_Rp> && + (!is_trivially_copyable_v> || sizeof(range_value_t<_Rp>) > 2 * sizeof(size_t))) { return *ranges::__min_element_impl(__first, __last, __comp, __proj); } else { range_value_t<_Rp> __result = *__first;