Skip to content

Commit f20566d

Browse files
philnik777tstellar
authored andcommitted
[libc++][ranges] Implement ranges::clamp
Differential Revision: https://reviews.llvm.org/D126193 (cherry picked from commit a203acb)
1 parent 33e5f15 commit f20566d

14 files changed

+241
-9
lines changed

libcxx/docs/Status/RangesAlgorithms.csv

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ Read-only,is_sorted_until,Nikolas Klauser,`D125608 <https://llvm.org/D125608>`_,
3232
Read-only,includes,Hui Xie,`D130116 <https://llvm.org/D130116>`_,✅
3333
Read-only,is_heap,Konstantin Varlamov,`D130547 <https://llvm.org/D130547>`_,✅
3434
Read-only,is_heap_until,Konstantin Varlamov,`D130547 <https://llvm.org/D130547>`_,✅
35-
Read-only,clamp,Nikolas Klauser,`D126193 <https://llvm.org/D126193>`_,Under review
35+
Read-only,clamp,Nikolas Klauser,`D126193 <https://llvm.org/D126193>`_,
3636
Read-only,is_permutation,Nikolas Klauser,`D127194 <https://llvm.org/D127194>`_,Under review
3737
Read-only,for_each,Nikolas Klauser,`D124332 <https://llvm.org/D124332>`_,✅
3838
Read-only,for_each_n,Nikolas Klauser,`D124332 <https://llvm.org/D124332>`_,✅

