Read-only,includes,Hui Xie,`D130116 <https://llvm.org/D130116>`_,✅
Read-only,is_heap,Konstantin Varlamov,`D130547 <https://llvm.org/D130547>`_,✅
Read-only,is_heap_until,Konstantin Varlamov,`D130547 <https://llvm.org/D130547>`_,✅
-Read-only,clamp,Nikolas Klauser,`D126193 <https://llvm.org/D126193>`_,Under review
+Read-only,clamp,Nikolas Klauser,`D126193 <https://llvm.org/D126193>`_,✅
Read-only,is_permutation,Nikolas Klauser,`D127194 <https://llvm.org/D127194>`_,Under review
Read-only,for_each,Nikolas Klauser,`D124332 <https://llvm.org/D124332>`_,✅
Read-only,for_each_n,Nikolas Klauser,`D124332 <https://llvm.org/D124332>`_,✅
__algorithm/ranges_all_of.h
__algorithm/ranges_any_of.h
__algorithm/ranges_binary_search.h
+ __algorithm/ranges_clamp.h
__algorithm/ranges_copy.h
__algorithm/ranges_copy_backward.h
__algorithm/ranges_copy_if.h
#if _LIBCPP_STD_VER > 14
template<class _Tp, class _Compare>
_LIBCPP_NODISCARD_EXT inline
-_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR
+_LIBCPP_INLINE_VISIBILITY constexpr
const _Tp&
clamp(const _Tp& __v, const _Tp& __lo, const _Tp& __hi, _Compare __comp)
{
template<class _Tp>
_LIBCPP_NODISCARD_EXT inline
-_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR
+_LIBCPP_INLINE_VISIBILITY constexpr
const _Tp&
clamp(const _Tp& __v, const _Tp& __lo, const _Tp& __hi)
{
--- /dev/null
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___ALGORITHM_RANGES_CLAMP_H
+#define _LIBCPP___ALGORITHM_RANGES_CLAMP_H
+
+#include <__assert>
+#include <__config>
+#include <__functional/identity.h>
+#include <__functional/invoke.h>
+#include <__functional/ranges_operations.h>
+#include <__iterator/concepts.h>
+#include <__iterator/projected.h>
+#include <__utility/forward.h>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+# pragma GCC system_header
+#endif
+
+#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES)
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+namespace ranges {
+namespace __clamp {
+struct __fn {
+
+ template <class _Type,
+ class _Proj = identity,
+ indirect_strict_weak_order<projected<const _Type*, _Proj>> _Comp = ranges::less>
+ _LIBCPP_HIDE_FROM_ABI constexpr
+ const _Type& operator()(const _Type& __value,
+ const _Type& __low,
+ const _Type& __high,
+ _Comp __comp = {},
+ _Proj __proj = {}) const {
+ _LIBCPP_ASSERT(!bool(std::invoke(__comp, std::invoke(__proj, __high), std::invoke(__proj, __low))),
+ "Bad bounds passed to std::ranges::clamp");
+
+ if (std::invoke(__comp, std::invoke(__proj, __value), std::invoke(__proj, __low)))
+ return __low;
+ else if (std::invoke(__comp, std::invoke(__proj, __high), std::invoke(__proj, __value)))
+ return __high;
+ else
+ return __value;
+ }
+
+};
+} // namespace __clamp
+
+inline namespace __cpo {
+ inline constexpr auto clamp = __clamp::__fn{};
+} // namespace __cpo
+} // namespace ranges
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES)
+
+#endif // _LIBCPP___ALGORITHM_RANGES_CLAMP_H
constexpr borrowed_iterator_t<R>
ranges::replace_if(R&& r, Pred pred, const T& new_value, Proj proj = {}); // since C++20
+ template<class T, class Proj = identity,
+ indirect_strict_weak_order<projected<const T*, Proj>> Comp = ranges::less>
+ constexpr const T&
+ ranges::clamp(const T& v, const T& lo, const T& hi, Comp comp = {}, Proj proj = {}); // since C++20
+
template<input_iterator I1, sentinel_for<I1> S1, input_iterator I2, sentinel_for<I2> S2,
class Proj1 = identity, class Proj2 = identity,
indirect_strict_weak_order<projected<I1, Proj1>,
indirectly_copyable_storable<iterator_t<R>, O>)
constexpr unique_copy_result<borrowed_iterator_t<R>, O>
unique_copy(R&& r, O result, C comp = {}, Proj proj = {}); // Since C++20
+<<<<<<< HEAD
template<class I, class O>
using remove_copy_result = in_out_result<I, O>; // Since C++20
#include <__algorithm/ranges_all_of.h>
#include <__algorithm/ranges_any_of.h>
#include <__algorithm/ranges_binary_search.h>
+#include <__algorithm/ranges_clamp.h>
#include <__algorithm/ranges_copy.h>
#include <__algorithm/ranges_copy_backward.h>
#include <__algorithm/ranges_copy_if.h>
module ranges_all_of { private header "__algorithm/ranges_all_of.h" }
module ranges_any_of { private header "__algorithm/ranges_any_of.h" }
module ranges_binary_search { private header "__algorithm/ranges_binary_search.h" }
+ module ranges_clamp { private header "__algorithm/ranges_clamp.h" }
module ranges_copy { private header "__algorithm/ranges_copy.h" }
module ranges_copy_backward { private header "__algorithm/ranges_copy_backward.h" }
module ranges_copy_if { private header "__algorithm/ranges_copy_if.h" }
(void)std::ranges::any_of(a, UnaryTrue(&copies)); assert(copies == 0);
(void)std::ranges::binary_search(first, last, value, Less(&copies)); assert(copies == 0);
(void)std::ranges::binary_search(a, value, Less(&copies)); assert(copies == 0);
- //(void)std::ranges::clamp(value, value, value, Less(&copies)); assert(copies == 0);
+ (void)std::ranges::clamp(value, value, value, Less(&copies)); assert(copies == 0);
(void)std::ranges::count_if(first, last, UnaryTrue(&copies)); assert(copies == 0);
(void)std::ranges::count_if(a, UnaryTrue(&copies)); assert(copies == 0);
(void)std::ranges::copy_if(first, last, first2, UnaryTrue(&copies)); assert(copies == 0);
(void)std::ranges::any_of(a, UnaryTrue(), Proj(&copies)); assert(copies == 0);
(void)std::ranges::binary_search(first, last, value, Less(), Proj(&copies)); assert(copies == 0);
(void)std::ranges::binary_search(a, value, Less(), Proj(&copies)); assert(copies == 0);
- //(void)std::ranges::clamp(T(), T(), T(), Less(), Proj(&copies)); assert(copies == 0);
+ (void)std::ranges::clamp(T(), T(), T(), Less(), Proj(&copies)); assert(copies == 0);
(void)std::ranges::count(first, last, value, Proj(&copies)); assert(copies == 0);
(void)std::ranges::count(a, value, Proj(&copies)); assert(copies == 0);
(void)std::ranges::count_if(first, last, UnaryTrue(), Proj(&copies)); assert(copies == 0);
#include <__algorithm/ranges_all_of.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_all_of.h'}}
#include <__algorithm/ranges_any_of.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_any_of.h'}}
#include <__algorithm/ranges_binary_search.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_binary_search.h'}}
+#include <__algorithm/ranges_clamp.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_clamp.h'}}
#include <__algorithm/ranges_copy.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_copy.h'}}
#include <__algorithm/ranges_copy_backward.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_copy_backward.h'}}
#include <__algorithm/ranges_copy_if.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_copy_if.h'}}
--- /dev/null
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: has-unix-headers
+// UNSUPPORTED: c++03, c++11, c++14, c++17, libcpp-has-no-incomplete-ranges
+// 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}}
+// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1
+
+// <algorithm>
+
+// In a call to `ranges::clamp(val, low, high)`, `low` must be `<= high`.
+
+#include <algorithm>
+#include <functional>
+
+#include "check_assertion.h"
+
+int main(int, char**) {
+ std::ranges::clamp(1, 2, 0, std::ranges::greater{});
+ TEST_LIBCPP_ASSERT_FAILURE(std::ranges::clamp(1, 2, 0), "Bad bounds passed to std::ranges::clamp");
+
+ std::ranges::clamp(1, 0, 2);
+ TEST_LIBCPP_ASSERT_FAILURE(std::ranges::clamp(1, 0, 2, std::ranges::greater{}),
+ "Bad bounds passed to std::ranges::clamp");
+
+ std::ranges::clamp(1, 1, 1); // Equal bounds should be fine.
+
+ return 0;
+}
--- /dev/null
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// <algorithm>
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+// UNSUPPORTED: libcpp-has-no-incomplete-ranges
+
+// Older Clangs don't properly deduce decltype(auto) with a concept constraint
+// XFAIL: apple-clang-13.0
+
+// template<class T, class Proj = identity,
+// indirect_strict_weak_order<projected<const T*, Proj>> Comp = ranges::less>
+// constexpr const T&
+// ranges::clamp(const T& v, const T& lo, const T& hi, Comp comp = {}, Proj proj = {});
+
+#include <algorithm>
+#include <cassert>
+#include <functional>
+#include <utility>
+
+template <class T, class Comp = std::ranges::less, class Proj = std::identity>
+concept HasClamp =
+ requires(T&& val, T&& low, T&& high, Comp&& comp, Proj&& proj) {
+ std::ranges::clamp(std::forward<T>(val), std::forward<T>(low), std::forward<T>(high),
+ std::forward<Comp>(comp), std::forward<Proj>(proj));
+ };
+
+struct NoComp {};
+struct CreateNoComp {
+ auto operator()(int) const { return NoComp(); }
+};
+
+static_assert(HasClamp<int, std::ranges::less, std::identity>);
+static_assert(!HasClamp<NoComp>);
+static_assert(!HasClamp<int, NoComp>);
+static_assert(!HasClamp<int, std::ranges::less, CreateNoComp>);
+
+constexpr bool test() {
+ { // low < val < high
+ int val = 2;
+ int low = 1;
+ int high = 3;
+ std::same_as<const int&> decltype(auto) ret = std::ranges::clamp(val, low, high);
+ assert(ret == 2);
+ assert(&ret == &val);
+ }
+
+ { // low > val < high
+ assert(std::ranges::clamp(10, 20, 30) == 20);
+ }
+
+ { // low < val > high
+ assert(std::ranges::clamp(15, 5, 10) == 10);
+ }
+
+ { // low == val == high
+ int val = 10;
+ assert(&std::ranges::clamp(val, 10, 10) == &val);
+ }
+
+ { // Check that a custom comparator works.
+ assert(std::ranges::clamp(10, 30, 20, std::ranges::greater{}) == 20);
+ }
+
+ { // Check that a custom projection works.
+ struct S {
+ int i;
+
+ constexpr const int& lvalue_proj() const { return i; }
+ constexpr int prvalue_proj() const { return i; }
+ };
+
+ struct Comp {
+ constexpr bool operator()(const int& lhs, const int& rhs) const { return lhs < rhs; }
+ constexpr bool operator()(int&& lhs, int&& rhs) const { return lhs > rhs; }
+ };
+
+ auto val = S{10};
+ auto low = S{20};
+ auto high = S{30};
+ // Check that the value category of the projection return type is preserved.
+ assert(&std::ranges::clamp(val, low, high, Comp{}, &S::lvalue_proj) == &low);
+ assert(&std::ranges::clamp(val, high, low, Comp{}, &S::prvalue_proj) == &low);
+ }
+
+ { // Check that the implementation doesn't cause double moves (which could result from calling the projection on
+ // `value` once and then forwarding the result into the comparator).
+ struct CheckDoubleMove {
+ int i;
+ bool moved = false;
+
+ constexpr explicit CheckDoubleMove(int set_i) : i(set_i) {}
+ constexpr CheckDoubleMove(const CheckDoubleMove&) = default;
+ constexpr CheckDoubleMove(CheckDoubleMove&& rhs) noexcept : i(rhs.i) {
+ assert(!rhs.moved);
+ rhs.moved = true;
+ }
+ };
+
+ auto val = CheckDoubleMove{20};
+ auto low = CheckDoubleMove{10};
+ auto high = CheckDoubleMove{30};
+
+ auto moving_comp = [](CheckDoubleMove lhs, CheckDoubleMove rhs) { return lhs.i < rhs.i; };
+ auto prvalue_proj = [](const CheckDoubleMove& x) -> CheckDoubleMove { return x; };
+ assert(&std::ranges::clamp(val, low, high, moving_comp, prvalue_proj) == &val);
+ }
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
test(std::ranges::includes, in, in2, binary_pred);
test(std::ranges::is_heap, in, binary_pred);
test(std::ranges::is_heap_until, in, binary_pred);
- //std::ranges::clamp(2, 1, 3, binary_pred);
+ std::ranges::clamp(2, 1, 3, binary_pred);
//test(std::ranges::is_permutation, in, in2, binary_pred);
test(std::ranges::copy_if, in, out, unary_pred);
test(std::ranges::remove_copy_if, in, out, unary_pred);
Bar a{Foo{1}};
Bar b{Foo{2}};
- //Bar c{Foo{3}};
+ Bar c{Foo{3}};
Foo x{2};
size_t count = 1;
test(std::ranges::includes, in, in2, &Foo::binary_pred, &Bar::val, &Bar::val);
test(std::ranges::is_heap, in, &Foo::binary_pred, &Bar::val);
test(std::ranges::is_heap_until, in, &Foo::binary_pred, &Bar::val);
- //std::ranges::clamp(b, a, c, &Foo::binary_pred);
+ std::ranges::clamp(b, a, c, &Foo::binary_pred, &Bar::val);
//test(std::ranges::is_permutation, in, in2, &Foo::binary_pred, &Bar::val, &Bar::val);
test(std::ranges::for_each, in, &Foo::unary_pred, &Bar::val);
std::ranges::for_each_n(in.begin(), count, &Foo::unary_pred, &Bar::val);
static_assert(test(std::ranges::all_of, a, odd));
static_assert(test(std::ranges::any_of, a, odd));
static_assert(test(std::ranges::binary_search, a, 42));
-//static_assert(test(std::ranges::clamp, 42, 42, 42));
+static_assert(test(std::ranges::clamp, 42, 42, 42));
static_assert(test(std::ranges::copy, a, a));
static_assert(test(std::ranges::copy_backward, a, a));
static_assert(test(std::ranges::copy_if, a, a, odd));