181ad6265SDimitry Andric //===----------------------------------------------------------------------===// 281ad6265SDimitry Andric // 381ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 481ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 581ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 681ad6265SDimitry Andric // 781ad6265SDimitry Andric //===----------------------------------------------------------------------===// 881ad6265SDimitry Andric 981ad6265SDimitry Andric #ifndef _LIBCPP___ALGORITHM_RANGES_MINMAX_H 1081ad6265SDimitry Andric #define _LIBCPP___ALGORITHM_RANGES_MINMAX_H 1181ad6265SDimitry Andric 1281ad6265SDimitry Andric #include <__algorithm/min_max_result.h> 1381ad6265SDimitry Andric #include <__algorithm/minmax_element.h> 1481ad6265SDimitry Andric #include <__assert> 1581ad6265SDimitry Andric #include <__concepts/copyable.h> 1606c3fb27SDimitry Andric #include <__concepts/same_as.h> 1781ad6265SDimitry Andric #include <__config> 1881ad6265SDimitry Andric #include <__functional/identity.h> 1981ad6265SDimitry Andric #include <__functional/invoke.h> 2081ad6265SDimitry Andric #include <__functional/ranges_operations.h> 2181ad6265SDimitry Andric #include <__iterator/concepts.h> 2206c3fb27SDimitry Andric #include <__iterator/next.h> 2381ad6265SDimitry Andric #include <__iterator/projected.h> 2481ad6265SDimitry Andric #include <__ranges/access.h> 2581ad6265SDimitry Andric #include <__ranges/concepts.h> 26*0fca6ea1SDimitry Andric #include <__type_traits/desugars_to.h> 2706c3fb27SDimitry Andric #include <__type_traits/is_reference.h> 28*0fca6ea1SDimitry Andric #include <__type_traits/is_trivially_copyable.h> 2906c3fb27SDimitry Andric #include <__type_traits/remove_cvref.h> 3081ad6265SDimitry Andric #include <__utility/forward.h> 3181ad6265SDimitry Andric #include <__utility/move.h> 32bdd1243dSDimitry Andric #include <__utility/pair.h> 3381ad6265SDimitry Andric #include <initializer_list> 3481ad6265SDimitry Andric 3581ad6265SDimitry Andric #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) 3681ad6265SDimitry Andric # pragma GCC system_header 3781ad6265SDimitry Andric #endif 3881ad6265SDimitry Andric 3906c3fb27SDimitry Andric #if _LIBCPP_STD_VER >= 20 4081ad6265SDimitry Andric 4181ad6265SDimitry Andric _LIBCPP_PUSH_MACROS 4281ad6265SDimitry Andric # include <__undef_macros> 4381ad6265SDimitry Andric 4481ad6265SDimitry Andric _LIBCPP_BEGIN_NAMESPACE_STD 4581ad6265SDimitry Andric 4681ad6265SDimitry Andric namespace ranges { 4781ad6265SDimitry Andric template <class _T1> 4881ad6265SDimitry Andric using minmax_result = min_max_result<_T1>; 4981ad6265SDimitry Andric 5081ad6265SDimitry Andric namespace __minmax { 5181ad6265SDimitry Andric struct __fn { 5206c3fb27SDimitry Andric template <class _Type, 5306c3fb27SDimitry Andric class _Proj = identity, 5481ad6265SDimitry Andric indirect_strict_weak_order<projected<const _Type*, _Proj>> _Comp = ranges::less> 55*0fca6ea1SDimitry Andric [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr ranges::minmax_result<const _Type&> 5606c3fb27SDimitry Andric operator()(_LIBCPP_LIFETIMEBOUND const _Type& __a, 5706c3fb27SDimitry Andric _LIBCPP_LIFETIMEBOUND const _Type& __b, 5806c3fb27SDimitry Andric _Comp __comp = {}, 5906c3fb27SDimitry Andric _Proj __proj = {}) const { 6081ad6265SDimitry Andric if (std::invoke(__comp, std::invoke(__proj, __b), std::invoke(__proj, __a))) 6181ad6265SDimitry Andric return {__b, __a}; 6281ad6265SDimitry Andric return {__a, __b}; 6381ad6265SDimitry Andric } 6481ad6265SDimitry Andric 6506c3fb27SDimitry Andric template <copyable _Type, 6606c3fb27SDimitry Andric class _Proj = identity, 6781ad6265SDimitry Andric indirect_strict_weak_order<projected<const _Type*, _Proj>> _Comp = ranges::less> 68*0fca6ea1SDimitry Andric [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr ranges::minmax_result<_Type> 6906c3fb27SDimitry Andric operator()(initializer_list<_Type> __il, _Comp __comp = {}, _Proj __proj = {}) const { 70cb14a3feSDimitry Andric _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( 71cb14a3feSDimitry Andric __il.begin() != __il.end(), "initializer_list has to contain at least one element"); 7281ad6265SDimitry Andric auto __iters = std::__minmax_element_impl(__il.begin(), __il.end(), __comp, __proj); 7381ad6265SDimitry Andric return ranges::minmax_result<_Type>{*__iters.first, *__iters.second}; 7481ad6265SDimitry Andric } 7581ad6265SDimitry Andric 7606c3fb27SDimitry Andric template <input_range _Range, 7706c3fb27SDimitry Andric class _Proj = identity, 7881ad6265SDimitry Andric indirect_strict_weak_order<projected<iterator_t<_Range>, _Proj>> _Comp = ranges::less> 7981ad6265SDimitry Andric requires indirectly_copyable_storable<iterator_t<_Range>, range_value_t<_Range>*> 80*0fca6ea1SDimitry Andric [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr ranges::minmax_result<range_value_t<_Range>> 8106c3fb27SDimitry Andric operator()(_Range&& __r, _Comp __comp = {}, _Proj __proj = {}) const { 8281ad6265SDimitry Andric auto __first = ranges::begin(__r); 8381ad6265SDimitry Andric auto __last = ranges::end(__r); 8481ad6265SDimitry Andric using _ValueT = range_value_t<_Range>; 8581ad6265SDimitry Andric 86cb14a3feSDimitry Andric _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__first != __last, "range has to contain at least one element"); 8781ad6265SDimitry Andric 88*0fca6ea1SDimitry Andric // This optimiation is not in minmax_element because clang doesn't see through the pointers and as a result doesn't 89*0fca6ea1SDimitry Andric // vectorize the code. 90*0fca6ea1SDimitry Andric if constexpr (contiguous_range<_Range> && is_integral_v<_ValueT> && 91*0fca6ea1SDimitry Andric __is_cheap_to_copy<_ValueT> & __is_identity<_Proj>::value && 92*0fca6ea1SDimitry Andric __desugars_to_v<__less_tag, _Comp, _ValueT, _ValueT>) { 93*0fca6ea1SDimitry Andric minmax_result<_ValueT> __result = {__r[0], __r[0]}; 94*0fca6ea1SDimitry Andric for (auto __e : __r) { 95*0fca6ea1SDimitry Andric if (__e < __result.min) 96*0fca6ea1SDimitry Andric __result.min = __e; 97*0fca6ea1SDimitry Andric if (__result.max < __e) 98*0fca6ea1SDimitry Andric __result.max = __e; 99*0fca6ea1SDimitry Andric } 100*0fca6ea1SDimitry Andric return __result; 101*0fca6ea1SDimitry Andric } else if constexpr (forward_range<_Range>) { 10206c3fb27SDimitry Andric // Special-case the one element case. Avoid repeatedly initializing objects from the result of an iterator 10306c3fb27SDimitry Andric // dereference when doing so might not be idempotent. The `if constexpr` avoids the extra branch in cases where 10406c3fb27SDimitry Andric // it's not needed. 10506c3fb27SDimitry Andric if constexpr (!same_as<remove_cvref_t<range_reference_t<_Range>>, _ValueT> || 10606c3fb27SDimitry Andric is_rvalue_reference_v<range_reference_t<_Range>>) { 10706c3fb27SDimitry Andric if (ranges::next(__first) == __last) { 10806c3fb27SDimitry Andric // During initialization, members are allowed to refer to already initialized members 10906c3fb27SDimitry Andric // (see http://eel.is/c++draft/dcl.init.aggr#6) 11006c3fb27SDimitry Andric minmax_result<_ValueT> __result = {*__first, __result.min}; 11106c3fb27SDimitry Andric return __result; 11206c3fb27SDimitry Andric } 11306c3fb27SDimitry Andric } 11481ad6265SDimitry Andric auto __result = std::__minmax_element_impl(__first, __last, __comp, __proj); 11581ad6265SDimitry Andric return {*__result.first, *__result.second}; 11681ad6265SDimitry Andric } else { 11781ad6265SDimitry Andric // input_iterators can't be copied, so the implementation for input_iterators has to store 11881ad6265SDimitry Andric // the values instead of a pointer to the correct values 11981ad6265SDimitry Andric auto __less = [&](auto&& __a, auto&& __b) -> bool { 12006c3fb27SDimitry Andric return std::invoke(__comp, 12106c3fb27SDimitry Andric std::invoke(__proj, std::forward<decltype(__a)>(__a)), 12281ad6265SDimitry Andric std::invoke(__proj, std::forward<decltype(__b)>(__b))); 12381ad6265SDimitry Andric }; 12481ad6265SDimitry Andric 12506c3fb27SDimitry Andric // During initialization, members are allowed to refer to already initialized members 12606c3fb27SDimitry Andric // (see http://eel.is/c++draft/dcl.init.aggr#6) 12781ad6265SDimitry Andric ranges::minmax_result<_ValueT> __result = {*__first, __result.min}; 12881ad6265SDimitry Andric if (__first == __last || ++__first == __last) 12981ad6265SDimitry Andric return __result; 13081ad6265SDimitry Andric 13181ad6265SDimitry Andric if (__less(*__first, __result.min)) 13281ad6265SDimitry Andric __result.min = *__first; 13381ad6265SDimitry Andric else 13481ad6265SDimitry Andric __result.max = *__first; 13581ad6265SDimitry Andric 13681ad6265SDimitry Andric while (++__first != __last) { 13781ad6265SDimitry Andric _ValueT __i = *__first; 13881ad6265SDimitry Andric if (++__first == __last) { 13981ad6265SDimitry Andric if (__less(__i, __result.min)) 14081ad6265SDimitry Andric __result.min = __i; 14181ad6265SDimitry Andric else if (!__less(__i, __result.max)) 14281ad6265SDimitry Andric __result.max = __i; 14381ad6265SDimitry Andric return __result; 14481ad6265SDimitry Andric } 14581ad6265SDimitry Andric 14681ad6265SDimitry Andric if (__less(*__first, __i)) { 14781ad6265SDimitry Andric if (__less(*__first, __result.min)) 14881ad6265SDimitry Andric __result.min = *__first; 14981ad6265SDimitry Andric if (!__less(__i, __result.max)) 15081ad6265SDimitry Andric __result.max = std::move(__i); 15181ad6265SDimitry Andric } else { 15281ad6265SDimitry Andric if (__less(__i, __result.min)) 15381ad6265SDimitry Andric __result.min = std::move(__i); 15481ad6265SDimitry Andric if (!__less(*__first, __result.max)) 15581ad6265SDimitry Andric __result.max = *__first; 15681ad6265SDimitry Andric } 15781ad6265SDimitry Andric } 15881ad6265SDimitry Andric return __result; 15981ad6265SDimitry Andric } 16081ad6265SDimitry Andric } 16181ad6265SDimitry Andric }; 16281ad6265SDimitry Andric } // namespace __minmax 16381ad6265SDimitry Andric 16481ad6265SDimitry Andric inline namespace __cpo { 16581ad6265SDimitry Andric inline constexpr auto minmax = __minmax::__fn{}; 16681ad6265SDimitry Andric } // namespace __cpo 16781ad6265SDimitry Andric } // namespace ranges 16881ad6265SDimitry Andric 16981ad6265SDimitry Andric _LIBCPP_END_NAMESPACE_STD 17081ad6265SDimitry Andric 17181ad6265SDimitry Andric _LIBCPP_POP_MACROS 17281ad6265SDimitry Andric 17306c3fb27SDimitry Andric #endif // _LIBCPP_STD_VER >= 20 17481ad6265SDimitry Andric 17581ad6265SDimitry Andric #endif // _LIBCPP___ALGORITHM_RANGES_MINMAX_H 176