libcxx/include/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ set(files
7272
__algorithm/ranges_all_of.h
7373
__algorithm/ranges_any_of.h
7474
__algorithm/ranges_binary_search.h
75+
__algorithm/ranges_clamp.h
7576
__algorithm/ranges_copy.h
7677
__algorithm/ranges_copy_backward.h
7778
__algorithm/ranges_copy_if.h

libcxx/include/__algorithm/clamp.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD
2222
#if _LIBCPP_STD_VER > 14
2323
template<class _Tp, class _Compare>
2424
_LIBCPP_NODISCARD_EXT inline
25-
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR
25+
_LIBCPP_INLINE_VISIBILITY constexpr
2626
const _Tp&
2727
clamp(const _Tp& __v, const _Tp& __lo, const _Tp& __hi, _Compare __comp)
2828
{
@@ -33,7 +33,7 @@ clamp(const _Tp& __v, const _Tp& __lo, const _Tp& __hi, _Compare __comp)
3333

3434
template<class _Tp>
3535
_LIBCPP_NODISCARD_EXT inline
36-
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR
36+
_LIBCPP_INLINE_VISIBILITY constexpr
3737
const _Tp&
3838
clamp(const _Tp& __v, const _Tp& __lo, const _Tp& __hi)
3939
{
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
//===----------------------------------------------------------------------===//
2+
//
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
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef _LIBCPP___ALGORITHM_RANGES_CLAMP_H
10+
#define _LIBCPP___ALGORITHM_RANGES_CLAMP_H
11+
12+
#include <__assert>
13+
#include <__config>
14+
#include <__functional/identity.h>
15+
#include <__functional/invoke.h>
16+
#include <__functional/ranges_operations.h>
17+
#include <__iterator/concepts.h>
18+
#include <__iterator/projected.h>
19+
#include <__utility/forward.h>
20+
21+
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
22+
# pragma GCC system_header
23+
#endif
24+
25+
#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES)
26+
27+
_LIBCPP_BEGIN_NAMESPACE_STD
28+
29+
namespace ranges {
30+
namespace __clamp {
31+
struct __fn {
32+
33+
template <class _Type,
34+
class _Proj = identity,
35+
indirect_strict_weak_order<projected<const _Type*, _Proj>> _Comp = ranges::less>
36+
_LIBCPP_HIDE_FROM_ABI constexpr
37+
const _Type& operator()(const _Type& __value,
38+
const _Type& __low,
39+
const _Type& __high,
40+
_Comp __comp = {},
41+
_Proj __proj = {}) const {
42+
_LIBCPP_ASSERT(!bool(std::invoke(__comp, std::invoke(__proj, __high), std::invoke(__proj, __low))),
43+
"Bad bounds passed to std::ranges::clamp");
44+
45+
if (std::invoke(__comp, std::invoke(__proj, __value), std::invoke(__proj, __low)))
46+
return __low;
47+
else if (std::invoke(__comp, std::invoke(__proj, __high), std::invoke(__proj, __value)))
48+
return __high;
49+
else
50+
return __value;
51+
}
52+
53+
};
54+
} // namespace __clamp
55+
56+
inline namespace __cpo {
57+
inline constexpr auto clamp = __clamp::__fn{};
58+
} // namespace __cpo
59+
} // namespace ranges
60+
61+
_LIBCPP_END_NAMESPACE_STD
62+
63+
#endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES)
64+
65+
#endif // _LIBCPP___ALGORITHM_RANGES_CLAMP_H

libcxx/include/algorithm

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -593,6 +593,11 @@ namespace ranges {
593593
constexpr borrowed_iterator_t<R>
594594
ranges::replace_if(R&& r, Pred pred, const T& new_value, Proj proj = {}); // since C++20
595595
596+
template<class T, class Proj = identity,
597+
indirect_strict_weak_order<projected<const T*, Proj>> Comp = ranges::less>
598+
constexpr const T&
599+
ranges::clamp(const T& v, const T& lo, const T& hi, Comp comp = {}, Proj proj = {}); // since C++20
600+
596601
template<input_iterator I1, sentinel_for<I1> S1, input_iterator I2, sentinel_for<I2> S2,
597602
class Proj1 = identity, class Proj2 = identity,
598603
indirect_strict_weak_order<projected<I1, Proj1>,
@@ -931,6 +936,7 @@ namespace ranges {
931936
indirectly_copyable_storable<iterator_t<R>, O>)
932937
constexpr unique_copy_result<borrowed_iterator_t<R>, O>
933938
unique_copy(R&& r, O result, C comp = {}, Proj proj = {}); // Since C++20
939+
<<<<<<< HEAD
934940
935941
template<class I, class O>
936942
using remove_copy_result = in_out_result<I, O>; // Since C++20
@@ -1764,6 +1770,7 @@ template <class BidirectionalIterator, class Compare>
17641770
#include <__algorithm/ranges_all_of.h>
17651771
#include <__algorithm/ranges_any_of.h>
17661772
#include <__algorithm/ranges_binary_search.h>
1773+
#include <__algorithm/ranges_clamp.h>
17671774
#include <__algorithm/ranges_copy.h>
17681775
#include <__algorithm/ranges_copy_backward.h>
17691776
#include <__algorithm/ranges_copy_if.h>

libcxx/include/module.modulemap.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,7 @@ module std [system] {
311311
module ranges_all_of { private header "__algorithm/ranges_all_of.h" }
312312
module ranges_any_of { private header "__algorithm/ranges_any_of.h" }
313313
module ranges_binary_search { private header "__algorithm/ranges_binary_search.h" }
314+
module ranges_clamp { private header "__algorithm/ranges_clamp.h" }
314315
module ranges_copy { private header "__algorithm/ranges_copy.h" }
315316
module ranges_copy_backward { private header "__algorithm/ranges_copy_backward.h" }
316317
module ranges_copy_if { private header "__algorithm/ranges_copy_if.h" }

libcxx/test/libcxx/algorithms/ranges_robust_against_copying_comparators.pass.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ constexpr bool all_the_algorithms()
9898
(void)std::ranges::any_of(a, UnaryTrue(&copies)); assert(copies == 0);
9999
(void)std::ranges::binary_search(first, last, value, Less(&copies)); assert(copies == 0);
100100
(void)std::ranges::binary_search(a, value, Less(&copies)); assert(copies == 0);
101-
//(void)std::ranges::clamp(value, value, value, Less(&copies)); assert(copies == 0);
101+
(void)std::ranges::clamp(value, value, value, Less(&copies)); assert(copies == 0);
102102
(void)std::ranges::count_if(first, last, UnaryTrue(&copies)); assert(copies == 0);
103103
(void)std::ranges::count_if(a, UnaryTrue(&copies)); assert(copies == 0);
104104
(void)std::ranges::copy_if(first, last, first2, UnaryTrue(&copies)); assert(copies == 0);

libcxx/test/libcxx/algorithms/ranges_robust_against_copying_projections.pass.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ constexpr bool all_the_algorithms()
8080
(void)std::ranges::any_of(a, UnaryTrue(), Proj(&copies)); assert(copies == 0);
8181
(void)std::ranges::binary_search(first, last, value, Less(), Proj(&copies)); assert(copies == 0);
8282
(void)std::ranges::binary_search(a, value, Less(), Proj(&copies)); assert(copies == 0);
83-
//(void)std::ranges::clamp(T(), T(), T(), Less(), Proj(&copies)); assert(copies == 0);
83+
(void)std::ranges::clamp(T(), T(), T(), Less(), Proj(&copies)); assert(copies == 0);
8484
(void)std::ranges::count(first, last, value, Proj(&copies)); assert(copies == 0);
8585
(void)std::ranges::count(a, value, Proj(&copies)); assert(copies == 0);
8686
(void)std::ranges::count_if(first, last, UnaryTrue(), Proj(&copies)); assert(copies == 0);

libcxx/test/libcxx/private_headers.verify.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ END-SCRIPT
109109
#include <__algorithm/ranges_all_of.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_all_of.h'}}
110110
#include <__algorithm/ranges_any_of.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_any_of.h'}}
111111
#include <__algorithm/ranges_binary_search.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_binary_search.h'}}
112+
#include <__algorithm/ranges_clamp.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_clamp.h'}}
112113
#include <__algorithm/ranges_copy.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_copy.h'}}
113114
#include <__algorithm/ranges_copy_backward.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_copy_backward.h'}}
114115
#include <__algorithm/ranges_copy_if.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_copy_if.h'}}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
//===----------------------------------------------------------------------===//
2+
//
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
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
// REQUIRES: has-unix-headers
10+
// UNSUPPORTED: c++03, c++11, c++14, c++17, libcpp-has-no-incomplete-ranges
11+
// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx{{10.9|10.10|10.11|10.12|10.13|10.14|10.15|11.0|12.0}}
12+
// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1
13+
14+
// <algorithm>
15+
16+
// In a call to `ranges::clamp(val, low, high)`, `low` must be `<= high`.
17+
18+
#include <algorithm>
19+
#include <functional>
20+
21+
#include "check_assertion.h"
22+
23+
int main(int, char**) {
24+
std::ranges::clamp(1, 2, 0, std::ranges::greater{});
25+
TEST_LIBCPP_ASSERT_FAILURE(std::ranges::clamp(1, 2, 0), "Bad bounds passed to std::ranges::clamp");
26+
27+
std::ranges::clamp(1, 0, 2);
28+
TEST_LIBCPP_ASSERT_FAILURE(std::ranges::clamp(1, 0, 2, std::ranges::greater{}),
29+
"Bad bounds passed to std::ranges::clamp");
30+
31+
std::ranges::clamp(1, 1, 1); // Equal bounds should be fine.
32+
33+
return 0;
34+
}

0 commit comments

Comments
 (0)