forked from OSchip/llvm-project
[libc++][ranges] Implement ranges::binary_search and ranges::{lower, upper}_bound
Reviewed By: Mordante, var-const, ldionne, #libc Spies: sstefan1, libcxx-commits, mgorny Differential Revision: https://reviews.llvm.org/D121964
This commit is contained in:
parent
881125ad91
commit
8171586176
|
@ -160,6 +160,7 @@ endfunction()
|
||||||
# Register Benchmark tests
|
# Register Benchmark tests
|
||||||
#==============================================================================
|
#==============================================================================
|
||||||
set(BENCHMARK_TESTS
|
set(BENCHMARK_TESTS
|
||||||
|
algorithms/lower_bound.bench.cpp
|
||||||
algorithms/make_heap.bench.cpp
|
algorithms/make_heap.bench.cpp
|
||||||
algorithms/make_heap_then_sort_heap.bench.cpp
|
algorithms/make_heap_then_sort_heap.bench.cpp
|
||||||
algorithms/min_max_element.bench.cpp
|
algorithms/min_max_element.bench.cpp
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// 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
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <numeric>
|
||||||
|
#include <random>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
template <class ValueType>
|
||||||
|
struct LowerBound {
|
||||||
|
size_t Quantity;
|
||||||
|
|
||||||
|
mutable std::mt19937_64 rng { std::random_device{}() };
|
||||||
|
|
||||||
|
void run(benchmark::State& state) const {
|
||||||
|
runOpOnCopies<ValueType>(state, Quantity, Order::Ascending, BatchSize::CountBatch, [&](auto& Copy) {
|
||||||
|
auto result = std::lower_bound(Copy.begin(), Copy.end(), Copy[rng() % Copy.size()]);
|
||||||
|
benchmark::DoNotOptimize(result);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string name() const {
|
||||||
|
return "BM_LowerBound" + ValueType::name() + "_" + std::to_string(Quantity);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
int main(int argc, char** argv) {
|
||||||
|
benchmark::Initialize(&argc, argv);
|
||||||
|
if (benchmark::ReportUnrecognizedArguments(argc, argv))
|
||||||
|
return 1;
|
||||||
|
makeCartesianProductBenchmark<LowerBound, AllValueTypes>(Quantities);
|
||||||
|
benchmark::RunSpecifiedBenchmarks();
|
||||||
|
}
|
|
@ -11,10 +11,10 @@ Search,mismatch,Nikolas Klauser,`D117817 <https://llvm.org/D117817>`_,✅
|
||||||
Search,equal,Nikolas Klauser,`D123681 <https://reviews.llvm.org/D123681>`_,✅
|
Search,equal,Nikolas Klauser,`D123681 <https://reviews.llvm.org/D123681>`_,✅
|
||||||
Search,lexicographical_compare,Not assigned,n/a,Not started
|
Search,lexicographical_compare,Not assigned,n/a,Not started
|
||||||
Search,partition_point,Christopher Di Bella,`D105794 <https://llvm.org/D105794>`_,Under review
|
Search,partition_point,Christopher Di Bella,`D105794 <https://llvm.org/D105794>`_,Under review
|
||||||
Search,lower_bound,Nikolas Klauser,`D121964 <https://llvm.org/D121964>`_,Under review
|
Search,lower_bound,Nikolas Klauser,`D121964 <https://llvm.org/D121964>`_,✅
|
||||||
Search,upper_bound,Nikolas Klauser,`D121964 <https://llvm.org/D121964>`_,Under review
|
Search,upper_bound,Nikolas Klauser,`D121964 <https://llvm.org/D121964>`_,✅
|
||||||
Search,equal_range,Christopher Di Bella,n/a,Not started
|
Search,equal_range,Christopher Di Bella,n/a,Not started
|
||||||
Search,binary_search,Nikolas Klauser,`D121964 <https://llvm.org/D121964>`_,Under review
|
Search,binary_search,Nikolas Klauser,`D121964 <https://llvm.org/D121964>`_,✅
|
||||||
Search,min,Nikolas Klauser,`D119589 <https://llvm.org/D119589>`_,✅
|
Search,min,Nikolas Klauser,`D119589 <https://llvm.org/D119589>`_,✅
|
||||||
Search,max,Nikolas Klauser,`D122002 <https://llvm.org/D122002>`_,✅
|
Search,max,Nikolas Klauser,`D122002 <https://llvm.org/D122002>`_,✅
|
||||||
Search,minmax,Nikolas Klauser,`D120637 <https://llvm.org/D120637>`_,✅
|
Search,minmax,Nikolas Klauser,`D120637 <https://llvm.org/D120637>`_,✅
|
||||||
|
|
|
|
@ -68,6 +68,7 @@ set(files
|
||||||
__algorithm/push_heap.h
|
__algorithm/push_heap.h
|
||||||
__algorithm/ranges_all_of.h
|
__algorithm/ranges_all_of.h
|
||||||
__algorithm/ranges_any_of.h
|
__algorithm/ranges_any_of.h
|
||||||
|
__algorithm/ranges_binary_search.h
|
||||||
__algorithm/ranges_copy.h
|
__algorithm/ranges_copy.h
|
||||||
__algorithm/ranges_copy_backward.h
|
__algorithm/ranges_copy_backward.h
|
||||||
__algorithm/ranges_copy_if.h
|
__algorithm/ranges_copy_if.h
|
||||||
|
@ -85,6 +86,7 @@ set(files
|
||||||
__algorithm/ranges_is_partitioned.h
|
__algorithm/ranges_is_partitioned.h
|
||||||
__algorithm/ranges_is_sorted.h
|
__algorithm/ranges_is_sorted.h
|
||||||
__algorithm/ranges_is_sorted_until.h
|
__algorithm/ranges_is_sorted_until.h
|
||||||
|
__algorithm/ranges_lower_bound.h
|
||||||
__algorithm/ranges_max.h
|
__algorithm/ranges_max.h
|
||||||
__algorithm/ranges_max_element.h
|
__algorithm/ranges_max_element.h
|
||||||
__algorithm/ranges_min.h
|
__algorithm/ranges_min.h
|
||||||
|
@ -96,6 +98,7 @@ set(files
|
||||||
__algorithm/ranges_reverse.h
|
__algorithm/ranges_reverse.h
|
||||||
__algorithm/ranges_swap_ranges.h
|
__algorithm/ranges_swap_ranges.h
|
||||||
__algorithm/ranges_transform.h
|
__algorithm/ranges_transform.h
|
||||||
|
__algorithm/ranges_upper_bound.h
|
||||||
__algorithm/remove.h
|
__algorithm/remove.h
|
||||||
__algorithm/remove_copy.h
|
__algorithm/remove_copy.h
|
||||||
__algorithm/remove_copy_if.h
|
__algorithm/remove_copy_if.h
|
||||||
|
|
|
@ -21,23 +21,15 @@
|
||||||
|
|
||||||
_LIBCPP_BEGIN_NAMESPACE_STD
|
_LIBCPP_BEGIN_NAMESPACE_STD
|
||||||
|
|
||||||
template <class _Compare, class _ForwardIterator, class _Tp>
|
|
||||||
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
|
|
||||||
bool
|
|
||||||
__binary_search(_ForwardIterator __first, _ForwardIterator __last, const _Tp& __value_, _Compare __comp)
|
|
||||||
{
|
|
||||||
__first = _VSTD::__lower_bound<_Compare>(__first, __last, __value_, __comp);
|
|
||||||
return __first != __last && !__comp(__value_, *__first);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class _ForwardIterator, class _Tp, class _Compare>
|
template <class _ForwardIterator, class _Tp, class _Compare>
|
||||||
_LIBCPP_NODISCARD_EXT inline
|
_LIBCPP_NODISCARD_EXT inline
|
||||||
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
|
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
|
||||||
bool
|
bool
|
||||||
binary_search(_ForwardIterator __first, _ForwardIterator __last, const _Tp& __value_, _Compare __comp)
|
binary_search(_ForwardIterator __first, _ForwardIterator __last, const _Tp& __value_, _Compare __comp)
|
||||||
{
|
{
|
||||||
typedef typename __comp_ref_type<_Compare>::type _Comp_ref;
|
using _Comp_ref = typename __comp_ref_type<_Compare>::type;
|
||||||
return _VSTD::__binary_search<_Comp_ref>(__first, __last, __value_, __comp);
|
__first = std::lower_bound<_ForwardIterator, _Tp, _Comp_ref>(__first, __last, __value_, __comp);
|
||||||
|
return __first != __last && !__comp(__value_, *__first);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class _ForwardIterator, class _Tp>
|
template <class _ForwardIterator, class _Tp>
|
||||||
|
@ -46,7 +38,7 @@ _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
|
||||||
bool
|
bool
|
||||||
binary_search(_ForwardIterator __first, _ForwardIterator __last, const _Tp& __value_)
|
binary_search(_ForwardIterator __first, _ForwardIterator __last, const _Tp& __value_)
|
||||||
{
|
{
|
||||||
return _VSTD::binary_search(__first, __last, __value_,
|
return std::binary_search(__first, __last, __value_,
|
||||||
__less<typename iterator_traits<_ForwardIterator>::value_type, _Tp>());
|
__less<typename iterator_traits<_ForwardIterator>::value_type, _Tp>());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include <__algorithm/lower_bound.h>
|
#include <__algorithm/lower_bound.h>
|
||||||
#include <__algorithm/upper_bound.h>
|
#include <__algorithm/upper_bound.h>
|
||||||
#include <__config>
|
#include <__config>
|
||||||
|
#include <__functional/identity.h>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
|
|
||||||
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
||||||
|
@ -46,10 +47,11 @@ __equal_range(_ForwardIterator __first, _ForwardIterator __last, const _Tp& __va
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
auto __proj = std::__identity();
|
||||||
_ForwardIterator __mp1 = __m;
|
_ForwardIterator __mp1 = __m;
|
||||||
return pair<_ForwardIterator, _ForwardIterator>
|
return pair<_ForwardIterator, _ForwardIterator>
|
||||||
(
|
(
|
||||||
_VSTD::__lower_bound<_Compare>(__first, __m, __value_, __comp),
|
_VSTD::__lower_bound_impl(__first, __m, __value_, __comp, __proj),
|
||||||
_VSTD::__upper_bound<_Compare>(++__mp1, __last, __value_, __comp)
|
_VSTD::__upper_bound<_Compare>(++__mp1, __last, __value_, __comp)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -166,7 +166,7 @@ __inplace_merge(_BidirectionalIterator __first, _BidirectionalIterator __middle,
|
||||||
__len11 = __len1 / 2;
|
__len11 = __len1 / 2;
|
||||||
__m1 = __first;
|
__m1 = __first;
|
||||||
_VSTD::advance(__m1, __len11);
|
_VSTD::advance(__m1, __len11);
|
||||||
__m2 = _VSTD::__lower_bound<_Compare>(__middle, __last, *__m1, __comp);
|
__m2 = std::lower_bound(__middle, __last, *__m1, __comp);
|
||||||
__len21 = _VSTD::distance(__middle, __m2);
|
__len21 = _VSTD::distance(__middle, __m2);
|
||||||
}
|
}
|
||||||
difference_type __len12 = __len1 - __len11; // distance(__m1, __middle)
|
difference_type __len12 = __len1 - __len11; // distance(__m1, __middle)
|
||||||
|
|
|
@ -12,6 +12,8 @@
|
||||||
#include <__algorithm/comp.h>
|
#include <__algorithm/comp.h>
|
||||||
#include <__algorithm/half_positive.h>
|
#include <__algorithm/half_positive.h>
|
||||||
#include <__config>
|
#include <__config>
|
||||||
|
#include <__functional/identity.h>
|
||||||
|
#include <__type_traits/is_callable.h>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
|
|
||||||
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
||||||
|
@ -20,44 +22,38 @@
|
||||||
|
|
||||||
_LIBCPP_BEGIN_NAMESPACE_STD
|
_LIBCPP_BEGIN_NAMESPACE_STD
|
||||||
|
|
||||||
template <class _Compare, class _ForwardIterator, class _Tp>
|
template <class _Iter, class _Sent, class _Type, class _Proj, class _Comp>
|
||||||
_LIBCPP_CONSTEXPR_AFTER_CXX17 _ForwardIterator
|
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17
|
||||||
__lower_bound(_ForwardIterator __first, _ForwardIterator __last, const _Tp& __value_, _Compare __comp)
|
_Iter __lower_bound_impl(_Iter __first, _Sent __last, const _Type& __value, _Comp& __comp, _Proj& __proj) {
|
||||||
{
|
auto __len = std::__ranges_distance(__first, __last);
|
||||||
typedef typename iterator_traits<_ForwardIterator>::difference_type difference_type;
|
|
||||||
difference_type __len = _VSTD::distance(__first, __last);
|
while (__len != 0) {
|
||||||
while (__len != 0)
|
auto __l2 = std::__half_positive(__len);
|
||||||
{
|
_Iter __m = __first;
|
||||||
difference_type __l2 = _VSTD::__half_positive(__len);
|
std::__ranges_advance(__m, __l2);
|
||||||
_ForwardIterator __m = __first;
|
if (std::__invoke(__comp, std::__invoke(__proj, *__m), __value)) {
|
||||||
_VSTD::advance(__m, __l2);
|
|
||||||
if (__comp(*__m, __value_))
|
|
||||||
{
|
|
||||||
__first = ++__m;
|
__first = ++__m;
|
||||||
__len -= __l2 + 1;
|
__len -= __l2 + 1;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
__len = __l2;
|
__len = __l2;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return __first;
|
return __first;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class _ForwardIterator, class _Tp, class _Compare>
|
template <class _ForwardIterator, class _Tp, class _Compare>
|
||||||
_LIBCPP_NODISCARD_EXT inline
|
_LIBCPP_NODISCARD_EXT inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17
|
||||||
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
|
_ForwardIterator lower_bound(_ForwardIterator __first, _ForwardIterator __last, const _Tp& __value_, _Compare __comp) {
|
||||||
_ForwardIterator
|
static_assert(__is_callable<_Compare, decltype(*__first), const _Tp&>::value,
|
||||||
lower_bound(_ForwardIterator __first, _ForwardIterator __last, const _Tp& __value_, _Compare __comp)
|
"The comparator has to be callable");
|
||||||
{
|
auto __proj = std::__identity();
|
||||||
return _VSTD::__lower_bound<_Compare&>(__first, __last, __value_, __comp);
|
return std::__lower_bound_impl(__first, __last, __value_, __comp, __proj);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class _ForwardIterator, class _Tp>
|
template <class _ForwardIterator, class _Tp>
|
||||||
_LIBCPP_NODISCARD_EXT inline
|
_LIBCPP_NODISCARD_EXT inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17
|
||||||
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
|
_ForwardIterator lower_bound(_ForwardIterator __first, _ForwardIterator __last, const _Tp& __value_) {
|
||||||
_ForwardIterator
|
return std::lower_bound(__first, __last, __value_,
|
||||||
lower_bound(_ForwardIterator __first, _ForwardIterator __last, const _Tp& __value_)
|
|
||||||
{
|
|
||||||
return _VSTD::lower_bound(__first, __last, __value_,
|
|
||||||
__less<typename iterator_traits<_ForwardIterator>::value_type, _Tp>());
|
__less<typename iterator_traits<_ForwardIterator>::value_type, _Tp>());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,62 @@
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// 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_BINARY_SEARCH_H
|
||||||
|
#define _LIBCPP___ALGORITHM_RANGES_BINARY_SEARCH_H
|
||||||
|
|
||||||
|
#include <__algorithm/lower_bound.h>
|
||||||
|
#include <__config>
|
||||||
|
#include <__functional/identity.h>
|
||||||
|
#include <__functional/invoke.h>
|
||||||
|
#include <__functional/ranges_operations.h>
|
||||||
|
#include <__iterator/concepts.h>
|
||||||
|
#include <__iterator/projected.h>
|
||||||
|
#include <__ranges/access.h>
|
||||||
|
#include <__ranges/concepts.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 __binary_search {
|
||||||
|
struct __fn {
|
||||||
|
template <forward_iterator _Iter, sentinel_for<_Iter> _Sent, class _Type, class _Proj = identity,
|
||||||
|
indirect_strict_weak_order<const _Type*, projected<_Iter, _Proj>> _Comp = ranges::less>
|
||||||
|
_LIBCPP_HIDE_FROM_ABI constexpr
|
||||||
|
bool operator()(_Iter __first, _Sent __last, const _Type& __value, _Comp __comp = {}, _Proj __proj = {}) const {
|
||||||
|
auto __ret = std::__lower_bound_impl(__first, __last, __value, __comp, __proj);
|
||||||
|
return __ret != __last && !std::invoke(__comp, __value, std::invoke(__proj, *__first));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <forward_range _Range, class _Type, class _Proj = identity,
|
||||||
|
indirect_strict_weak_order<const _Type*, projected<iterator_t<_Range>, _Proj>> _Comp = ranges::less>
|
||||||
|
_LIBCPP_HIDE_FROM_ABI constexpr
|
||||||
|
bool operator()(_Range&& __r, const _Type& __value, _Comp __comp = {}, _Proj __proj = {}) const {
|
||||||
|
auto __first = ranges::begin(__r);
|
||||||
|
auto __last = ranges::end(__r);
|
||||||
|
auto __ret = std::__lower_bound_impl(__first, __last, __value, __comp, __proj);
|
||||||
|
return __ret != __last && !std::invoke(__comp, __value, std::invoke(__proj, *__first));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // namespace __binary_search
|
||||||
|
|
||||||
|
inline namespace __cpo {
|
||||||
|
inline constexpr auto binary_search = __binary_search::__fn{};
|
||||||
|
} // namespace __cpo
|
||||||
|
} // namespace ranges
|
||||||
|
|
||||||
|
_LIBCPP_END_NAMESPACE_STD
|
||||||
|
|
||||||
|
#endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES)
|
||||||
|
|
||||||
|
#endif // _LIBCPP___ALGORITHM_RANGES_BINARY_SEARCH_H
|
|
@ -0,0 +1,65 @@
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// 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_LOWER_BOUND_H
|
||||||
|
#define _LIBCPP___ALGORITHM_RANGES_LOWER_BOUND_H
|
||||||
|
|
||||||
|
#include <__algorithm/lower_bound.h>
|
||||||
|
#include <__config>
|
||||||
|
#include <__functional/identity.h>
|
||||||
|
#include <__functional/invoke.h>
|
||||||
|
#include <__functional/ranges_operations.h>
|
||||||
|
#include <__iterator/advance.h>
|
||||||
|
#include <__iterator/concepts.h>
|
||||||
|
#include <__iterator/iterator_traits.h>
|
||||||
|
#include <__iterator/projected.h>
|
||||||
|
#include <__ranges/access.h>
|
||||||
|
#include <__ranges/concepts.h>
|
||||||
|
#include <__ranges/dangling.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 __lower_bound {
|
||||||
|
struct __fn {
|
||||||
|
template <forward_iterator _Iter, sentinel_for<_Iter> _Sent, class _Type, class _Proj = identity,
|
||||||
|
indirect_strict_weak_order<const _Type*, projected<_Iter, _Proj>> _Comp = ranges::less>
|
||||||
|
_LIBCPP_HIDE_FROM_ABI constexpr
|
||||||
|
_Iter operator()(_Iter __first, _Sent __last, const _Type& __value, _Comp __comp = {}, _Proj __proj = {}) const {
|
||||||
|
return std::__lower_bound_impl(__first, __last, __value, __comp, __proj);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <forward_range _Range, class _Type, class _Proj = identity,
|
||||||
|
indirect_strict_weak_order<const _Type*, projected<iterator_t<_Range>, _Proj>> _Comp = ranges::less>
|
||||||
|
_LIBCPP_HIDE_FROM_ABI constexpr
|
||||||
|
borrowed_iterator_t<_Range> operator()(_Range&& __r,
|
||||||
|
const _Type& __value,
|
||||||
|
_Comp __comp = {},
|
||||||
|
_Proj __proj = {}) const {
|
||||||
|
return std::__lower_bound_impl(ranges::begin(__r), ranges::end(__r), __value, __comp, __proj);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // namespace __lower_bound
|
||||||
|
|
||||||
|
inline namespace __cpo {
|
||||||
|
inline constexpr auto lower_bound = __lower_bound::__fn{};
|
||||||
|
} // namespace __cpo
|
||||||
|
} // namespace ranges
|
||||||
|
|
||||||
|
_LIBCPP_END_NAMESPACE_STD
|
||||||
|
|
||||||
|
#endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES)
|
||||||
|
|
||||||
|
#endif // _LIBCPP___ALGORITHM_RANGES_LOWER_BOUND_H
|
|
@ -0,0 +1,70 @@
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// 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_UPPER_BOUND_H
|
||||||
|
#define _LIBCPP___ALGORITHM_RANGES_UPPER_BOUND_H
|
||||||
|
|
||||||
|
#include <__algorithm/lower_bound.h>
|
||||||
|
#include <__config>
|
||||||
|
#include <__functional/identity.h>
|
||||||
|
#include <__functional/invoke.h>
|
||||||
|
#include <__functional/ranges_operations.h>
|
||||||
|
#include <__iterator/concepts.h>
|
||||||
|
#include <__iterator/projected.h>
|
||||||
|
#include <__ranges/access.h>
|
||||||
|
#include <__ranges/concepts.h>
|
||||||
|
#include <__ranges/dangling.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 __upper_bound {
|
||||||
|
struct __fn {
|
||||||
|
template <forward_iterator _Iter, sentinel_for<_Iter> _Sent, class _Type, class _Proj = identity,
|
||||||
|
indirect_strict_weak_order<const _Type*, projected<_Iter, _Proj>> _Comp = ranges::less>
|
||||||
|
_LIBCPP_HIDE_FROM_ABI constexpr
|
||||||
|
_Iter operator()(_Iter __first, _Sent __last, const _Type& __value, _Comp __comp = {}, _Proj __proj = {}) const {
|
||||||
|
auto __comp_lhs_rhs_swapped = [&](const auto& __lhs, const auto& __rhs) {
|
||||||
|
return !std::invoke(__comp, __rhs, __lhs);
|
||||||
|
};
|
||||||
|
|
||||||
|
return std::__lower_bound_impl(__first, __last, __value, __comp_lhs_rhs_swapped, __proj);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <forward_range _Range, class _Type, class _Proj = identity,
|
||||||
|
indirect_strict_weak_order<const _Type*, projected<iterator_t<_Range>, _Proj>> _Comp = ranges::less>
|
||||||
|
_LIBCPP_HIDE_FROM_ABI constexpr
|
||||||
|
borrowed_iterator_t<_Range> operator()(_Range&& __r,
|
||||||
|
const _Type& __value,
|
||||||
|
_Comp __comp = {},
|
||||||
|
_Proj __proj = {}) const {
|
||||||
|
auto __comp_lhs_rhs_swapped = [&](const auto& __lhs, const auto& __rhs) {
|
||||||
|
return !std::invoke(__comp, __rhs, __lhs);
|
||||||
|
};
|
||||||
|
|
||||||
|
return std::__lower_bound_impl(ranges::begin(__r), ranges::end(__r), __value, __comp_lhs_rhs_swapped, __proj);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // namespace __upper_bound
|
||||||
|
|
||||||
|
inline namespace __cpo {
|
||||||
|
inline constexpr auto upper_bound = __upper_bound::__fn{};
|
||||||
|
} // namespace __cpo
|
||||||
|
} // namespace ranges
|
||||||
|
|
||||||
|
_LIBCPP_END_NAMESPACE_STD
|
||||||
|
|
||||||
|
#endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES)
|
||||||
|
|
||||||
|
#endif // _LIBCPP___ALGORITHM_RANGES_UPPER_BOUND_H
|
|
@ -194,6 +194,15 @@ inline namespace __cpo {
|
||||||
|
|
||||||
#endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES)
|
#endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES)
|
||||||
|
|
||||||
|
template <class _Iter, class _Sent>
|
||||||
|
_LIBCPP_CONSTEXPR_AFTER_CXX11 void __ranges_advance(_Iter& __first, _Sent& __last) {
|
||||||
|
#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES)
|
||||||
|
return ranges::advance(__first, __last);
|
||||||
|
#else
|
||||||
|
return std::advance(__first, __last);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
_LIBCPP_END_NAMESPACE_STD
|
_LIBCPP_END_NAMESPACE_STD
|
||||||
|
|
||||||
#endif // _LIBCPP___ITERATOR_ADVANCE_H
|
#endif // _LIBCPP___ITERATOR_ADVANCE_H
|
||||||
|
|
|
@ -102,6 +102,16 @@ inline namespace __cpo {
|
||||||
|
|
||||||
#endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES)
|
#endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES)
|
||||||
|
|
||||||
|
template <class _Iter, class _Sent>
|
||||||
|
_LIBCPP_CONSTEXPR_AFTER_CXX11
|
||||||
|
typename iterator_traits<_Iter>::difference_type __ranges_distance(_Iter __first, _Sent __second) {
|
||||||
|
#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES)
|
||||||
|
return ranges::distance(__first, __second);
|
||||||
|
#else
|
||||||
|
return std::distance(__first, __second);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
_LIBCPP_END_NAMESPACE_STD
|
_LIBCPP_END_NAMESPACE_STD
|
||||||
|
|
||||||
#endif // _LIBCPP___ITERATOR_DISTANCE_H
|
#endif // _LIBCPP___ITERATOR_DISTANCE_H
|
||||||
|
|
|
@ -345,6 +345,37 @@ namespace ranges {
|
||||||
indirect_strict_weak_order<projected<iterator_t<R>, Proj>> Comp = ranges::less>
|
indirect_strict_weak_order<projected<iterator_t<R>, Proj>> Comp = ranges::less>
|
||||||
constexpr borrowed_iterator_t<R>
|
constexpr borrowed_iterator_t<R>
|
||||||
ranges::is_sorted_until(R&& r, Comp comp = {}, Proj proj = {}); // since C++20
|
ranges::is_sorted_until(R&& r, Comp comp = {}, Proj proj = {}); // since C++20
|
||||||
|
|
||||||
|
template<forward_iterator I, sentinel_for<I> S, class T, class Proj = identity,
|
||||||
|
indirect_strict_weak_order<const T*, projected<I, Proj>> Comp = ranges::less>
|
||||||
|
constexpr I upper_bound(I first, S last, const T& value, Comp comp = {}, Proj proj = {}); // since C++20
|
||||||
|
|
||||||
|
template<forward_range R, class T, class Proj = identity,
|
||||||
|
indirect_strict_weak_order<const T*, projected<iterator_t<R>, Proj>> Comp =
|
||||||
|
ranges::less>
|
||||||
|
constexpr borrowed_iterator_t<R>
|
||||||
|
upper_bound(R&& r, const T& value, Comp comp = {}, Proj proj = {}); // since C++20
|
||||||
|
|
||||||
|
template<forward_iterator I, sentinel_for<I> S, class T, class Proj = identity,
|
||||||
|
indirect_strict_weak_order<const T*, projected<I, Proj>> Comp = ranges::less>
|
||||||
|
constexpr I lower_bound(I first, S last, const T& value, Comp comp = {},
|
||||||
|
Proj proj = {}); // since C++20
|
||||||
|
template<forward_range R, class T, class Proj = identity,
|
||||||
|
indirect_strict_weak_order<const T*, projected<iterator_t<R>, Proj>> Comp =
|
||||||
|
ranges::less>
|
||||||
|
constexpr borrowed_iterator_t<R>
|
||||||
|
lower_bound(R&& r, const T& value, Comp comp = {}, Proj proj = {}); // since C++20
|
||||||
|
|
||||||
|
template<forward_iterator I, sentinel_for<I> S, class T, class Proj = identity,
|
||||||
|
indirect_strict_weak_order<const T*, projected<I, Proj>> Comp = ranges::less>
|
||||||
|
constexpr bool binary_search(I first, S last, const T& value, Comp comp = {},
|
||||||
|
Proj proj = {}); // since C++20
|
||||||
|
template<forward_range R, class T, class Proj = identity,
|
||||||
|
indirect_strict_weak_order<const T*, projected<iterator_t<R>, Proj>> Comp =
|
||||||
|
ranges::less>
|
||||||
|
constexpr bool binary_search(R&& r, const T& value, Comp comp = {},
|
||||||
|
Proj proj = {}); // since C++20
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr bool // constexpr in C++20
|
constexpr bool // constexpr in C++20
|
||||||
|
@ -1063,6 +1094,7 @@ template <class BidirectionalIterator, class Compare>
|
||||||
#include <__algorithm/push_heap.h>
|
#include <__algorithm/push_heap.h>
|
||||||
#include <__algorithm/ranges_all_of.h>
|
#include <__algorithm/ranges_all_of.h>
|
||||||
#include <__algorithm/ranges_any_of.h>
|
#include <__algorithm/ranges_any_of.h>
|
||||||
|
#include <__algorithm/ranges_binary_search.h>
|
||||||
#include <__algorithm/ranges_copy.h>
|
#include <__algorithm/ranges_copy.h>
|
||||||
#include <__algorithm/ranges_copy_backward.h>
|
#include <__algorithm/ranges_copy_backward.h>
|
||||||
#include <__algorithm/ranges_copy_if.h>
|
#include <__algorithm/ranges_copy_if.h>
|
||||||
|
@ -1080,6 +1112,7 @@ template <class BidirectionalIterator, class Compare>
|
||||||
#include <__algorithm/ranges_is_partitioned.h>
|
#include <__algorithm/ranges_is_partitioned.h>
|
||||||
#include <__algorithm/ranges_is_sorted.h>
|
#include <__algorithm/ranges_is_sorted.h>
|
||||||
#include <__algorithm/ranges_is_sorted_until.h>
|
#include <__algorithm/ranges_is_sorted_until.h>
|
||||||
|
#include <__algorithm/ranges_lower_bound.h>
|
||||||
#include <__algorithm/ranges_max.h>
|
#include <__algorithm/ranges_max.h>
|
||||||
#include <__algorithm/ranges_max_element.h>
|
#include <__algorithm/ranges_max_element.h>
|
||||||
#include <__algorithm/ranges_min.h>
|
#include <__algorithm/ranges_min.h>
|
||||||
|
@ -1091,6 +1124,7 @@ template <class BidirectionalIterator, class Compare>
|
||||||
#include <__algorithm/ranges_reverse.h>
|
#include <__algorithm/ranges_reverse.h>
|
||||||
#include <__algorithm/ranges_swap_ranges.h>
|
#include <__algorithm/ranges_swap_ranges.h>
|
||||||
#include <__algorithm/ranges_transform.h>
|
#include <__algorithm/ranges_transform.h>
|
||||||
|
#include <__algorithm/ranges_upper_bound.h>
|
||||||
#include <__algorithm/remove.h>
|
#include <__algorithm/remove.h>
|
||||||
#include <__algorithm/remove_copy.h>
|
#include <__algorithm/remove_copy.h>
|
||||||
#include <__algorithm/remove_copy_if.h>
|
#include <__algorithm/remove_copy_if.h>
|
||||||
|
|
|
@ -300,6 +300,7 @@ module std [system] {
|
||||||
module push_heap { private header "__algorithm/push_heap.h" }
|
module push_heap { private header "__algorithm/push_heap.h" }
|
||||||
module ranges_all_of { private header "__algorithm/ranges_all_of.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_any_of { private header "__algorithm/ranges_any_of.h" }
|
||||||
|
module ranges_binary_search { private header "__algorithm/ranges_binary_search.h" }
|
||||||
module ranges_copy { private header "__algorithm/ranges_copy.h" }
|
module ranges_copy { private header "__algorithm/ranges_copy.h" }
|
||||||
module ranges_copy_backward { private header "__algorithm/ranges_copy_backward.h" }
|
module ranges_copy_backward { private header "__algorithm/ranges_copy_backward.h" }
|
||||||
module ranges_copy_if { private header "__algorithm/ranges_copy_if.h" }
|
module ranges_copy_if { private header "__algorithm/ranges_copy_if.h" }
|
||||||
|
@ -317,6 +318,7 @@ module std [system] {
|
||||||
module ranges_is_partitioned { private header "__algorithm/ranges_is_partitioned.h" }
|
module ranges_is_partitioned { private header "__algorithm/ranges_is_partitioned.h" }
|
||||||
module ranges_is_sorted { private header "__algorithm/ranges_is_sorted.h" }
|
module ranges_is_sorted { private header "__algorithm/ranges_is_sorted.h" }
|
||||||
module ranges_is_sorted_until { private header "__algorithm/ranges_is_sorted_until.h" }
|
module ranges_is_sorted_until { private header "__algorithm/ranges_is_sorted_until.h" }
|
||||||
|
module ranges_lower_bound { private header "__algorithm/ranges_lower_bound.h" }
|
||||||
module ranges_max { private header "__algorithm/ranges_max.h" }
|
module ranges_max { private header "__algorithm/ranges_max.h" }
|
||||||
module ranges_max_element { private header "__algorithm/ranges_max_element.h" }
|
module ranges_max_element { private header "__algorithm/ranges_max_element.h" }
|
||||||
module ranges_min { private header "__algorithm/ranges_min.h" }
|
module ranges_min { private header "__algorithm/ranges_min.h" }
|
||||||
|
@ -328,6 +330,7 @@ module std [system] {
|
||||||
module ranges_reverse { private header "__algorithm/ranges_reverse.h" }
|
module ranges_reverse { private header "__algorithm/ranges_reverse.h" }
|
||||||
module ranges_swap_ranges { private header "__algorithm/ranges_swap_ranges.h" }
|
module ranges_swap_ranges { private header "__algorithm/ranges_swap_ranges.h" }
|
||||||
module ranges_transform { private header "__algorithm/ranges_transform.h" }
|
module ranges_transform { private header "__algorithm/ranges_transform.h" }
|
||||||
|
module ranges_upper_bound { private header "__algorithm/ranges_upper_bound.h" }
|
||||||
module remove { private header "__algorithm/remove.h" }
|
module remove { private header "__algorithm/remove.h" }
|
||||||
module remove_copy { private header "__algorithm/remove_copy.h" }
|
module remove_copy { private header "__algorithm/remove_copy.h" }
|
||||||
module remove_copy_if { private header "__algorithm/remove_copy_if.h" }
|
module remove_copy_if { private header "__algorithm/remove_copy_if.h" }
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// 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
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
// UNSUPPORTED: c++03
|
||||||
|
|
||||||
|
// <algorithm>
|
||||||
|
|
||||||
|
// check that the classical algorithms with non-callable comparators fail
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
struct S {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
S(int i_) : i(i_) {}
|
||||||
|
|
||||||
|
bool compare(const S&) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
S a[] = {1, 2, 3, 4};
|
||||||
|
std::lower_bound(a, a + 4, 0, &S::compare); // expected-error@*:* {{The comparator has to be callable}}
|
||||||
|
std::minmax({S{1}}, &S::compare); // expected-error@*:* {{The comparator has to be callable}}
|
||||||
|
std::minmax_element(a, a + 4, &S::compare); // expected-error@*:* {{The comparator has to be callable}}
|
||||||
|
}
|
|
@ -96,8 +96,8 @@ constexpr bool all_the_algorithms()
|
||||||
(void)std::ranges::all_of(a, UnaryTrue(&copies)); assert(copies == 0);
|
(void)std::ranges::all_of(a, UnaryTrue(&copies)); assert(copies == 0);
|
||||||
(void)std::ranges::any_of(first, last, UnaryTrue(&copies)); assert(copies == 0);
|
(void)std::ranges::any_of(first, last, UnaryTrue(&copies)); assert(copies == 0);
|
||||||
(void)std::ranges::any_of(a, UnaryTrue(&copies)); assert(copies == 0);
|
(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(first, last, value, Less(&copies)); assert(copies == 0);
|
||||||
//(void)std::ranges::binary_search(a, 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(first, last, UnaryTrue(&copies)); assert(copies == 0);
|
||||||
(void)std::ranges::count_if(a, UnaryTrue(&copies)); assert(copies == 0);
|
(void)std::ranges::count_if(a, UnaryTrue(&copies)); assert(copies == 0);
|
||||||
|
@ -142,8 +142,8 @@ constexpr bool all_the_algorithms()
|
||||||
//if (!std::is_constant_evaluated()) { (void)std::ranges::inplace_merge(a, mid, Less(&copies)); assert(copies == 0); }
|
//if (!std::is_constant_evaluated()) { (void)std::ranges::inplace_merge(a, mid, Less(&copies)); assert(copies == 0); }
|
||||||
//(void)std::ranges::lexicographical_compare(first, last, first2, last2, Less(&copies)); assert(copies == 0);
|
//(void)std::ranges::lexicographical_compare(first, last, first2, last2, Less(&copies)); assert(copies == 0);
|
||||||
//(void)std::ranges::lexicographical_compare(a, b, Less(&copies)); assert(copies == 0);
|
//(void)std::ranges::lexicographical_compare(a, b, Less(&copies)); assert(copies == 0);
|
||||||
//(void)std::ranges::lower_bound(first, last, value, Less(&copies)); assert(copies == 0);
|
(void)std::ranges::lower_bound(first, last, value, Less(&copies)); assert(copies == 0);
|
||||||
//(void)std::ranges::lower_bound(a, value, Less(&copies)); assert(copies == 0);
|
(void)std::ranges::lower_bound(a, value, Less(&copies)); assert(copies == 0);
|
||||||
//(void)std::ranges::make_heap(first, last, Less(&copies)); assert(copies == 0);
|
//(void)std::ranges::make_heap(first, last, Less(&copies)); assert(copies == 0);
|
||||||
//(void)std::ranges::make_heap(a, Less(&copies)); assert(copies == 0);
|
//(void)std::ranges::make_heap(a, Less(&copies)); assert(copies == 0);
|
||||||
(void)std::ranges::max(value, value, Less(&copies)); assert(copies == 0);
|
(void)std::ranges::max(value, value, Less(&copies)); assert(copies == 0);
|
||||||
|
@ -226,8 +226,8 @@ constexpr bool all_the_algorithms()
|
||||||
//(void)std::ranges::unique(a, Equal(&copies)); assert(copies == 0);
|
//(void)std::ranges::unique(a, Equal(&copies)); assert(copies == 0);
|
||||||
//(void)std::ranges::unique_copy(first, last, first2, Equal(&copies)); assert(copies == 0);
|
//(void)std::ranges::unique_copy(first, last, first2, Equal(&copies)); assert(copies == 0);
|
||||||
//(void)std::ranges::unique_copy(a, first2, Equal(&copies)); assert(copies == 0);
|
//(void)std::ranges::unique_copy(a, first2, Equal(&copies)); assert(copies == 0);
|
||||||
//(void)std::ranges::upper_bound(first, last, value, Less(&copies)); assert(copies == 0);
|
(void)std::ranges::upper_bound(first, last, value, Less(&copies)); assert(copies == 0);
|
||||||
//(void)std::ranges::upper_bound(a, value, Less(&copies)); assert(copies == 0);
|
(void)std::ranges::upper_bound(a, value, Less(&copies)); assert(copies == 0);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -105,6 +105,7 @@ END-SCRIPT
|
||||||
#include <__algorithm/push_heap.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/push_heap.h'}}
|
#include <__algorithm/push_heap.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/push_heap.h'}}
|
||||||
#include <__algorithm/ranges_all_of.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_all_of.h'}}
|
#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_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_copy.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_copy.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_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'}}
|
#include <__algorithm/ranges_copy_if.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_copy_if.h'}}
|
||||||
|
@ -122,6 +123,7 @@ END-SCRIPT
|
||||||
#include <__algorithm/ranges_is_partitioned.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_is_partitioned.h'}}
|
#include <__algorithm/ranges_is_partitioned.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_is_partitioned.h'}}
|
||||||
#include <__algorithm/ranges_is_sorted.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_is_sorted.h'}}
|
#include <__algorithm/ranges_is_sorted.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_is_sorted.h'}}
|
||||||
#include <__algorithm/ranges_is_sorted_until.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_is_sorted_until.h'}}
|
#include <__algorithm/ranges_is_sorted_until.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_is_sorted_until.h'}}
|
||||||
|
#include <__algorithm/ranges_lower_bound.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_lower_bound.h'}}
|
||||||
#include <__algorithm/ranges_max.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_max.h'}}
|
#include <__algorithm/ranges_max.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_max.h'}}
|
||||||
#include <__algorithm/ranges_max_element.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_max_element.h'}}
|
#include <__algorithm/ranges_max_element.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_max_element.h'}}
|
||||||
#include <__algorithm/ranges_min.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_min.h'}}
|
#include <__algorithm/ranges_min.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_min.h'}}
|
||||||
|
@ -133,6 +135,7 @@ END-SCRIPT
|
||||||
#include <__algorithm/ranges_reverse.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_reverse.h'}}
|
#include <__algorithm/ranges_reverse.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_reverse.h'}}
|
||||||
#include <__algorithm/ranges_swap_ranges.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_swap_ranges.h'}}
|
#include <__algorithm/ranges_swap_ranges.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_swap_ranges.h'}}
|
||||||
#include <__algorithm/ranges_transform.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_transform.h'}}
|
#include <__algorithm/ranges_transform.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_transform.h'}}
|
||||||
|
#include <__algorithm/ranges_upper_bound.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_upper_bound.h'}}
|
||||||
#include <__algorithm/remove.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/remove.h'}}
|
#include <__algorithm/remove.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/remove.h'}}
|
||||||
#include <__algorithm/remove_copy.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/remove_copy.h'}}
|
#include <__algorithm/remove_copy.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/remove_copy.h'}}
|
||||||
#include <__algorithm/remove_copy_if.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/remove_copy_if.h'}}
|
#include <__algorithm/remove_copy_if.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/remove_copy_if.h'}}
|
||||||
|
|
|
@ -0,0 +1,176 @@
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// 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
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||||
|
// UNSUPPORTED: libcpp-has-no-incomplete-ranges
|
||||||
|
|
||||||
|
// template<forward_iterator I, sentinel_for<I> S, class T, class Proj = identity,
|
||||||
|
// indirect_strict_weak_order<const T*, projected<I, Proj>> Comp = ranges::less>
|
||||||
|
// constexpr bool ranges::binary_search(I first, S last, const T& value, Comp comp = {},
|
||||||
|
// Proj proj = {});
|
||||||
|
// template<forward_range R, class T, class Proj = identity,
|
||||||
|
// indirect_strict_weak_order<const T*, projected<iterator_t<R>, Proj>> Comp =
|
||||||
|
// ranges::less>
|
||||||
|
// constexpr bool ranges::binary_search(R&& r, const T& value, Comp comp = {},
|
||||||
|
// Proj proj = {});
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <array>
|
||||||
|
#include <cassert>
|
||||||
|
#include <functional>
|
||||||
|
#include <ranges>
|
||||||
|
|
||||||
|
#include "almost_satisfies_types.h"
|
||||||
|
#include "test_iterators.h"
|
||||||
|
|
||||||
|
struct NotLessThanComparable {};
|
||||||
|
|
||||||
|
template <class It, class Sent = It>
|
||||||
|
concept HasLowerBoundIt = requires(It it, Sent sent) { std::ranges::binary_search(it, sent, 1); };
|
||||||
|
|
||||||
|
static_assert(HasLowerBoundIt<int*>);
|
||||||
|
static_assert(!HasLowerBoundIt<cpp20_input_iterator<int*>, sentinel_wrapper<cpp20_input_iterator<int*>>>);
|
||||||
|
static_assert(!HasLowerBoundIt<ForwardIteratorNotDerivedFrom>);
|
||||||
|
static_assert(!HasLowerBoundIt<ForwardIteratorNotIncrementable>);
|
||||||
|
static_assert(!HasLowerBoundIt<NotLessThanComparable*>);
|
||||||
|
|
||||||
|
template <class Range>
|
||||||
|
concept HasLowerBoundR = requires(Range range) { std::ranges::binary_search(range, 1); };
|
||||||
|
|
||||||
|
static_assert(HasLowerBoundR<std::array<int, 1>>);
|
||||||
|
static_assert(!HasLowerBoundR<ForwardRangeNotDerivedFrom>);
|
||||||
|
static_assert(!HasLowerBoundR<ForwardRangeNotIncrementable>);
|
||||||
|
static_assert(!HasLowerBoundR<UncheckedRange<NotLessThanComparable*>>);
|
||||||
|
|
||||||
|
template <class Pred>
|
||||||
|
concept HasLowerBoundPred = requires(int* it, Pred pred) {std::ranges::binary_search(it, it, 1, pred); };
|
||||||
|
|
||||||
|
static_assert(HasLowerBoundPred<std::ranges::less>);
|
||||||
|
static_assert(!HasLowerBoundPred<IndirectUnaryPredicateNotCopyConstructible>);
|
||||||
|
static_assert(!HasLowerBoundPred<IndirectUnaryPredicateNotPredicate>);
|
||||||
|
|
||||||
|
template <class It, class Sent = It>
|
||||||
|
constexpr void test_iterators() {
|
||||||
|
{ // simple test
|
||||||
|
{
|
||||||
|
int a[] = {1, 2, 3, 4, 5, 6};
|
||||||
|
std::same_as<bool> auto ret = std::ranges::binary_search(It(a), Sent(It(a + 6)), 3);
|
||||||
|
assert(ret);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
int a[] = {1, 2, 3, 4, 5, 6};
|
||||||
|
auto range = std::ranges::subrange(It(a), Sent(It(a + 6)));
|
||||||
|
std::same_as<bool> auto ret = std::ranges::binary_search(range, 3);
|
||||||
|
assert(ret);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // check that the predicate is used
|
||||||
|
int a[] = {6, 5, 4, 3, 2, 1};
|
||||||
|
assert(std::ranges::binary_search(It(a), Sent(It(a + 6)), 2, std::ranges::greater{}));
|
||||||
|
auto range = std::ranges::subrange(It(a), Sent(It(a + 6)));
|
||||||
|
assert(std::ranges::binary_search(range, 2, std::ranges::greater{}));
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // check that the projection is used
|
||||||
|
int a[] = {1, 2, 3, 4, 5, 6};
|
||||||
|
assert(std::ranges::binary_search(It(a), Sent(It(a + 6)), 0, {}, [](int i) { return i - 3; }));
|
||||||
|
auto range = std::ranges::subrange(It(a), Sent(It(a + 6)));
|
||||||
|
assert(std::ranges::binary_search(range, 0, {}, [](int i) { return i - 3; }));
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // check that true is returned with multiple matches
|
||||||
|
int a[] = {1, 2, 2, 2, 3};
|
||||||
|
assert(std::ranges::binary_search(It(a), Sent(It(a + 5)), 2));
|
||||||
|
auto range = std::ranges::subrange(It(a), Sent(It(a + 5)));
|
||||||
|
assert(std::ranges::binary_search(range, 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // check that false is returned if all elements compare less than
|
||||||
|
int a[] = {1, 2, 3, 4};
|
||||||
|
assert(!std::ranges::binary_search(It(a), Sent(It(a + 4)), 5));
|
||||||
|
auto range = std::ranges::subrange(It(a), Sent(It(a + 4)));
|
||||||
|
assert(!std::ranges::binary_search(range, 5));
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // check that false is returned if no element compares less than
|
||||||
|
int a[] = {1, 2, 3, 4};
|
||||||
|
assert(!std::ranges::binary_search(It(a), Sent(It(a + 4)), 0));
|
||||||
|
auto range = std::ranges::subrange(It(a), Sent(It(a + 4)));
|
||||||
|
assert(!std::ranges::binary_search(range, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // check that a single element works
|
||||||
|
int a[] = {1};
|
||||||
|
assert(std::ranges::binary_search(It(a), Sent(It(a + 1)), 1));
|
||||||
|
auto range = std::ranges::subrange(It(a), Sent(It(a + 1)));
|
||||||
|
assert(std::ranges::binary_search(range, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // check that an even number of elements works and that searching for the first element works
|
||||||
|
int a[] = {1, 2, 7, 8, 10, 11};
|
||||||
|
assert(std::ranges::binary_search(It(a), Sent(It(a + 6)), 1));
|
||||||
|
auto range = std::ranges::subrange(It(a), Sent(It(a + 6)));
|
||||||
|
assert(std::ranges::binary_search(range, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // check that an odd number of elements works and that searching for the last element works
|
||||||
|
int a[] = {1, 2, 7, 10, 11};
|
||||||
|
assert(std::ranges::binary_search(It(a), Sent(It(a + 5)), 11));
|
||||||
|
auto range = std::ranges::subrange(It(a), Sent(It(a + 5)));
|
||||||
|
assert(std::ranges::binary_search(range, 11));
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // check that it works when all but the searched for elements are equal
|
||||||
|
int a[] = {1, 2, 2, 2, 2};
|
||||||
|
assert(std::ranges::binary_search(It(a), Sent(It(a + 5)), 1));
|
||||||
|
auto range = std::ranges::subrange(It(a), Sent(It(a + 5)));
|
||||||
|
assert(std::ranges::binary_search(range, 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool test() {
|
||||||
|
test_iterators<int*>();
|
||||||
|
test_iterators<forward_iterator<int*>>();
|
||||||
|
test_iterators<forward_iterator<int*>, sentinel_wrapper<forward_iterator<int*>>>();
|
||||||
|
test_iterators<bidirectional_iterator<int*>>();
|
||||||
|
test_iterators<random_access_iterator<int*>>();
|
||||||
|
test_iterators<contiguous_iterator<int*>>();
|
||||||
|
test_iterators<contiguous_iterator<int*>, sentinel_wrapper<contiguous_iterator<int*>>>();
|
||||||
|
|
||||||
|
{ // check that std::invoke is used
|
||||||
|
struct S { int check; int other; };
|
||||||
|
S a[] = {{1, 6}, {2, 5}, {3, 4}, {4, 3}, {5, 2}, {6, 1}};
|
||||||
|
assert(std::ranges::binary_search(a, a + 6, 4, {}, &S::check));
|
||||||
|
assert(std::ranges::binary_search(a, 4, {}, &S::check));
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // check that an empty range works
|
||||||
|
std::array<int, 0> a;
|
||||||
|
assert(!std::ranges::binary_search(a.begin(), a.end(), 1));
|
||||||
|
assert(!std::ranges::binary_search(a, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // check that a non-const operator() works
|
||||||
|
struct Func {
|
||||||
|
constexpr bool operator()(const int& i, const int& j) { return i < j; }
|
||||||
|
};
|
||||||
|
int a[] = {1, 6, 9, 10, 23};
|
||||||
|
assert(std::ranges::binary_search(a, 6, Func{}));
|
||||||
|
assert(std::ranges::binary_search(a, a + 5, 6, Func{}));
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int, char**) {
|
||||||
|
test();
|
||||||
|
static_assert(test());
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,274 @@
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// 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
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||||
|
// UNSUPPORTED: libcpp-has-no-incomplete-ranges
|
||||||
|
|
||||||
|
// template<forward_iterator I, sentinel_for<I> S, class T, class Proj = identity,
|
||||||
|
// indirect_strict_weak_order<const T*, projected<I, Proj>> Comp = ranges::less>
|
||||||
|
// constexpr I ranges::lower_bound(I first, S last, const T& value, Comp comp = {},
|
||||||
|
// Proj proj = {});
|
||||||
|
// template<forward_range R, class T, class Proj = identity,
|
||||||
|
// indirect_strict_weak_order<const T*, projected<iterator_t<R>, Proj>> Comp =
|
||||||
|
// ranges::less>
|
||||||
|
// constexpr borrowed_iterator_t<R>
|
||||||
|
// ranges::lower_bound(R&& r, const T& value, Comp comp = {}, Proj proj = {});
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <array>
|
||||||
|
#include <cassert>
|
||||||
|
#include <functional>
|
||||||
|
#include <ranges>
|
||||||
|
|
||||||
|
#include "almost_satisfies_types.h"
|
||||||
|
#include "test_iterators.h"
|
||||||
|
|
||||||
|
struct NotLessThanComparable {};
|
||||||
|
|
||||||
|
template <class It, class Sent = It>
|
||||||
|
concept HasLowerBoundIt = requires(It it, Sent sent) { std::ranges::lower_bound(it, sent, 1); };
|
||||||
|
|
||||||
|
static_assert(HasLowerBoundIt<int*>);
|
||||||
|
static_assert(!HasLowerBoundIt<cpp20_input_iterator<int*>, sentinel_wrapper<cpp20_input_iterator<int*>>>);
|
||||||
|
static_assert(!HasLowerBoundIt<ForwardIteratorNotDerivedFrom>);
|
||||||
|
static_assert(!HasLowerBoundIt<ForwardIteratorNotIncrementable>);
|
||||||
|
static_assert(!HasLowerBoundIt<NotLessThanComparable*>);
|
||||||
|
|
||||||
|
template <class Range>
|
||||||
|
concept HasLowerBoundR = requires(Range range) { std::ranges::lower_bound(range, 1); };
|
||||||
|
|
||||||
|
static_assert(HasLowerBoundR<std::array<int, 1>>);
|
||||||
|
static_assert(!HasLowerBoundR<ForwardRangeNotDerivedFrom>);
|
||||||
|
static_assert(!HasLowerBoundR<ForwardRangeNotIncrementable>);
|
||||||
|
static_assert(!HasLowerBoundR<UncheckedRange<NotLessThanComparable*>>);
|
||||||
|
|
||||||
|
template <class Pred>
|
||||||
|
concept HasLowerBoundPred = requires(int* it, Pred pred) {std::ranges::lower_bound(it, it, 1, pred); };
|
||||||
|
|
||||||
|
static_assert(HasLowerBoundPred<std::ranges::less>);
|
||||||
|
static_assert(!HasLowerBoundPred<IndirectUnaryPredicateNotCopyConstructible>);
|
||||||
|
static_assert(!HasLowerBoundPred<IndirectUnaryPredicateNotPredicate>);
|
||||||
|
|
||||||
|
template <class It>
|
||||||
|
constexpr void test_iterators() {
|
||||||
|
{ // simple test
|
||||||
|
{
|
||||||
|
int a[] = {1, 2, 3, 4, 5, 6};
|
||||||
|
std::same_as<It> auto ret = std::ranges::lower_bound(It(a), It(a + 6), 3);
|
||||||
|
assert(base(ret) == a + 2);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
int a[] = {1, 2, 3, 4, 5, 6};
|
||||||
|
auto range = std::ranges::subrange(It(a), It(a + 6));
|
||||||
|
std::same_as<It> auto ret = std::ranges::lower_bound(range, 3);
|
||||||
|
assert(base(ret) == a + 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // check that the predicate is used
|
||||||
|
{
|
||||||
|
int a[] = {6, 5, 4, 3, 2, 1};
|
||||||
|
auto ret = std::ranges::lower_bound(It(a), It(a + 6), 2, std::ranges::greater{});
|
||||||
|
assert(base(ret) == a + 4);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
int a[] = {6, 5, 4, 3, 2, 1};
|
||||||
|
auto range = std::ranges::subrange(It(a), It(a + 6));
|
||||||
|
auto ret = std::ranges::lower_bound(range, 2, std::ranges::greater{});
|
||||||
|
assert(base(ret) == a + 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // check that the projection is used
|
||||||
|
{
|
||||||
|
int a[] = {1, 2, 3, 4, 5, 6};
|
||||||
|
auto ret = std::ranges::lower_bound(It(a), It(a + 6), 0, {}, [](int i) { return i - 3; });
|
||||||
|
assert(base(ret) == a + 2);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
int a[] = {1, 2, 3, 4, 5, 6};
|
||||||
|
auto range = std::ranges::subrange(It(a), It(a + 6));
|
||||||
|
auto ret = std::ranges::lower_bound(range, 0, {}, [](int i) { return i - 3; });
|
||||||
|
assert(base(ret) == a + 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // check that the last lower bound is returned
|
||||||
|
{
|
||||||
|
int a[] = {1, 2, 2, 2, 3};
|
||||||
|
auto ret = std::ranges::lower_bound(It(a), It(a + 5), 2);
|
||||||
|
assert(base(ret) == a + 1);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
int a[] = {1, 2, 2, 2, 3};
|
||||||
|
auto range = std::ranges::subrange(It(a), It(a + 5));
|
||||||
|
auto ret = std::ranges::lower_bound(range, 2);
|
||||||
|
assert(base(ret) == a + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // check that end is returned if all elements compare less than
|
||||||
|
{
|
||||||
|
int a[] = {1, 2, 3, 4};
|
||||||
|
auto ret = std::ranges::lower_bound(It(a), It(a + 4), 5);
|
||||||
|
assert(base(ret) == a + 4);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
int a[] = {1, 2, 3, 4};
|
||||||
|
auto range = std::ranges::subrange(It(a), It(a + 4));
|
||||||
|
auto ret = std::ranges::lower_bound(range, 5);
|
||||||
|
assert(base(ret) == a + 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // check that the first element is returned if no element compares less than
|
||||||
|
{
|
||||||
|
int a[] = {1, 2, 3, 4};
|
||||||
|
auto ret = std::ranges::lower_bound(It(a), It(a + 4), 0);
|
||||||
|
assert(base(ret) == a);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
int a[] = {1, 2, 3, 4};
|
||||||
|
auto range = std::ranges::subrange(It(a), It(a + 4));
|
||||||
|
auto ret = std::ranges::lower_bound(range, 0);
|
||||||
|
assert(base(ret) == a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // check that a single element works
|
||||||
|
{
|
||||||
|
int a[] = {1};
|
||||||
|
auto ret = std::ranges::lower_bound(It(a), It(a + 1), 1);
|
||||||
|
assert(base(ret) == a);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
int a[] = {1};
|
||||||
|
auto range = std::ranges::subrange(It(a), It(a + 1));
|
||||||
|
auto ret = std::ranges::lower_bound(range, 1);
|
||||||
|
assert(base(ret) == a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // check that an even number of elements works
|
||||||
|
{
|
||||||
|
int a[] = {1, 3, 6, 6, 7, 8};
|
||||||
|
auto ret = std::ranges::lower_bound(It(a), It(a + 6), 6);
|
||||||
|
assert(base(ret) == a + 2);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
int a[] = {1, 3, 6, 6, 7, 8};
|
||||||
|
auto range = std::ranges::subrange(It(a), It(a + 6));
|
||||||
|
auto ret = std::ranges::lower_bound(range, 6);
|
||||||
|
assert(base(ret) == a + 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // check that an odd number of elements works
|
||||||
|
{
|
||||||
|
int a[] = {1, 3, 6, 6, 7};
|
||||||
|
auto ret = std::ranges::lower_bound(It(a), It(a + 5), 6);
|
||||||
|
assert(base(ret) == a + 2);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
int a[] = {1, 3, 6, 6, 7};
|
||||||
|
auto range = std::ranges::subrange(It(a), It(a + 5));
|
||||||
|
auto ret = std::ranges::lower_bound(range, 6);
|
||||||
|
assert(base(ret) == a + 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // check that it works when all but the searched for element are equal
|
||||||
|
{
|
||||||
|
int a[] = {1, 6, 6, 6, 6, 6};
|
||||||
|
auto ret = std::ranges::lower_bound(It(a), It(a + 6), 1);
|
||||||
|
assert(base(ret) == a);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
int a[] = {1, 6, 6, 6, 6, 6};
|
||||||
|
auto range = std::ranges::subrange(It(a), It(a + 6));
|
||||||
|
auto ret = std::ranges::lower_bound(range, 1);
|
||||||
|
assert(base(ret) == a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool test() {
|
||||||
|
test_iterators<int*>();
|
||||||
|
test_iterators<forward_iterator<int*>>();
|
||||||
|
test_iterators<bidirectional_iterator<int*>>();
|
||||||
|
test_iterators<random_access_iterator<int*>>();
|
||||||
|
test_iterators<contiguous_iterator<int*>>();
|
||||||
|
|
||||||
|
{ // check that std::invoke is used for the projections
|
||||||
|
{
|
||||||
|
struct S { int check; int other; };
|
||||||
|
S a[] = {{1, 6}, {2, 5}, {3, 4}, {4, 3}, {5, 2}, {6, 1}};
|
||||||
|
auto ret = std::ranges::lower_bound(a, a + 6, 4, {}, &S::check);
|
||||||
|
assert(ret == a + 3);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
struct S { int check; int other; };
|
||||||
|
S a[] = {{1, 6}, {2, 5}, {3, 4}, {4, 3}, {5, 2}, {6, 1}};
|
||||||
|
auto ret = std::ranges::lower_bound(a, 4, {}, &S::check);
|
||||||
|
assert(ret == a + 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // check that std::invoke is used for the predicate
|
||||||
|
struct S {
|
||||||
|
int check;
|
||||||
|
int other;
|
||||||
|
|
||||||
|
constexpr bool compare(const S& s) const {
|
||||||
|
return check < s.check;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
{
|
||||||
|
S a[] = {{1, 6}, {2, 5}, {3, 4}, {4, 3}, {5, 2}, {6, 1}};
|
||||||
|
auto ret = std::ranges::lower_bound(a, a + 6, S{4, 0}, &S::compare);
|
||||||
|
assert(ret == a + 3);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
S a[] = {{1, 6}, {2, 5}, {3, 4}, {4, 3}, {5, 2}, {6, 1}};
|
||||||
|
auto ret = std::ranges::lower_bound(a, S{4, 0}, &S::compare);
|
||||||
|
assert(ret == a + 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // check that an empty range works
|
||||||
|
{
|
||||||
|
std::array<int, 0> a;
|
||||||
|
auto ret = std::ranges::lower_bound(a.begin(), a.end(), 1);
|
||||||
|
assert(ret == a.end());
|
||||||
|
}
|
||||||
|
{
|
||||||
|
std::array<int, 0> a;
|
||||||
|
auto ret = std::ranges::lower_bound(a, 1);
|
||||||
|
assert(ret == a.end());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // check that ranges::dangling is returned
|
||||||
|
[[maybe_unused]] std::same_as<std::ranges::dangling> auto ret = std::ranges::lower_bound(std::array{1, 2}, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // check that an iterator is returned with a borrowing range
|
||||||
|
int a[] = {1, 2, 3};
|
||||||
|
std::same_as<int*> auto ret = std::ranges::lower_bound(std::views::all(a), 1);
|
||||||
|
assert(ret == a);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int, char**) {
|
||||||
|
test();
|
||||||
|
static_assert(test());
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,273 @@
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// 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
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||||
|
// UNSUPPORTED: libcpp-has-no-incomplete-ranges
|
||||||
|
|
||||||
|
// template<forward_iterator I, sentinel_for<I> S, class T, class Proj = identity,
|
||||||
|
// indirect_strict_weak_order<const T*, projected<I, Proj>> Comp = ranges::less>
|
||||||
|
// constexpr I ranges::upper_bound(I first, S last, const T& value, Comp comp = {}, Proj proj = {});
|
||||||
|
// template<forward_range R, class T, class Proj = identity,
|
||||||
|
// indirect_strict_weak_order<const T*, projected<iterator_t<R>, Proj>> Comp =
|
||||||
|
// ranges::less>
|
||||||
|
// constexpr borrowed_iterator_t<R>
|
||||||
|
// ranges::upper_bound(R&& r, const T& value, Comp comp = {}, Proj proj = {});
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <array>
|
||||||
|
#include <cassert>
|
||||||
|
#include <functional>
|
||||||
|
#include <ranges>
|
||||||
|
|
||||||
|
#include "almost_satisfies_types.h"
|
||||||
|
#include "test_iterators.h"
|
||||||
|
|
||||||
|
struct NotLessThanComparable {};
|
||||||
|
|
||||||
|
template <class It, class Sent = It>
|
||||||
|
concept HasUpperBoundIt = requires(It it, Sent sent) { std::ranges::upper_bound(it, sent, 1); };
|
||||||
|
|
||||||
|
static_assert(HasUpperBoundIt<int*>);
|
||||||
|
static_assert(!HasUpperBoundIt<cpp20_input_iterator<int*>, sentinel_wrapper<cpp20_input_iterator<int*>>>);
|
||||||
|
static_assert(!HasUpperBoundIt<ForwardIteratorNotDerivedFrom>);
|
||||||
|
static_assert(!HasUpperBoundIt<ForwardIteratorNotIncrementable>);
|
||||||
|
static_assert(!HasUpperBoundIt<NotLessThanComparable*>);
|
||||||
|
|
||||||
|
template <class Range>
|
||||||
|
concept HasUpperBoundR = requires(Range range) { std::ranges::upper_bound(range, 1); };
|
||||||
|
|
||||||
|
static_assert(HasUpperBoundR<std::array<int, 1>>);
|
||||||
|
static_assert(!HasUpperBoundR<ForwardRangeNotDerivedFrom>);
|
||||||
|
static_assert(!HasUpperBoundR<ForwardRangeNotIncrementable>);
|
||||||
|
static_assert(!HasUpperBoundR<UncheckedRange<NotLessThanComparable*>>);
|
||||||
|
|
||||||
|
template <class Pred>
|
||||||
|
concept HasUpperBoundPred = requires(int* it, Pred pred) {std::ranges::upper_bound(it, it, 1, pred); };
|
||||||
|
|
||||||
|
static_assert(HasUpperBoundPred<std::ranges::less>);
|
||||||
|
static_assert(!HasUpperBoundPred<IndirectUnaryPredicateNotCopyConstructible>);
|
||||||
|
static_assert(!HasUpperBoundPred<IndirectUnaryPredicateNotPredicate>);
|
||||||
|
|
||||||
|
template <class It>
|
||||||
|
constexpr void test_iterators() {
|
||||||
|
{ // simple test
|
||||||
|
{
|
||||||
|
int a[] = {1, 2, 3, 4, 5, 6};
|
||||||
|
std::same_as<It> auto ret = std::ranges::upper_bound(It(a), It(a + 6), 3);
|
||||||
|
assert(base(ret) == a + 3);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
int a[] = {1, 2, 3, 4, 5, 6};
|
||||||
|
auto range = std::ranges::subrange(It(a), It(a + 6));
|
||||||
|
std::same_as<It> auto ret = std::ranges::upper_bound(range, 3);
|
||||||
|
assert(base(ret) == a + 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // check that the predicate is used
|
||||||
|
{
|
||||||
|
int a[] = {6, 5, 4, 3, 2, 1};
|
||||||
|
auto ret = std::ranges::upper_bound(It(a), It(a + 6), 2, std::ranges::greater{});
|
||||||
|
assert(base(ret) == a + 5);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
int a[] = {6, 5, 4, 3, 2, 1};
|
||||||
|
auto range = std::ranges::subrange(It(a), It(a + 6));
|
||||||
|
auto ret = std::ranges::upper_bound(range, 2, std::ranges::greater{});
|
||||||
|
assert(base(ret) == a + 5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // check that the projection is used
|
||||||
|
{
|
||||||
|
int a[] = {1, 2, 3, 4, 5, 6};
|
||||||
|
auto ret = std::ranges::upper_bound(It(a), It(a + 6), 0, {}, [](int i) { return i - 3; });
|
||||||
|
assert(base(ret) == a + 3);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
int a[] = {1, 2, 3, 4, 5, 6};
|
||||||
|
auto range = std::ranges::subrange(It(a), It(a + 6));
|
||||||
|
auto ret = std::ranges::upper_bound(range, 0, {}, [](int i) { return i - 3; });
|
||||||
|
assert(base(ret) == a + 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // check that the last upper bound is returned
|
||||||
|
{
|
||||||
|
int a[] = {1, 2, 2, 2, 3};
|
||||||
|
auto ret = std::ranges::upper_bound(It(a), It(a + 5), 2);
|
||||||
|
assert(base(ret) == a + 4);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
int a[] = {1, 2, 2, 2, 3};
|
||||||
|
auto range = std::ranges::subrange(It(a), It(a + 5));
|
||||||
|
auto ret = std::ranges::upper_bound(range, 2);
|
||||||
|
assert(base(ret) == a + 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // check that end is returned if all elements compare less than
|
||||||
|
{
|
||||||
|
int a[] = {1, 2, 3, 4};
|
||||||
|
auto ret = std::ranges::upper_bound(It(a), It(a + 4), 5);
|
||||||
|
assert(base(ret) == a + 4);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
int a[] = {1, 2, 3, 4};
|
||||||
|
auto range = std::ranges::subrange(It(a), It(a + 4));
|
||||||
|
auto ret = std::ranges::upper_bound(range, 5);
|
||||||
|
assert(base(ret) == a + 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // check that the first element is returned if no element compares less than
|
||||||
|
{
|
||||||
|
int a[] = {1, 2, 3, 4};
|
||||||
|
auto ret = std::ranges::upper_bound(It(a), It(a + 4), 0);
|
||||||
|
assert(base(ret) == a);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
int a[] = {1, 2, 3, 4};
|
||||||
|
auto range = std::ranges::subrange(It(a), It(a + 4));
|
||||||
|
auto ret = std::ranges::upper_bound(range, 0);
|
||||||
|
assert(base(ret) == a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // check that a single element works
|
||||||
|
{
|
||||||
|
int a[] = {1};
|
||||||
|
auto ret = std::ranges::upper_bound(It(a), It(a + 1), 1);
|
||||||
|
assert(base(ret) == a + 1);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
int a[] = {1};
|
||||||
|
auto range = std::ranges::subrange(It(a), It(a + 1));
|
||||||
|
auto ret = std::ranges::upper_bound(range, 1);
|
||||||
|
assert(base(ret) == a + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // check that an even number of elements works
|
||||||
|
{
|
||||||
|
int a[] = {1, 3, 6, 6, 7, 8};
|
||||||
|
auto ret = std::ranges::upper_bound(It(a), It(a + 6), 6);
|
||||||
|
assert(base(ret) == a + 4);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
int a[] = {1, 3, 6, 6, 7, 8};
|
||||||
|
auto range = std::ranges::subrange(It(a), It(a + 6));
|
||||||
|
auto ret = std::ranges::upper_bound(range, 6);
|
||||||
|
assert(base(ret) == a + 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // check that an odd number of elements works
|
||||||
|
{
|
||||||
|
int a[] = {1, 3, 6, 6, 7};
|
||||||
|
auto ret = std::ranges::upper_bound(It(a), It(a + 5), 6);
|
||||||
|
assert(base(ret) == a + 4);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
int a[] = {1, 3, 6, 6, 7};
|
||||||
|
auto range = std::ranges::subrange(It(a), It(a + 5));
|
||||||
|
auto ret = std::ranges::upper_bound(range, 6);
|
||||||
|
assert(base(ret) == a + 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // check that it works when all but the searched for element are equal
|
||||||
|
{
|
||||||
|
int a[] = {1, 6, 6, 6, 6, 6};
|
||||||
|
auto ret = std::ranges::upper_bound(It(a), It(a + 6), 1);
|
||||||
|
assert(base(ret) == a + 1);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
int a[] = {1, 6, 6, 6, 6, 6};
|
||||||
|
auto range = std::ranges::subrange(It(a), It(a + 6));
|
||||||
|
auto ret = std::ranges::upper_bound(range, 1);
|
||||||
|
assert(base(ret) == a + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool test() {
|
||||||
|
test_iterators<int*>();
|
||||||
|
test_iterators<forward_iterator<int*>>();
|
||||||
|
test_iterators<bidirectional_iterator<int*>>();
|
||||||
|
test_iterators<random_access_iterator<int*>>();
|
||||||
|
test_iterators<contiguous_iterator<int*>>();
|
||||||
|
|
||||||
|
{ // check that std::invoke is used for the projections
|
||||||
|
{
|
||||||
|
struct S { int check; int other; };
|
||||||
|
S a[] = {{1, 6}, {2, 5}, {3, 4}, {4, 3}, {5, 2}, {6, 1}};
|
||||||
|
auto ret = std::ranges::upper_bound(a, a + 6, 4, {}, &S::check);
|
||||||
|
assert(ret == a + 4);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
struct S { int check; int other; };
|
||||||
|
S a[] = {{1, 6}, {2, 5}, {3, 4}, {4, 3}, {5, 2}, {6, 1}};
|
||||||
|
auto ret = std::ranges::upper_bound(a, 4, {}, &S::check);
|
||||||
|
assert(ret == a + 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // check that std::invoke is used for the predicate
|
||||||
|
struct S {
|
||||||
|
int check;
|
||||||
|
int other;
|
||||||
|
|
||||||
|
constexpr bool compare(const S& s) const {
|
||||||
|
return check < s.check;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
{
|
||||||
|
S a[] = {{1, 6}, {2, 5}, {3, 4}, {4, 3}, {5, 2}, {6, 1}};
|
||||||
|
auto ret = std::ranges::upper_bound(a, a + 6, S{4, 0}, &S::compare);
|
||||||
|
assert(ret == a + 4);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
S a[] = {{1, 6}, {2, 5}, {3, 4}, {4, 3}, {5, 2}, {6, 1}};
|
||||||
|
auto ret = std::ranges::upper_bound(a, S{4, 0}, &S::compare);
|
||||||
|
assert(ret == a + 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // check that an empty range works
|
||||||
|
{
|
||||||
|
std::array<int, 0> a;
|
||||||
|
auto ret = std::ranges::upper_bound(a.begin(), a.end(), 1);
|
||||||
|
assert(ret == a.end());
|
||||||
|
}
|
||||||
|
{
|
||||||
|
std::array<int, 0> a;
|
||||||
|
auto ret = std::ranges::upper_bound(a, 1);
|
||||||
|
assert(ret == a.end());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // check that ranges::dangling is returned
|
||||||
|
[[maybe_unused]] std::same_as<std::ranges::dangling> auto ret = std::ranges::upper_bound(std::array{1, 2}, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // check that an iterator is returned with a borrowing range
|
||||||
|
int a[] = {1, 2, 3};
|
||||||
|
std::same_as<int*> auto ret = std::ranges::upper_bound(std::views::all(a), 1);
|
||||||
|
assert(ret == a + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int, char**) {
|
||||||
|
test();
|
||||||
|
static_assert(test());
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -63,7 +63,7 @@ auto triple = [](int x) { return 3*x; };
|
||||||
//static_assert(test(std::ranges::adjacent_find, a));
|
//static_assert(test(std::ranges::adjacent_find, a));
|
||||||
static_assert(test(std::ranges::all_of, a, odd));
|
static_assert(test(std::ranges::all_of, a, odd));
|
||||||
static_assert(test(std::ranges::any_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::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, a, a));
|
||||||
static_assert(test(std::ranges::copy_backward, a, a));
|
static_assert(test(std::ranges::copy_backward, a, a));
|
||||||
|
@ -94,7 +94,7 @@ static_assert(test(std::ranges::is_partitioned, a, odd));
|
||||||
static_assert(test(std::ranges::is_sorted, a));
|
static_assert(test(std::ranges::is_sorted, a));
|
||||||
static_assert(test(std::ranges::is_sorted_until, a));
|
static_assert(test(std::ranges::is_sorted_until, a));
|
||||||
//static_assert(test(std::ranges::lexicographical_compare, a, a));
|
//static_assert(test(std::ranges::lexicographical_compare, a, a));
|
||||||
//static_assert(test(std::ranges::lower_bound, a, 42));
|
static_assert(test(std::ranges::lower_bound, a, 42));
|
||||||
//static_assert(test(std::ranges::make_heap, a));
|
//static_assert(test(std::ranges::make_heap, a));
|
||||||
static_assert(test(std::ranges::max, a));
|
static_assert(test(std::ranges::max, a));
|
||||||
static_assert(test(std::ranges::max_element, a));
|
static_assert(test(std::ranges::max_element, a));
|
||||||
|
@ -146,7 +146,7 @@ static_assert(test(std::ranges::swap_ranges, a, a));
|
||||||
static_assert(test(std::ranges::transform, a, a, triple));
|
static_assert(test(std::ranges::transform, a, a, triple));
|
||||||
//static_assert(test(std::ranges::unique, a));
|
//static_assert(test(std::ranges::unique, a));
|
||||||
//static_assert(test(std::ranges::unique_copy, a, a));
|
//static_assert(test(std::ranges::unique_copy, a, a));
|
||||||
//static_assert(test(std::ranges::upper_bound, a, 42));
|
static_assert(test(std::ranges::upper_bound, a, 42));
|
||||||
|
|
||||||
// [memory.syn]
|
// [memory.syn]
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue