diff --git a/libcxx/include/__algorithm/all_of.h b/libcxx/include/__algorithm/all_of.h --- a/libcxx/include/__algorithm/all_of.h +++ b/libcxx/include/__algorithm/all_of.h @@ -11,6 +11,14 @@ #define _LIBCPP___ALGORITHM_ALL_OF_H #include <__config> +#include <__function_like.h> +#include <__functional/identity.h> +#include <__functional/invoke.h> +#include <__functional/reference_wrapper.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 @@ -30,6 +38,38 @@ return true; } +#if !defined(_LIBCPP_HAS_NO_RANGES) + +namespace ranges { + struct __all_of_fn final : __function_like { + constexpr explicit __all_of_fn(__tag __x) noexcept : __function_like(__x) {} + + template _Sp, class _Proj = identity, + indirect_unary_predicate> _Pred> + _LIBCPP_NODISCARD_EXT constexpr + bool operator()(_Ip __first, const _Sp __last, _Pred __pred, _Proj __proj = {}) const { + for (; __first != __last; ++__first) { + if (!_VSTD::invoke(__pred, _VSTD::invoke(__proj, *__first))) { + return false; + } + } + + return true; + } + + template, _Proj>> _Pred> + _LIBCPP_NODISCARD_EXT constexpr + bool operator()(_Rp&& __r, _Pred __pred, _Proj __proj = {}) const { + return (*this)(ranges::begin(__r), ranges::end(__r), _VSTD::ref(__pred), _VSTD::ref(__proj)); + } + }; + + inline constexpr auto all_of = __all_of_fn(__function_like::__tag()); +} // namespace ranges + +#endif // !defined(_LIBCPP_HAS_NO_RANGES) + _LIBCPP_END_NAMESPACE_STD _LIBCPP_POP_MACROS diff --git a/libcxx/include/__algorithm/any_of.h b/libcxx/include/__algorithm/any_of.h --- a/libcxx/include/__algorithm/any_of.h +++ b/libcxx/include/__algorithm/any_of.h @@ -10,7 +10,16 @@ #ifndef _LIBCPP___ALGORITHM_ANY_OF_H #define _LIBCPP___ALGORITHM_ANY_OF_H +#include <__algorithm/find_if.h> #include <__config> +#include <__function_like.h> +#include <__functional/identity.h> +#include <__functional/reference_wrapper.h> +#include <__iterator/concepts.h> +#include <__iterator/projected.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__utility/move.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) #pragma GCC system_header @@ -30,6 +39,32 @@ return false; } +#if !defined(_LIBCPP_HAS_NO_RANGES) + +namespace ranges { + struct __any_of_fn final : __function_like { + constexpr explicit __any_of_fn(__tag __x) noexcept : __function_like(__x) {} + + template _Sp, class _Proj = identity, + indirect_unary_predicate> _Pred> + _LIBCPP_NODISCARD_EXT constexpr + bool operator()(_Ip __first, const _Sp __last, _Pred __pred, _Proj __proj = {}) const { + return ranges::find_if(_VSTD::move(__first), __last, _VSTD::ref(__pred), _VSTD::ref(__proj)) != __last; + } + + template, _Proj>> _Pred> + _LIBCPP_NODISCARD_EXT constexpr + bool operator()(_Rp&& __r, _Pred __pred, _Proj __proj = {}) const { + return (*this)(ranges::begin(__r), ranges::end(__r), _VSTD::ref(__pred), _VSTD::ref(__proj)); + } + }; + + inline constexpr auto any_of = __any_of_fn(__function_like::__tag()); +} // namespace ranges + +#endif // !defined(_LIBCPP_HAS_NO_RANGES) + _LIBCPP_END_NAMESPACE_STD _LIBCPP_POP_MACROS diff --git a/libcxx/include/__algorithm/none_of.h b/libcxx/include/__algorithm/none_of.h --- a/libcxx/include/__algorithm/none_of.h +++ b/libcxx/include/__algorithm/none_of.h @@ -10,7 +10,16 @@ #ifndef _LIBCPP___ALGORITHM_NONE_OF_H #define _LIBCPP___ALGORITHM_NONE_OF_H +#include <__algorithm/find_if.h> #include <__config> +#include <__function_like.h> +#include <__functional/identity.h> +#include <__functional/reference_wrapper.h> +#include <__iterator/concepts.h> +#include <__iterator/projected.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__utility/move.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) #pragma GCC system_header @@ -30,6 +39,32 @@ return true; } +#if !defined(_LIBCPP_HAS_NO_RANGES) + +namespace ranges { + struct __none_of_fn final : __function_like { + constexpr explicit __none_of_fn(__tag __x) noexcept : __function_like(__x) {} + + template _Sp, class _Proj = identity, + indirect_unary_predicate> _Pred> + _LIBCPP_NODISCARD_EXT constexpr + bool operator()(_Ip __first, const _Sp __last, _Pred __pred, _Proj __proj = {}) const { + return ranges::find_if(_VSTD::move(__first), __last, _VSTD::ref(__pred), _VSTD::ref(__proj)) == __last; + } + + template, _Proj>> _Pred> + _LIBCPP_NODISCARD_EXT constexpr + bool operator()(_Rp&& __r, _Pred __pred, _Proj __proj = {}) const { + return (*this)(ranges::begin(__r), ranges::end(__r), _VSTD::ref(__pred), _VSTD::ref(__proj)); + } + }; + + inline constexpr auto none_of = __none_of_fn(__function_like::__tag()); +} // namespace ranges + +#endif // !defined(_LIBCPP_HAS_NO_RANGES) + _LIBCPP_END_NAMESPACE_STD _LIBCPP_POP_MACROS diff --git a/libcxx/include/algorithm b/libcxx/include/algorithm --- a/libcxx/include/algorithm +++ b/libcxx/include/algorithm @@ -22,14 +22,38 @@ constexpr bool // constexpr in C++20 all_of(InputIterator first, InputIterator last, Predicate pred); +template S, class Proj = identity, + indirect_unary_predicate> Pred> + constexpr bool ranges::all_of(I first, S last, Pred pred, Proj proj = {}); // since C++20 + +template, Proj>> Pred> + constexpr bool ranges::all_of(R&& r, Pred pred, Proj proj = {}); // since C++20 + template constexpr bool // constexpr in C++20 any_of(InputIterator first, InputIterator last, Predicate pred); +template S, class Proj = identity, + indirect_unary_predicate> Pred> + constexpr bool ranges::any_of(I first, S last, Pred pred, Proj proj = {}); // since C++20 + +template, Proj>> Pred> + constexpr bool ranges::any_of(R&& r, Pred pred, Proj proj = {}); // since C++20 + template constexpr bool // constexpr in C++20 none_of(InputIterator first, InputIterator last, Predicate pred); +template S, class Proj = identity, + indirect_unary_predicate> Pred> + constexpr bool ranges::none_of(I first, S last, Pred pred, Proj proj = {}); // since C++20 + +template, Proj>> Pred> + constexpr bool ranges::none_of(R&& r, Pred pred, Proj proj = {}); // since C++20 + template constexpr Function // constexpr in C++20 for_each(InputIterator first, InputIterator last, Function f); diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap --- a/libcxx/include/module.modulemap +++ b/libcxx/include/module.modulemap @@ -220,8 +220,14 @@ module __algorithm { module adjacent_find { header "__algorithm/adjacent_find.h" } - module all_of { header "__algorithm/all_of.h" } - module any_of { header "__algorithm/any_of.h" } + module all_of { + header "__algorithm/all_of.h" + export __function_like + } + module any_of { + header "__algorithm/any_of.h" + export __function_like + } module binary_search { header "__algorithm/binary_search.h" } module clamp { header "__algorithm/clamp.h" } module comp { header "__algorithm/comp.h" } @@ -278,7 +284,10 @@ module move { header "__algorithm/move.h" } module move_backward { header "__algorithm/move_backward.h" } module next_permutation { header "__algorithm/next_permutation.h" } - module none_of { header "__algorithm/none_of.h" } + module none_of { + header "__algorithm/none_of.h" + export __function_like + } module nth_element { header "__algorithm/nth_element.h" } module partial_sort { header "__algorithm/partial_sort.h" } module partial_sort_copy { header "__algorithm/partial_sort_copy.h" } diff --git a/libcxx/test/libcxx/diagnostics/nodiscard_ranges_extensions.pass.cpp b/libcxx/test/libcxx/diagnostics/nodiscard_ranges_extensions.pass.cpp --- a/libcxx/test/libcxx/diagnostics/nodiscard_ranges_extensions.pass.cpp +++ b/libcxx/test/libcxx/diagnostics/nodiscard_ranges_extensions.pass.cpp @@ -30,6 +30,15 @@ auto arr = std::array{0, 1, 2, 3, 4, 5}; namespace ranges = std::ranges; + ranges::all_of(ranges::begin(arr), ranges::end(arr), [](auto) { return true; }); + ranges::all_of(arr, [](auto) { return true; }); + + ranges::any_of(ranges::begin(arr), ranges::end(arr), [](auto) { return true; }); + ranges::any_of(arr, [](auto) { return true; }); + + ranges::none_of(ranges::begin(arr), ranges::end(arr), [](auto) { return true; }); + ranges::none_of(arr, [](auto) { return true; }); + ranges::find(ranges::begin(arr), ranges::end(arr), 1); ranges::find(arr, 1); diff --git a/libcxx/test/libcxx/diagnostics/nodiscard_ranges_extensions.verify.cpp b/libcxx/test/libcxx/diagnostics/nodiscard_ranges_extensions.verify.cpp --- a/libcxx/test/libcxx/diagnostics/nodiscard_ranges_extensions.verify.cpp +++ b/libcxx/test/libcxx/diagnostics/nodiscard_ranges_extensions.verify.cpp @@ -30,6 +30,24 @@ auto arr = std::array{0, 1, 2, 3, 4, 5}; namespace ranges = std::ranges; + // expected-warning-re@+1 {{ignoring return value of function declared with {{'nodiscard'|warn_unused_result}} attribute}} + ranges::all_of(ranges::begin(arr), ranges::end(arr), [](auto) { return true; }); + + // expected-warning-re@+1 {{ignoring return value of function declared with {{'nodiscard'|warn_unused_result}} attribute}} + ranges::all_of(arr, [](auto) { return true; }); + + // expected-warning-re@+1 {{ignoring return value of function declared with {{'nodiscard'|warn_unused_result}} attribute}} + ranges::any_of(ranges::begin(arr), ranges::end(arr), [](auto) { return true; }); + + // expected-warning-re@+1 {{ignoring return value of function declared with {{'nodiscard'|warn_unused_result}} attribute}} + ranges::any_of(arr, [](auto) { return true; }); + + // expected-warning-re@+1 {{ignoring return value of function declared with {{'nodiscard'|warn_unused_result}} attribute}} + ranges::none_of(ranges::begin(arr), ranges::end(arr), [](auto) { return true; }); + + // expected-warning-re@+1 {{ignoring return value of function declared with {{'nodiscard'|warn_unused_result}} attribute}} + ranges::none_of(arr, [](auto) { return true; }); + // expected-warning-re@+1 {{ignoring return value of function declared with {{'nodiscard'|warn_unused_result}} attribute}} ranges::find(ranges::begin(arr), ranges::end(arr), 1); diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.all_of/ranges_all_of/ranges_all_of.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.all_of/ranges_all_of/ranges_all_of.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.all_of/ranges_all_of/ranges_all_of.pass.cpp @@ -0,0 +1,132 @@ +//===----------------------------------------------------------------------===// +// +// 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-no-concepts +// UNSUPPORTED: gcc-10 + +// + +// ranges::all_of + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "test_algorithm.h" +#include "test_macros.h" +#include "test_iterators.h" +#include "test_range.h" + +template class I, class T> +constexpr bool check_all_of() +{ + namespace ranges = std::ranges; + + auto range = std::array{0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + auto successor = [](auto const x) { return x + 1; }; + auto is_zero = [](T const x) { return x == 0; }; + auto is_ten = [](T const x) { return x == 10; }; + + { + auto pred = complexity_invocable(is_zero); + { + auto subrange = ranges::subrange(I(range.begin()), sentinel_wrapper(range.end())); + assert(ranges::all_of(subrange.begin(), subrange.end(), std::ref(pred))); + } + { + auto subrange = ranges::subrange(I(range.begin()), sentinel_wrapper(range.end())); + assert(ranges::all_of(subrange, std::ref(pred))); + } + + assert(pred.count() == 2 * ranges::ssize(range)); + } + { + auto pred = complexity_invocable(is_ten); + { + auto subrange = ranges::subrange(I(range.begin()), sentinel_wrapper(range.end())); + assert(!ranges::all_of(subrange.begin(), subrange.end(), std::ref(pred))); + } + { + auto subrange = ranges::subrange(I(range.begin()), sentinel_wrapper(range.end())); + assert(!ranges::all_of(subrange, std::ref(pred))); + } + assert(pred.count() == 2); + } + { + auto pred = complexity_invocable([](auto const x){ return x % 2 == 1; }); + auto proj = complexity_invocable(successor); + { + auto subrange = ranges::subrange(I(range.begin()), sentinel_wrapper(range.end())); + assert(ranges::all_of(subrange.begin(), subrange.end(), std::ref(pred), std::ref(proj))); + } + { + auto subrange = ranges::subrange(I(range.begin()), sentinel_wrapper(range.end())); + assert(ranges::all_of(subrange, std::ref(pred), std::ref(proj))); + } + assert(pred.count() == 2 * ranges::ssize(range)); + assert(proj.count() == 2 * ranges::ssize(range)); + } + { + auto pred = complexity_invocable(is_ten); + auto proj = complexity_invocable(successor); + { + auto subrange = ranges::subrange(I(range.begin()), sentinel_wrapper(range.end())); + assert(!ranges::all_of(subrange.begin(), subrange.end(), std::ref(pred), std::ref(proj))); + } + { + auto subrange = ranges::subrange(I(range.begin()), sentinel_wrapper(range.end())); + assert(!ranges::all_of(subrange, std::ref(pred), std::ref(proj))); + } + assert(pred.count() == 2); + assert(proj.count() == 2); + } + + return true; +} + +int main(int, char**) +{ + static_assert(check_all_of()); + static_assert(check_all_of()); + check_all_of(); + check_all_of(); + + static_assert(check_all_of()); + static_assert(check_all_of()); + check_all_of(); + check_all_of(); + + static_assert(check_all_of()); + static_assert(check_all_of()); + check_all_of(); + check_all_of(); + + static_assert(check_all_of()); + static_assert(check_all_of()); + check_all_of(); + check_all_of(); + + static_assert(check_all_of()); + static_assert(check_all_of()); + check_all_of(); + check_all_of(); + + static_assert(check_all_of()); + static_assert(check_all_of()); + check_all_of(); + check_all_of(); + + return 0; +} diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.all_of/ranges_all_of/special_function.compile.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.all_of/ranges_all_of/special_function.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.all_of/ranges_all_of/special_function.compile.pass.cpp @@ -0,0 +1,110 @@ +//===----------------------------------------------------------------------===// +// +// 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-no-concepts +// UNSUPPORTED: gcc-10 + +// ranges::all_of + +#include + +#include +#include +#include +#include + +#include "test_standard_function.h" + +static_assert(is_function_like()); + +namespace ranges = std::ranges; + +namespace std::ranges { + template + class basic_istream_view { + struct iterator; + public: + iterator begin(); + default_sentinel_t end() const; + }; +} // namespace std::ranges + +auto f = [](auto) { return true; }; + +// The entities defined in the std::ranges namespace in this Clause are not found by argument-dependent +// name lookup ([basic.lookup.argdep]). When found by unqualified ([basic.lookup.unqual]) name lookup for +// the postfix-expression in a function call ([expr.call]), they inhibit argument-dependent name lookup. +template +constexpr bool no_unqualified_lookup() { + auto identity = ranges::basic_istream_view(); + static_assert(!requires(T value) { all_of(ranges::begin(identity), ranges::end(identity), f); }); + static_assert(!requires(T value) { all_of(ranges::begin(identity), ranges::end(identity), f, &T::first); }); + static_assert(!requires(T value) { all_of(identity, f); }); + static_assert(!requires(T value) { all_of(identity, f, &T::first); }); + return true; +}; + +static_assert(no_unqualified_lookup>()); + +namespace test { +template +struct iterator { + using value_type = std::pair; + using difference_type = std::ptrdiff_t; + using iterator_category = std::forward_iterator_tag; + + iterator() = default; + + value_type operator*() const; + iterator& operator++(); + iterator operator++(int); + + bool operator==(iterator const&) const = default; +}; + +template +struct range { + std::pair const* begin() const; + std::pair const* end() const; +}; + +template +void all_of(iterator, iterator, auto) { + static_assert(std::same_as); +} + +template +void all_of(iterator, iterator, auto, auto) { + static_assert(std::same_as); +} + +template +void all_of(R&&, auto) { + static_assert(std::same_as); +} + +template +void all_of(R&&, auto, auto) { + static_assert(std::same_as); +} +} // namespace test + +// When found by unqualified ([basic.lookup.unqual]) name lookup for the postfix-expression in a +// function call ([expr.call]), they inhibit argument-dependent name lookup. +void adl_inhibition() { + using std::ranges::all_of; + + test::iterator*> x; + (void)all_of(x, x, f); + (void)all_of(x, x, f, &std::pair::first); + + test::range r; + (void)all_of(r, f); + (void)all_of(r, f, &std::pair::first); +} diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.any_of/ranges_any_of/ranges_any_of.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.any_of/ranges_any_of/ranges_any_of.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.any_of/ranges_any_of/ranges_any_of.pass.cpp @@ -0,0 +1,130 @@ +//===----------------------------------------------------------------------===// +// +// 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-no-concepts +// UNSUPPORTED: gcc-10 + +// + +// ranges::any_of + +#include + +#include +#include +#include +#include +#include +#include + +#include "test_algorithm.h" +#include "test_macros.h" +#include "test_iterators.h" +#include "test_range.h" + +template class I, class T> +constexpr bool check_any_of() +{ + namespace ranges = std::ranges; + + auto range = std::array{0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + auto successor = [](auto const x) { return x + 1; }; + auto is_zero = [](T const x) { return x == 0; }; + auto is_ten = [](T const x) { return x == 10; }; + + { + auto pred = complexity_invocable(is_zero); + { + auto subrange = ranges::subrange(I(range.begin()), sentinel_wrapper(range.end())); + assert(ranges::any_of(subrange.begin(), subrange.end(), std::ref(pred))); + } + { + auto subrange = ranges::subrange(I(range.begin()), sentinel_wrapper(range.end())); + assert(ranges::any_of(subrange, std::ref(pred))); + } + assert(pred.count() == 2); + } + { + auto pred = complexity_invocable(is_ten); + { + auto subrange = ranges::subrange(I(range.begin()), sentinel_wrapper(range.end())); + assert(!ranges::any_of(subrange.begin(), subrange.end(), std::ref(pred))); + } + { + auto subrange = ranges::subrange(I(range.begin()), sentinel_wrapper(range.end())); + assert(!ranges::any_of(subrange, std::ref(pred))); + } + assert(pred.count() == 2 * ranges::ssize(range)); + } + { + auto pred = complexity_invocable([](auto const x){ return x % 2 == 1; }); + auto proj = complexity_invocable(successor); + { + auto subrange = ranges::subrange(I(range.begin()), sentinel_wrapper(range.end())); + assert(ranges::any_of(subrange.begin(), subrange.end(), std::ref(pred), std::ref(proj))); + } + { + auto subrange = ranges::subrange(I(range.begin()), sentinel_wrapper(range.end())); + assert(ranges::any_of(subrange, std::ref(pred), std::ref(proj))); + } + assert(pred.count() == 2); + assert(proj.count() == 2); + } + { + auto pred = complexity_invocable(is_ten); + auto proj = complexity_invocable(successor); + { + auto subrange = ranges::subrange(I(range.begin()), sentinel_wrapper(range.end())); + assert(!ranges::any_of(subrange.begin(), subrange.end(), std::ref(pred), std::ref(proj))); + } + { + auto subrange = ranges::subrange(I(range.begin()), sentinel_wrapper(range.end())); + assert(!ranges::any_of(subrange, std::ref(pred), std::ref(proj))); + } + assert(pred.count() == 2 * ranges::ssize(range)); + assert(proj.count() == 2 * ranges::ssize(range)); + } + + return true; +} + +int main(int, char**) +{ + // static_assert(check_any_of()); + // static_assert(check_any_of()); + check_any_of(); + check_any_of(); + + // static_assert(check_any_of()); + // static_assert(check_any_of()); + check_any_of(); + check_any_of(); + + // static_assert(check_any_of()); + // static_assert(check_any_of()); + check_any_of(); + check_any_of(); + + // static_assert(check_any_of()); + // static_assert(check_any_of()); + check_any_of(); + check_any_of(); + + // static_assert(check_any_of()); + // static_assert(check_any_of()); + check_any_of(); + check_any_of(); + + // static_assert(check_any_of()); + // static_assert(check_any_of()); + check_any_of(); + check_any_of(); + + return 0; +} diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.any_of/ranges_any_of/special_function.compile.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.any_of/ranges_any_of/special_function.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.any_of/ranges_any_of/special_function.compile.pass.cpp @@ -0,0 +1,110 @@ +//===----------------------------------------------------------------------===// +// +// 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-no-concepts +// UNSUPPORTED: gcc-10 + +// ranges::any_of + +#include + +#include +#include +#include +#include + +#include "test_standard_function.h" + +static_assert(is_function_like()); + +namespace ranges = std::ranges; + +namespace std::ranges { + template + class basic_istream_view { + struct iterator; + public: + iterator begin(); + default_sentinel_t end() const; + }; +} // namespace std::ranges + +auto f = [](auto) { return true; }; + +// The entities defined in the std::ranges namespace in this Clause are not found by argument-dependent +// name lookup ([basic.lookup.argdep]). When found by unqualified ([basic.lookup.unqual]) name lookup for +// the postfix-expression in a function cany ([expr.cany]), they inhibit argument-dependent name lookup. +template +constexpr bool no_unqualified_lookup() { + auto identity = ranges::basic_istream_view(); + static_assert(!requires(T value) { any_of(ranges::begin(identity), ranges::end(identity), f); }); + static_assert(!requires(T value) { any_of(ranges::begin(identity), ranges::end(identity), f, &T::first); }); + static_assert(!requires(T value) { any_of(identity, f); }); + static_assert(!requires(T value) { any_of(identity, f, &T::first); }); + return true; +}; + +static_assert(no_unqualified_lookup>()); + +namespace test { +template +struct iterator { + using value_type = std::pair; + using difference_type = std::ptrdiff_t; + using iterator_category = std::forward_iterator_tag; + + iterator() = default; + + value_type operator*() const; + iterator& operator++(); + iterator operator++(int); + + bool operator==(iterator const&) const = default; +}; + +template +struct range { + std::pair const* begin() const; + std::pair const* end() const; +}; + +template +void any_of(iterator, iterator, auto) { + static_assert(std::same_as); +} + +template +void any_of(iterator, iterator, auto, auto) { + static_assert(std::same_as); +} + +template +void any_of(R&&, auto) { + static_assert(std::same_as); +} + +template +void any_of(R&&, auto, auto) { + static_assert(std::same_as); +} +} // namespace test + +// When found by unqualified ([basic.lookup.unqual]) name lookup for the postfix-expression in a +// function cany ([expr.cany]), they inhibit argument-dependent name lookup. +void adl_inhibition() { + using std::ranges::any_of; + + test::iterator*> x; + (void)any_of(x, x, f); + (void)any_of(x, x, f, &std::pair::first); + + test::range r; + (void)any_of(r, f); + (void)any_of(r, f, &std::pair::first); +} diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.none_of/ranges_none_of/ranges_none_of.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.none_of/ranges_none_of/ranges_none_of.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.none_of/ranges_none_of/ranges_none_of.pass.cpp @@ -0,0 +1,132 @@ +//===----------------------------------------------------------------------===// +// +// 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-no-concepts +// UNSUPPORTED: gcc-10 + +// + +// ranges::none_of + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "test_algorithm.h" +#include "test_macros.h" +#include "test_iterators.h" +#include "test_range.h" + +template class I, class T> +constexpr bool check_none_of() +{ + namespace ranges = std::ranges; + + auto range = std::array{10, 10, 10, 10, 10, 10, 10, 10, 10, 10}; + auto successor = [](auto const x) { return x + 1; }; + auto is_zero = [](T const x) { return x == 0; }; + auto is_ten = [](T const x) { return x == 10; }; + + { + auto pred = complexity_invocable(is_zero); + { + auto subrange = ranges::subrange(I(range.begin()), sentinel_wrapper(range.end())); + assert(ranges::none_of(subrange.begin(), subrange.end(), std::ref(pred))); + } + { + auto subrange = ranges::subrange(I(range.begin()), sentinel_wrapper(range.end())); + assert(ranges::none_of(subrange, std::ref(pred))); + } + + assert(pred.count() == 2 * ranges::ssize(range)); + } + { + auto pred = complexity_invocable(is_ten); + { + auto subrange = ranges::subrange(I(range.begin()), sentinel_wrapper(range.end())); + assert(!ranges::none_of(subrange.begin(), subrange.end(), std::ref(pred))); + } + { + auto subrange = ranges::subrange(I(range.begin()), sentinel_wrapper(range.end())); + assert(!ranges::none_of(subrange, std::ref(pred))); + } + assert(pred.count() == 2); + } + { + auto pred = complexity_invocable(is_zero); + auto proj = complexity_invocable(successor); + { + auto subrange = ranges::subrange(I(range.begin()), sentinel_wrapper(range.end())); + assert(ranges::none_of(subrange.begin(), subrange.end(), std::ref(pred), std::ref(proj))); + } + { + auto subrange = ranges::subrange(I(range.begin()), sentinel_wrapper(range.end())); + assert(ranges::none_of(subrange, std::ref(pred), std::ref(proj))); + } + assert(pred.count() == 2 * ranges::ssize(range)); + assert(proj.count() == 2 * ranges::ssize(range)); + } + { + auto pred = complexity_invocable([](auto const x){ return x % 2 != 0; }); + auto proj = complexity_invocable(successor); + { + auto subrange = ranges::subrange(I(range.begin()), sentinel_wrapper(range.end())); + assert(!ranges::none_of(subrange.begin(), subrange.end(), std::ref(pred), std::ref(proj))); + } + { + auto subrange = ranges::subrange(I(range.begin()), sentinel_wrapper(range.end())); + assert(!ranges::none_of(subrange, std::ref(pred), std::ref(proj))); + } + assert(pred.count() == 2); + assert(proj.count() == 2); + } + + return true; +} + +int main(int, char**) +{ + // static_assert(check_none_of()); + // static_assert(check_none_of()); + check_none_of(); + check_none_of(); + + // static_assert(check_none_of()); + // static_assert(check_none_of()); + // check_none_of(); + // check_none_of(); + + // static_assert(check_none_of()); + // static_assert(check_none_of()); + // check_none_of(); + // check_none_of(); + + // static_assert(check_none_of()); + // static_assert(check_none_of()); + // check_none_of(); + // check_none_of(); + + // static_assert(check_none_of()); + // static_assert(check_none_of()); + // check_none_of(); + // check_none_of(); + + // static_assert(check_none_of()); + // static_assert(check_none_of()); + // check_none_of(); + // check_none_of(); + + return 0; +} diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.none_of/ranges_none_of/special_function.compile.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.none_of/ranges_none_of/special_function.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.none_of/ranges_none_of/special_function.compile.pass.cpp @@ -0,0 +1,110 @@ +//===----------------------------------------------------------------------===// +// +// 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-no-concepts +// UNSUPPORTED: gcc-10 + +// ranges::none_of + +#include + +#include +#include +#include +#include + +#include "test_standard_function.h" + +static_assert(is_function_like()); + +namespace ranges = std::ranges; + +namespace std::ranges { + template + class basic_istream_view { + struct iterator; + public: + iterator begin(); + default_sentinel_t end() const; + }; +} // namespace std::ranges + +auto f = [](auto) { return true; }; + +// The entities defined in the std::ranges namespace in this Clause are not found by argument-dependent +// name lookup ([basic.lookup.argdep]). When found by unqualified ([basic.lookup.unqual]) name lookup for +// the postfix-expression in a function cany ([expr.cany]), they inhibit argument-dependent name lookup. +template +constexpr bool no_unqualified_lookup() { + auto identity = ranges::basic_istream_view(); + static_assert(!requires(T value) { none_of(ranges::begin(identity), ranges::end(identity), f); }); + static_assert(!requires(T value) { none_of(ranges::begin(identity), ranges::end(identity), f, &T::first); }); + static_assert(!requires(T value) { none_of(identity, f); }); + static_assert(!requires(T value) { none_of(identity, f, &T::first); }); + return true; +}; + +static_assert(no_unqualified_lookup>()); + +namespace test { +template +struct iterator { + using value_type = std::pair; + using difference_type = std::ptrdiff_t; + using iterator_category = std::forward_iterator_tag; + + iterator() = default; + + value_type operator*() const; + iterator& operator++(); + iterator operator++(int); + + bool operator==(iterator const&) const = default; +}; + +template +struct range { + std::pair const* begin() const; + std::pair const* end() const; +}; + +template +void none_of(iterator, iterator, auto) { + static_assert(std::same_as); +} + +template +void none_of(iterator, iterator, auto, auto) { + static_assert(std::same_as); +} + +template +void none_of(R&&, auto) { + static_assert(std::same_as); +} + +template +void none_of(R&&, auto, auto) { + static_assert(std::same_as); +} +} // namespace test + +// When found by unqualified ([basic.lookup.unqual]) name lookup for the postfix-expression in a +// function cany ([expr.cany]), they inhibit argument-dependent name lookup. +void adl_inhibition() { + using std::ranges::none_of; + + test::iterator*> x; + (void)none_of(x, x, f); + (void)none_of(x, x, f, &std::pair::first); + + test::range r; + (void)none_of(r, f); + (void)none_of(r, f, &std::pair::first); +}