1 //===----------------------------------------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
11 // UNSUPPORTED: c++03, c++11, c++14, c++17
13 // template<class T, class Proj = identity,
14 // indirect_strict_weak_order<projected<const T*, Proj>> Comp = ranges::less>
16 // ranges::clamp(const T& v, const T& lo, const T& hi, Comp comp = {}, Proj proj = {});
25 template <class T
, class Comp
= std::ranges::less
, class Proj
= std::identity
>
27 requires(T
&& val
, T
&& low
, T
&& high
, Comp
&& comp
, Proj
&& proj
) {
28 std::ranges::clamp(std::forward
<T
>(val
), std::forward
<T
>(low
), std::forward
<T
>(high
),
29 std::forward
<Comp
>(comp
), std::forward
<Proj
>(proj
));
34 auto operator()(int) const { return NoComp(); }
37 static_assert(HasClamp
<int, std::ranges::less
, std::identity
>);
38 static_assert(!HasClamp
<NoComp
>);
39 static_assert(!HasClamp
<int, NoComp
>);
40 static_assert(!HasClamp
<int, std::ranges::less
, CreateNoComp
>);
42 struct EnsureValueCategoryComp
{
43 constexpr bool operator()(const int&& x
, const int&& y
) const { return x
< y
; }
44 constexpr bool operator()(const int&& x
, int& y
) const { return x
< y
; }
45 constexpr bool operator()(int& x
, const int&& y
) const { return x
< y
; }
46 constexpr bool operator()(int& x
, int& y
) const { return x
< y
; }
47 constexpr bool operator()(std::same_as
<const int&> auto&& x
, std::same_as
<const int&> auto&& y
) const {
52 constexpr bool test() {
57 std::same_as
<const int&> decltype(auto) ret
= std::ranges::clamp(val
, low
, high
);
63 assert(std::ranges::clamp(10, 20, 30) == 20);
67 assert(std::ranges::clamp(15, 5, 10) == 10);
70 { // low == val == high
72 assert(&std::ranges::clamp(val
, 10, 10) == &val
);
75 { // Check that a custom comparator works.
76 assert(std::ranges::clamp(10, 30, 20, std::ranges::greater
{}) == 20);
79 { // Check that a custom projection works.
82 constexpr bool operator==(S
const& other
) const { return i
== other
.i
; }
88 auto proj
= [](S
const& s
) -> int const& { return s
.i
; };
90 assert(std::ranges::clamp(val
, low
, high
, std::less
{}, proj
) == low
);
93 { // Ensure that we respect the value category of the projection when calling the comparator.
94 // This additional example was provided by Tim Song in https://github.com/microsoft/STL/issues/3970#issuecomment-1685120958.
96 constexpr int const&& operator()(int const& x
) const { return std::move(x
); }
99 static_assert(std::indirect_strict_weak_order
<EnsureValueCategoryComp
, std::projected
<const int*, MoveProj
>>);
101 assert(std::ranges::clamp(0, 1, 2, EnsureValueCategoryComp
{}, MoveProj
{}) == 1);
104 { // Make sure we don't call the projection more than three times per [alg.clamp], see #64717
106 auto projection_function
= [&counter
](const int value
) -> int {
110 assert(std::ranges::clamp(3, 2, 4, std::ranges::less
{}, projection_function
) == 3);
111 #if !(defined(_LIBCPP_ENABLE_SAFE_MODE) || defined(_LIBCPP_ENABLE_DEBUG_MODE))
112 assert(counter
<= 3);
119 int main(int, char**) {
121 static_assert(test());