mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-03-09 05:02:19 +00:00
[libc++][ranges] Implement P2443R1: views::chunk_by
This patch implements https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p2443r1.html (`views::chunk_by`). Reviewed By: #libc, var-const Differential Revision: https://reviews.llvm.org/D144767
This commit is contained in:
parent
3e19b10b02
commit
065dc485bd
@ -346,7 +346,7 @@ Status
|
||||
--------------------------------------------------- -----------------
|
||||
``__cpp_lib_ranges_chunk`` *unimplemented*
|
||||
--------------------------------------------------- -----------------
|
||||
``__cpp_lib_ranges_chunk_by`` *unimplemented*
|
||||
``__cpp_lib_ranges_chunk_by`` ``202202L``
|
||||
--------------------------------------------------- -----------------
|
||||
``__cpp_lib_ranges_iota`` *unimplemented*
|
||||
--------------------------------------------------- -----------------
|
||||
|
@ -41,7 +41,7 @@ Implemented Papers
|
||||
|
||||
- P2497R0 - Testing for success or failure of ``<charconv>`` functions
|
||||
- P2697R1 - Interfacing ``bitset`` with ``string_view``
|
||||
|
||||
- P2443R1 - ``views::chunk_by``
|
||||
|
||||
Improvements and New Features
|
||||
-----------------------------
|
||||
|
@ -49,7 +49,7 @@
|
||||
"`P2440R1 <https://wg21.link/P2440R1>`__","LWG","``ranges::iota``, ``ranges::shift_left`` and ``ranges::shift_right``","February 2022","","","|ranges|"
|
||||
"`P2441R2 <https://wg21.link/P2441R2>`__","LWG","``views::join_with``","February 2022","","","|ranges|"
|
||||
"`P2442R1 <https://wg21.link/P2442R1>`__","LWG","Windowing range adaptors: ``views::chunk`` and ``views::slide``","February 2022","","","|ranges|"
|
||||
"`P2443R1 <https://wg21.link/P2443R1>`__","LWG","``views::chunk_by``","February 2022","","","|ranges|"
|
||||
"`P2443R1 <https://wg21.link/P2443R1>`__","LWG","``views::chunk_by``","February 2022","|Complete|","18.0","|ranges|"
|
||||
"","","","","","",""
|
||||
"`P0009R18 <https://wg21.link/P0009R18>`__","LWG","mdspan: A Non-Owning Multidimensional Array Reference","July 2022","|In progress| [#note-P0009R18]_|",""
|
||||
"`P0429R9 <https://wg21.link/P0429R9>`__","LWG","A Standard ``flat_map``","July 2022","",""
|
||||
|
Can't render this file because it has a wrong number of fields in line 2.
|
@ -31,7 +31,7 @@ C++23,`adjacent_transform <https://wg21.link/P2321R2>`_,Hui Xie,No patch yet,Not
|
||||
C++23,`join_with <https://wg21.link/P2441R2>`_,Unassigned,No patch yet,Not started
|
||||
C++23,`slide <https://wg21.link/P2442R1>`_,Unassigned,No patch yet,Not started
|
||||
C++23,`chunk <https://wg21.link/P2442R1>`_,Unassigned,No patch yet,Not started
|
||||
C++23,`chunk_by <https://wg21.link/P2443R1>`_,Unassigned,No patch yet,Not started
|
||||
C++23,`chunk_by <https://wg21.link/P2443R1>`_,Jakub Mazurkiewicz,`D144767 <https://llvm.org/D144767>`,✅
|
||||
C++23,`as_const <https://wg21.link/P2278R4>`_,Unassigned,No patch yet,Not started
|
||||
C++23,`as_rvalue <https://wg21.link/P2446R2>`_,Nikolas Klauser,`D137637 <https://llvm.org/D137637>`_,✅
|
||||
C++23,`stride <https://wg21.link/P1899R3>`_,Hristo Hristov and Will Hawkins,`D156924 <https://llvm.org/D156924>`_,In Progress
|
||||
|
|
@ -602,6 +602,7 @@ set(files
|
||||
__ranges/access.h
|
||||
__ranges/all.h
|
||||
__ranges/as_rvalue_view.h
|
||||
__ranges/chunk_by_view.h
|
||||
__ranges/common_view.h
|
||||
__ranges/concepts.h
|
||||
__ranges/container_compatible_range.h
|
||||
|
@ -24,6 +24,9 @@
|
||||
# pragma GCC system_header
|
||||
#endif
|
||||
|
||||
_LIBCPP_PUSH_MACROS
|
||||
#include <__undef_macros>
|
||||
|
||||
#if _LIBCPP_STD_VER >= 20
|
||||
|
||||
_LIBCPP_BEGIN_NAMESPACE_STD
|
||||
@ -75,4 +78,6 @@ _LIBCPP_END_NAMESPACE_STD
|
||||
|
||||
#endif // _LIBCPP_STD_VER >= 20
|
||||
|
||||
_LIBCPP_POP_MACROS
|
||||
|
||||
#endif // _LIBCPP___ALGORITHM_RANGES_ADJACENT_FIND_H
|
||||
|
230
libcxx/include/__ranges/chunk_by_view.h
Normal file
230
libcxx/include/__ranges/chunk_by_view.h
Normal file
@ -0,0 +1,230 @@
|
||||
// -*- C++ -*-
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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___RANGES_CHUNK_BY_VIEW_H
|
||||
#define _LIBCPP___RANGES_CHUNK_BY_VIEW_H
|
||||
|
||||
#include <__algorithm/ranges_adjacent_find.h>
|
||||
#include <__assert>
|
||||
#include <__concepts/constructible.h>
|
||||
#include <__config>
|
||||
#include <__functional/bind_back.h>
|
||||
#include <__functional/invoke.h>
|
||||
#include <__functional/not_fn.h>
|
||||
#include <__functional/reference_wrapper.h>
|
||||
#include <__iterator/concepts.h>
|
||||
#include <__iterator/default_sentinel.h>
|
||||
#include <__iterator/iterator_traits.h>
|
||||
#include <__iterator/next.h>
|
||||
#include <__iterator/prev.h>
|
||||
#include <__memory/addressof.h>
|
||||
#include <__ranges/access.h>
|
||||
#include <__ranges/all.h>
|
||||
#include <__ranges/concepts.h>
|
||||
#include <__ranges/movable_box.h>
|
||||
#include <__ranges/non_propagating_cache.h>
|
||||
#include <__ranges/range_adaptor.h>
|
||||
#include <__ranges/reverse_view.h>
|
||||
#include <__ranges/subrange.h>
|
||||
#include <__ranges/view_interface.h>
|
||||
#include <__type_traits/conditional.h>
|
||||
#include <__type_traits/decay.h>
|
||||
#include <__type_traits/is_nothrow_constructible.h>
|
||||
#include <__type_traits/is_object.h>
|
||||
#include <__utility/forward.h>
|
||||
#include <__utility/in_place.h>
|
||||
#include <__utility/move.h>
|
||||
|
||||
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
||||
# pragma GCC system_header
|
||||
#endif
|
||||
|
||||
_LIBCPP_PUSH_MACROS
|
||||
#include <__undef_macros>
|
||||
|
||||
_LIBCPP_BEGIN_NAMESPACE_STD
|
||||
|
||||
#if _LIBCPP_STD_VER >= 23
|
||||
|
||||
namespace ranges {
|
||||
|
||||
template <forward_range _View, indirect_binary_predicate<iterator_t<_View>, iterator_t<_View>> _Pred>
|
||||
requires view<_View> && is_object_v<_Pred>
|
||||
class chunk_by_view : public view_interface<chunk_by_view<_View, _Pred>> {
|
||||
_LIBCPP_NO_UNIQUE_ADDRESS _View __base_ = _View();
|
||||
_LIBCPP_NO_UNIQUE_ADDRESS __movable_box<_Pred> __pred_;
|
||||
|
||||
// We cache the result of begin() to allow providing an amortized O(1).
|
||||
using _Cache = __non_propagating_cache<iterator_t<_View>>;
|
||||
_Cache __cached_begin_;
|
||||
|
||||
class __iterator;
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr iterator_t<_View> __find_next(iterator_t<_View> __current) {
|
||||
_LIBCPP_ASSERT_UNCATEGORIZED(
|
||||
__pred_.__has_value(), "Trying to call __find_next() on a chunk_by_view that does not have a valid predicate.");
|
||||
|
||||
return ranges::next(ranges::adjacent_find(__current, ranges::end(__base_), std::not_fn(std::ref(*__pred_))),
|
||||
1,
|
||||
ranges::end(__base_));
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr iterator_t<_View> __find_prev(iterator_t<_View> __current)
|
||||
requires bidirectional_range<_View>
|
||||
{
|
||||
_LIBCPP_ASSERT_UNCATEGORIZED(
|
||||
__current != ranges::begin(__base_), "Trying to call __find_prev() on a begin iterator.");
|
||||
_LIBCPP_ASSERT_UNCATEGORIZED(
|
||||
__pred_.__has_value(), "Trying to call __find_prev() on a chunk_by_view that does not have a valid predicate.");
|
||||
|
||||
auto __first = ranges::begin(__base_);
|
||||
reverse_view __reversed{subrange{__first, __current}};
|
||||
auto __reversed_pred = [this]<class _Tp, class _Up>(_Tp&& __x, _Up&& __y) {
|
||||
return !std::invoke(*__pred_, std::forward<_Up>(__y), std::forward<_Tp>(__x));
|
||||
};
|
||||
return ranges::prev(ranges::adjacent_find(__reversed, __reversed_pred).base(), 1, std::move(__first));
|
||||
}
|
||||
|
||||
public:
|
||||
_LIBCPP_HIDE_FROM_ABI chunk_by_view()
|
||||
requires default_initializable<_View> && default_initializable<_Pred>
|
||||
= default;
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr explicit chunk_by_view(_View __base, _Pred __pred)
|
||||
: __base_(std::move(__base)), __pred_(in_place, std::move(__pred)) {}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr _View base() const&
|
||||
requires copy_constructible<_View>
|
||||
{
|
||||
return __base_;
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr _View base() && { return std::move(__base_); }
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr const _Pred& pred() const { return *__pred_; }
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr __iterator begin() {
|
||||
_LIBCPP_ASSERT_UNCATEGORIZED(
|
||||
__pred_.__has_value(), "Trying to call begin() on a chunk_by_view that does not have a valid predicate.");
|
||||
|
||||
auto __first = ranges::begin(__base_);
|
||||
if (!__cached_begin_.__has_value()) {
|
||||
__cached_begin_.__emplace(__find_next(__first));
|
||||
}
|
||||
return {*this, std::move(__first), *__cached_begin_};
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr auto end() {
|
||||
if constexpr (common_range<_View>) {
|
||||
return __iterator{*this, ranges::end(__base_), ranges::end(__base_)};
|
||||
} else {
|
||||
return default_sentinel;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <class _Range, class _Pred>
|
||||
chunk_by_view(_Range&&, _Pred) -> chunk_by_view<views::all_t<_Range>, _Pred>;
|
||||
|
||||
template <forward_range _View, indirect_binary_predicate<iterator_t<_View>, iterator_t<_View>> _Pred>
|
||||
requires view<_View> && is_object_v<_Pred>
|
||||
class chunk_by_view<_View, _Pred>::__iterator {
|
||||
friend chunk_by_view;
|
||||
|
||||
chunk_by_view* __parent_ = nullptr;
|
||||
_LIBCPP_NO_UNIQUE_ADDRESS iterator_t<_View> __current_ = iterator_t<_View>();
|
||||
_LIBCPP_NO_UNIQUE_ADDRESS iterator_t<_View> __next_ = iterator_t<_View>();
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr __iterator(
|
||||
chunk_by_view& __parent, iterator_t<_View> __current, iterator_t<_View> __next)
|
||||
: __parent_(std::addressof(__parent)), __current_(__current), __next_(__next) {}
|
||||
|
||||
public:
|
||||
using value_type = subrange<iterator_t<_View>>;
|
||||
using difference_type = range_difference_t<_View>;
|
||||
using iterator_category = input_iterator_tag;
|
||||
using iterator_concept = conditional_t<bidirectional_range<_View>, bidirectional_iterator_tag, forward_iterator_tag>;
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI __iterator() = default;
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr value_type operator*() const {
|
||||
_LIBCPP_ASSERT_UNCATEGORIZED(__current_ != __next_, "Trying to dereference past-the-end chunk_by_view iterator.");
|
||||
return {__current_, __next_};
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator++() {
|
||||
_LIBCPP_ASSERT_UNCATEGORIZED(__current_ != __next_, "Trying to increment past end chunk_by_view iterator.");
|
||||
__current_ = __next_;
|
||||
__next_ = __parent_->__find_next(__current_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr __iterator operator++(int) {
|
||||
auto __tmp = *this;
|
||||
++*this;
|
||||
return __tmp;
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator--()
|
||||
requires bidirectional_range<_View>
|
||||
{
|
||||
__next_ = __current_;
|
||||
__current_ = __parent_->__find_prev(__next_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr __iterator operator--(int)
|
||||
requires bidirectional_range<_View>
|
||||
{
|
||||
auto __tmp = *this;
|
||||
--*this;
|
||||
return __tmp;
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const __iterator& __x, const __iterator& __y) {
|
||||
return __x.__current_ == __y.__current_;
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const __iterator& __x, default_sentinel_t) {
|
||||
return __x.__current_ == __x.__next_;
|
||||
}
|
||||
};
|
||||
|
||||
namespace views {
|
||||
namespace __chunk_by {
|
||||
struct __fn {
|
||||
template <class _Range, class _Pred>
|
||||
_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Range&& __range, _Pred&& __pred) const
|
||||
noexcept(noexcept(/**/ chunk_by_view(std::forward<_Range>(__range), std::forward<_Pred>(__pred))))
|
||||
-> decltype(/*--*/ chunk_by_view(std::forward<_Range>(__range), std::forward<_Pred>(__pred))) {
|
||||
return /*-------------*/ chunk_by_view(std::forward<_Range>(__range), std::forward<_Pred>(__pred));
|
||||
}
|
||||
|
||||
template <class _Pred>
|
||||
requires constructible_from<decay_t<_Pred>, _Pred>
|
||||
_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Pred&& __pred) const
|
||||
noexcept(is_nothrow_constructible_v<decay_t<_Pred>, _Pred>) {
|
||||
return __range_adaptor_closure_t(std::__bind_back(*this, std::forward<_Pred>(__pred)));
|
||||
}
|
||||
};
|
||||
} // namespace __chunk_by
|
||||
|
||||
inline namespace __cpo {
|
||||
inline constexpr auto chunk_by = __chunk_by::__fn{};
|
||||
} // namespace __cpo
|
||||
} // namespace views
|
||||
} // namespace ranges
|
||||
|
||||
#endif // _LIBCPP_STD_VER >= 23
|
||||
|
||||
_LIBCPP_END_NAMESPACE_STD
|
||||
|
||||
_LIBCPP_POP_MACROS
|
||||
|
||||
#endif // _LIBCPP___RANGES_CHUNK_BY_VIEW_H
|
@ -26,6 +26,9 @@
|
||||
# pragma GCC system_header
|
||||
#endif
|
||||
|
||||
_LIBCPP_PUSH_MACROS
|
||||
#include <__undef_macros>
|
||||
|
||||
_LIBCPP_BEGIN_NAMESPACE_STD
|
||||
|
||||
#if _LIBCPP_STD_VER >= 20
|
||||
@ -203,4 +206,6 @@ public:
|
||||
|
||||
_LIBCPP_END_NAMESPACE_STD
|
||||
|
||||
_LIBCPP_POP_MACROS
|
||||
|
||||
#endif // _LIBCPP___RANGES_MOVABLE_BOX_H
|
||||
|
@ -1659,6 +1659,7 @@ module std_private_ranges_all [system] {
|
||||
export std_private_ranges_owning_view
|
||||
}
|
||||
module std_private_ranges_as_rvalue_view [system] { header "__ranges/as_rvalue_view.h" }
|
||||
module std_private_ranges_chunk_by_view [system] { header "__ranages/chunk_by_view.h" }
|
||||
module std_private_ranges_common_view [system] { header "__ranges/common_view.h" }
|
||||
module std_private_ranges_concepts [system] {
|
||||
header "__ranges/concepts.h"
|
||||
|
@ -320,17 +320,24 @@ namespace std::ranges {
|
||||
class zip_view; // C++23
|
||||
|
||||
template<class... Views>
|
||||
inline constexpr bool enable_borrowed_range<zip_view<Views...>> = // C++23
|
||||
inline constexpr bool enable_borrowed_range<zip_view<Views...>> = // C++23
|
||||
(enable_borrowed_range<Views> && ...);
|
||||
|
||||
namespace views { inline constexpr unspecified zip = unspecified; } // C++23
|
||||
namespace views { inline constexpr unspecified zip = unspecified; } // C++23
|
||||
|
||||
// [range.as.rvalue]
|
||||
template <view V>
|
||||
requires input_range<V>
|
||||
class as_rvalue_view; // since C++23
|
||||
class as_rvalue_view; // C++23
|
||||
|
||||
namespace views { inline constexpr unspecified as_rvalue ) unspecified; } // since C++23
|
||||
namespace views { inline constexpr unspecified as_rvalue ) unspecified; } // C++23
|
||||
|
||||
[range.chunk.by]
|
||||
template<forward_range V, indirect_binary_predicate<iterator_t<V>, iterator_t<V>> Pred>
|
||||
requires view<V> && is_object_v<Pred>
|
||||
class chunk_by_view; // C++23
|
||||
|
||||
namespace views { inline constexpr unspecified chunk_by = unspecified; } // C++23
|
||||
}
|
||||
|
||||
namespace std {
|
||||
@ -373,6 +380,7 @@ namespace std {
|
||||
#include <__ranges/access.h>
|
||||
#include <__ranges/all.h>
|
||||
#include <__ranges/as_rvalue_view.h>
|
||||
#include <__ranges/chunk_by_view.h>
|
||||
#include <__ranges/common_view.h>
|
||||
#include <__ranges/concepts.h>
|
||||
#include <__ranges/counted.h>
|
||||
|
@ -435,7 +435,7 @@ __cpp_lib_within_lifetime 202306L <type_traits>
|
||||
// # define __cpp_lib_print 202207L
|
||||
# define __cpp_lib_ranges_as_rvalue 202207L
|
||||
// # define __cpp_lib_ranges_chunk 202202L
|
||||
// # define __cpp_lib_ranges_chunk_by 202202L
|
||||
# define __cpp_lib_ranges_chunk_by 202202L
|
||||
// # define __cpp_lib_ranges_iota 202202L
|
||||
// # define __cpp_lib_ranges_join_with 202202L
|
||||
# define __cpp_lib_ranges_repeat 202207L
|
||||
|
@ -309,6 +309,7 @@ export namespace std {
|
||||
namespace views {
|
||||
using std::ranges::views::slide;
|
||||
}
|
||||
#endif
|
||||
|
||||
// [range.chunk.by], chunk by view
|
||||
using std::ranges::chunk_by_view;
|
||||
@ -317,6 +318,7 @@ export namespace std {
|
||||
using std::ranges::views::chunk_by;
|
||||
}
|
||||
|
||||
#if 0
|
||||
// [range.stride], stride view
|
||||
using std::ranges::stride_view;
|
||||
|
||||
|
@ -0,0 +1,26 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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, c++20
|
||||
|
||||
// <ranges>
|
||||
|
||||
// Test the libc++ extension that std::views::chunk_by is marked as [[nodiscard]].
|
||||
|
||||
#include <functional>
|
||||
#include <ranges>
|
||||
|
||||
void test() {
|
||||
int range[] = {1, 2, 3, 0, 1, 2};
|
||||
std::ranges::less_equal pred;
|
||||
|
||||
std::views::chunk_by(pred); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||
std::views::chunk_by(range, pred); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||
range | std::views::chunk_by(pred); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||
std::views::all | std::views::chunk_by(pred); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// REQUIRES: has-unix-headers
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
|
||||
// UNSUPPORTED: no-exceptions
|
||||
// UNSUPPORTED: !libcpp-hardening-mode=debug
|
||||
// XFAIL: availability-verbose_abort-missing
|
||||
|
||||
// <ranges>
|
||||
|
||||
// Call begin() on chunk_by_view with empty predicate
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include "check_assertion.h"
|
||||
#include "types.h"
|
||||
|
||||
int main(int, char**) {
|
||||
int input[] = {1, 2, 3};
|
||||
auto view1 = std::views::chunk_by(input, ThrowOnCopyPred{});
|
||||
auto view2 = std::views::chunk_by(input, ThrowOnCopyPred{});
|
||||
try {
|
||||
view1 = view2;
|
||||
} catch (...) {
|
||||
}
|
||||
TEST_LIBCPP_ASSERT_FAILURE(
|
||||
view1.begin(), "Trying to call begin() on a chunk_by_view that does not have a valid predicate.");
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// REQUIRES: has-unix-headers
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
|
||||
// UNSUPPORTED: no-exceptions
|
||||
// UNSUPPORTED: !libcpp-hardening-mode=debug
|
||||
// XFAIL: availability-verbose_abort-missing
|
||||
|
||||
// <ranges>
|
||||
|
||||
// Call find-next() on chunk_by_view with empty predicate
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include "check_assertion.h"
|
||||
#include "types.h"
|
||||
|
||||
int main(int, char**) {
|
||||
int input[] = {1, 2, 3};
|
||||
// This is the easiest way to get '__find_next' to fail. If we used default constructed view here,
|
||||
// then begin() would fail instead of __find_next.
|
||||
auto view1 = std::views::chunk_by(input, ThrowOnCopyPred{});
|
||||
auto view2 = std::views::chunk_by(input, ThrowOnCopyPred{});
|
||||
auto it = view1.begin();
|
||||
try {
|
||||
view1 = view2;
|
||||
} catch (...) {
|
||||
}
|
||||
TEST_LIBCPP_ASSERT_FAILURE(
|
||||
++it, "Trying to call __find_next() on a chunk_by_view that does not have a valid predicate.");
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// REQUIRES: has-unix-headers
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
|
||||
// UNSUPPORTED: no-exceptions
|
||||
// UNSUPPORTED: !libcpp-hardening-mode=debug
|
||||
// XFAIL: availability-verbose_abort-missing
|
||||
|
||||
// <ranges>
|
||||
|
||||
// Call find-prev() on chunk_by_view with begin iterator
|
||||
// Call find-prev() on chunk_by_view with empty predicate
|
||||
|
||||
#include <functional>
|
||||
#include <ranges>
|
||||
|
||||
#include "check_assertion.h"
|
||||
#include "types.h"
|
||||
|
||||
int main(int, char**) {
|
||||
int input[] = {1, 1, 2, 2};
|
||||
|
||||
{ // Call find-prev() on chunk_by_view with begin iterator
|
||||
auto view = std::views::chunk_by(input, std::equal_to{});
|
||||
auto it = view.begin();
|
||||
TEST_LIBCPP_ASSERT_FAILURE(--it, "Trying to call __find_prev() on a begin iterator.");
|
||||
}
|
||||
|
||||
{ // Call find-prev() on chunk_by_view with empty predicate
|
||||
auto view1 = std::views::chunk_by(input, ThrowOnCopyPred{});
|
||||
auto view2 = std::views::chunk_by(input, ThrowOnCopyPred{});
|
||||
auto it = view1.begin();
|
||||
++it;
|
||||
try {
|
||||
view1 = view2;
|
||||
} catch (...) {
|
||||
}
|
||||
TEST_LIBCPP_ASSERT_FAILURE(
|
||||
--it, "Trying to call __find_prev() on a chunk_by_view that does not have a valid predicate.");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// REQUIRES: has-unix-headers
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
|
||||
// UNSUPPORTED: !libcpp-hardening-mode=debug
|
||||
// XFAIL: availability-verbose_abort-missing
|
||||
|
||||
// <ranges>
|
||||
|
||||
// Dereference past end chunk_by_view iterator
|
||||
|
||||
#include <functional>
|
||||
#include <ranges>
|
||||
|
||||
#include "check_assertion.h"
|
||||
|
||||
int main(int, char**) {
|
||||
int input[] = {1, 2, 3};
|
||||
auto view = std::views::chunk_by(input, std::less{});
|
||||
auto it = view.begin();
|
||||
++it;
|
||||
TEST_LIBCPP_ASSERT_FAILURE(*it, "Trying to dereference past-the-end chunk_by_view iterator.");
|
||||
return 0;
|
||||
}
|
@ -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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// REQUIRES: has-unix-headers
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
|
||||
// UNSUPPORTED: !libcpp-hardening-mode=debug
|
||||
// XFAIL: availability-verbose_abort-missing
|
||||
|
||||
// <ranges>
|
||||
|
||||
// Increment past end chunk_by_view iterator
|
||||
|
||||
#include <functional>
|
||||
#include <ranges>
|
||||
|
||||
#include "check_assertion.h"
|
||||
|
||||
int main(int, char**) {
|
||||
int input[] = {1, 2, 3};
|
||||
auto view = std::views::chunk_by(input, std::less{});
|
||||
auto it = view.begin();
|
||||
++it;
|
||||
TEST_LIBCPP_ASSERT_FAILURE(++it, "Trying to increment past end chunk_by_view iterator.");
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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 TEST_LIBCXX_RANGES_RANGE_ADAPTORS_RANGE_CHUNK_BY_TYPES_H
|
||||
#define TEST_LIBCXX_RANGES_RANGE_ADAPTORS_RANGE_CHUNK_BY_TYPES_H
|
||||
|
||||
struct ThrowOnCopyPred {
|
||||
ThrowOnCopyPred() = default;
|
||||
ThrowOnCopyPred(const ThrowOnCopyPred&) { throw 0; }
|
||||
ThrowOnCopyPred& operator=(const ThrowOnCopyPred&) = delete;
|
||||
|
||||
ThrowOnCopyPred(ThrowOnCopyPred&&) = default;
|
||||
ThrowOnCopyPred& operator=(ThrowOnCopyPred&&) = default;
|
||||
|
||||
bool operator()(int x, int y) const { return x != y; }
|
||||
};
|
||||
|
||||
#endif // TEST_LIBCXX_RANGES_RANGE_ADAPTORS_RANGE_CHUNK_BY_TYPES_H
|
@ -687,11 +687,11 @@ ranges initializer_list
|
||||
ranges iosfwd
|
||||
ranges iterator
|
||||
ranges limits
|
||||
ranges new
|
||||
ranges optional
|
||||
ranges span
|
||||
ranges tuple
|
||||
ranges type_traits
|
||||
ranges variant
|
||||
ranges version
|
||||
ratio climits
|
||||
ratio cstdint
|
||||
|
|
@ -692,11 +692,11 @@ ranges initializer_list
|
||||
ranges iosfwd
|
||||
ranges iterator
|
||||
ranges limits
|
||||
ranges new
|
||||
ranges optional
|
||||
ranges span
|
||||
ranges tuple
|
||||
ranges type_traits
|
||||
ranges variant
|
||||
ranges version
|
||||
ratio climits
|
||||
ratio cstdint
|
||||
|
|
@ -694,11 +694,11 @@ ranges initializer_list
|
||||
ranges iosfwd
|
||||
ranges iterator
|
||||
ranges limits
|
||||
ranges new
|
||||
ranges optional
|
||||
ranges span
|
||||
ranges tuple
|
||||
ranges type_traits
|
||||
ranges variant
|
||||
ranges version
|
||||
ratio climits
|
||||
ratio cstdint
|
||||
|
|
@ -694,11 +694,11 @@ ranges initializer_list
|
||||
ranges iosfwd
|
||||
ranges iterator
|
||||
ranges limits
|
||||
ranges new
|
||||
ranges optional
|
||||
ranges span
|
||||
ranges tuple
|
||||
ranges type_traits
|
||||
ranges variant
|
||||
ranges version
|
||||
ratio climits
|
||||
ratio cstdint
|
||||
|
|
@ -700,11 +700,11 @@ ranges initializer_list
|
||||
ranges iosfwd
|
||||
ranges iterator
|
||||
ranges limits
|
||||
ranges new
|
||||
ranges optional
|
||||
ranges span
|
||||
ranges tuple
|
||||
ranges type_traits
|
||||
ranges variant
|
||||
ranges version
|
||||
ratio climits
|
||||
ratio cstdint
|
||||
|
|
@ -499,6 +499,7 @@ ranges initializer_list
|
||||
ranges iosfwd
|
||||
ranges iterator
|
||||
ranges limits
|
||||
ranges new
|
||||
ranges optional
|
||||
ranges span
|
||||
ranges tuple
|
||||
|
|
@ -499,6 +499,7 @@ ranges initializer_list
|
||||
ranges iosfwd
|
||||
ranges iterator
|
||||
ranges limits
|
||||
ranges new
|
||||
ranges optional
|
||||
ranges span
|
||||
ranges tuple
|
||||
|
|
@ -214,17 +214,11 @@
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# if !defined(_LIBCPP_VERSION)
|
||||
# ifndef __cpp_lib_ranges_chunk_by
|
||||
# error "__cpp_lib_ranges_chunk_by should be defined in c++23"
|
||||
# endif
|
||||
# if __cpp_lib_ranges_chunk_by != 202202L
|
||||
# error "__cpp_lib_ranges_chunk_by should have the value 202202L in c++23"
|
||||
# endif
|
||||
# else // _LIBCPP_VERSION
|
||||
# ifdef __cpp_lib_ranges_chunk_by
|
||||
# error "__cpp_lib_ranges_chunk_by should not be defined because it is unimplemented in libc++!"
|
||||
# endif
|
||||
# ifndef __cpp_lib_ranges_chunk_by
|
||||
# error "__cpp_lib_ranges_chunk_by should be defined in c++23"
|
||||
# endif
|
||||
# if __cpp_lib_ranges_chunk_by != 202202L
|
||||
# error "__cpp_lib_ranges_chunk_by should have the value 202202L in c++23"
|
||||
# endif
|
||||
|
||||
# if !defined(_LIBCPP_VERSION)
|
||||
@ -309,17 +303,11 @@
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# if !defined(_LIBCPP_VERSION)
|
||||
# ifndef __cpp_lib_ranges_chunk_by
|
||||
# error "__cpp_lib_ranges_chunk_by should be defined in c++26"
|
||||
# endif
|
||||
# if __cpp_lib_ranges_chunk_by != 202202L
|
||||
# error "__cpp_lib_ranges_chunk_by should have the value 202202L in c++26"
|
||||
# endif
|
||||
# else // _LIBCPP_VERSION
|
||||
# ifdef __cpp_lib_ranges_chunk_by
|
||||
# error "__cpp_lib_ranges_chunk_by should not be defined because it is unimplemented in libc++!"
|
||||
# endif
|
||||
# ifndef __cpp_lib_ranges_chunk_by
|
||||
# error "__cpp_lib_ranges_chunk_by should be defined in c++26"
|
||||
# endif
|
||||
# if __cpp_lib_ranges_chunk_by != 202202L
|
||||
# error "__cpp_lib_ranges_chunk_by should have the value 202202L in c++26"
|
||||
# endif
|
||||
|
||||
# if !defined(_LIBCPP_VERSION)
|
||||
|
@ -4971,17 +4971,11 @@
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# if !defined(_LIBCPP_VERSION)
|
||||
# ifndef __cpp_lib_ranges_chunk_by
|
||||
# error "__cpp_lib_ranges_chunk_by should be defined in c++23"
|
||||
# endif
|
||||
# if __cpp_lib_ranges_chunk_by != 202202L
|
||||
# error "__cpp_lib_ranges_chunk_by should have the value 202202L in c++23"
|
||||
# endif
|
||||
# else // _LIBCPP_VERSION
|
||||
# ifdef __cpp_lib_ranges_chunk_by
|
||||
# error "__cpp_lib_ranges_chunk_by should not be defined because it is unimplemented in libc++!"
|
||||
# endif
|
||||
# ifndef __cpp_lib_ranges_chunk_by
|
||||
# error "__cpp_lib_ranges_chunk_by should be defined in c++23"
|
||||
# endif
|
||||
# if __cpp_lib_ranges_chunk_by != 202202L
|
||||
# error "__cpp_lib_ranges_chunk_by should have the value 202202L in c++23"
|
||||
# endif
|
||||
|
||||
# if !defined(_LIBCPP_VERSION)
|
||||
@ -6518,17 +6512,11 @@
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# if !defined(_LIBCPP_VERSION)
|
||||
# ifndef __cpp_lib_ranges_chunk_by
|
||||
# error "__cpp_lib_ranges_chunk_by should be defined in c++26"
|
||||
# endif
|
||||
# if __cpp_lib_ranges_chunk_by != 202202L
|
||||
# error "__cpp_lib_ranges_chunk_by should have the value 202202L in c++26"
|
||||
# endif
|
||||
# else // _LIBCPP_VERSION
|
||||
# ifdef __cpp_lib_ranges_chunk_by
|
||||
# error "__cpp_lib_ranges_chunk_by should not be defined because it is unimplemented in libc++!"
|
||||
# endif
|
||||
# ifndef __cpp_lib_ranges_chunk_by
|
||||
# error "__cpp_lib_ranges_chunk_by should be defined in c++26"
|
||||
# endif
|
||||
# if __cpp_lib_ranges_chunk_by != 202202L
|
||||
# error "__cpp_lib_ranges_chunk_by should have the value 202202L in c++26"
|
||||
# endif
|
||||
|
||||
# if !defined(_LIBCPP_VERSION)
|
||||
|
@ -0,0 +1,237 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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, c++20
|
||||
|
||||
// <ranges>
|
||||
|
||||
// std::views::chunk_by
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <concepts>
|
||||
#include <initializer_list>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "test_iterators.h"
|
||||
|
||||
template <class View, class T>
|
||||
concept CanBePiped = requires(View&& view, T&& t) {
|
||||
{ std::forward<View>(view) | std::forward<T>(t) };
|
||||
};
|
||||
|
||||
struct Pred {
|
||||
constexpr bool operator()(int x, int y) const { return x != -y; }
|
||||
};
|
||||
|
||||
struct NonCopyablePredicate : Pred {
|
||||
NonCopyablePredicate(NonCopyablePredicate const&) = delete;
|
||||
};
|
||||
|
||||
struct Range : std::ranges::view_base {
|
||||
using Iterator = forward_iterator<int*>;
|
||||
using Sentinel = sentinel_wrapper<Iterator>;
|
||||
constexpr explicit Range(int* b, int* e) : begin_(b), end_(e) {}
|
||||
constexpr Iterator begin() const { return Iterator(begin_); }
|
||||
constexpr Sentinel end() const { return Sentinel(Iterator(end_)); }
|
||||
|
||||
private:
|
||||
int* begin_;
|
||||
int* end_;
|
||||
};
|
||||
|
||||
template <typename View>
|
||||
constexpr void compareViews(View v, std::initializer_list<std::initializer_list<int>> list) {
|
||||
auto b1 = v.begin();
|
||||
auto e1 = v.end();
|
||||
auto b2 = list.begin();
|
||||
auto e2 = list.end();
|
||||
for (; b1 != e1 && b2 != e2; ++b1, ++b2) {
|
||||
bool eq = std::ranges::equal(*b1, *b2, [](int x, int y) {
|
||||
assert(x == y);
|
||||
return true;
|
||||
});
|
||||
assert(eq);
|
||||
}
|
||||
assert(b1 == e1);
|
||||
assert(b2 == e2);
|
||||
}
|
||||
|
||||
constexpr int absoluteValue(int x) { return x < 0 ? -x : x; }
|
||||
|
||||
template <class T>
|
||||
constexpr const T&& asConstRvalue(T&& t) {
|
||||
return static_cast<T const&&>(t);
|
||||
}
|
||||
|
||||
constexpr bool test() {
|
||||
int buff[] = {-4, -3, -2, -1, 1, 2, 3, 4};
|
||||
|
||||
// Test range adaptor object
|
||||
{
|
||||
using RangeAdaptorObject = decltype(std::views::chunk_by);
|
||||
static_assert(std::is_const_v<RangeAdaptorObject>);
|
||||
|
||||
// The type of a customization point object, ignoring cv-qualifiers, shall model semiregular
|
||||
static_assert(std::semiregular<std::remove_const<RangeAdaptorObject>>);
|
||||
}
|
||||
|
||||
// Test `views::chunk_by(pred)(v)`
|
||||
{
|
||||
using Result = std::ranges::chunk_by_view<Range, Pred>;
|
||||
Range const range(buff, buff + 8);
|
||||
Pred pred;
|
||||
|
||||
{
|
||||
// 'views::chunk_by(pred)' - &&
|
||||
std::same_as<Result> decltype(auto) result = std::views::chunk_by(pred)(range);
|
||||
compareViews(result, {{-4, -3, -2, -1}, {1, 2, 3, 4}});
|
||||
}
|
||||
{
|
||||
// 'views::chunk_by(pred)' - const&&
|
||||
std::same_as<Result> decltype(auto) result = asConstRvalue(std::views::chunk_by(pred))(range);
|
||||
compareViews(result, {{-4, -3, -2, -1}, {1, 2, 3, 4}});
|
||||
}
|
||||
{
|
||||
// 'views::chunk_by(pred)' - &
|
||||
auto partial = std::views::chunk_by(pred);
|
||||
std::same_as<Result> decltype(auto) result = partial(range);
|
||||
compareViews(result, {{-4, -3, -2, -1}, {1, 2, 3, 4}});
|
||||
}
|
||||
{
|
||||
// 'views::chunk_by(pred)' - const&
|
||||
auto const partial = std::views::chunk_by(pred);
|
||||
std::same_as<Result> decltype(auto) result = partial(range);
|
||||
compareViews(result, {{-4, -3, -2, -1}, {1, 2, 3, 4}});
|
||||
}
|
||||
}
|
||||
|
||||
// Test `v | views::chunk_by(pred)`
|
||||
{
|
||||
using Result = std::ranges::chunk_by_view<Range, Pred>;
|
||||
Range const range(buff, buff + 8);
|
||||
Pred pred;
|
||||
|
||||
{
|
||||
// 'views::chunk_by(pred)' - &&
|
||||
std::same_as<Result> decltype(auto) result = range | std::views::chunk_by(pred);
|
||||
compareViews(result, {{-4, -3, -2, -1}, {1, 2, 3, 4}});
|
||||
}
|
||||
{
|
||||
// 'views::chunk_by(pred)' - const&&
|
||||
std::same_as<Result> decltype(auto) result = range | asConstRvalue(std::views::chunk_by(pred));
|
||||
compareViews(result, {{-4, -3, -2, -1}, {1, 2, 3, 4}});
|
||||
}
|
||||
{
|
||||
// 'views::chunk_by(pred)' - &
|
||||
auto partial = std::views::chunk_by(pred);
|
||||
std::same_as<Result> decltype(auto) result = range | partial;
|
||||
compareViews(result, {{-4, -3, -2, -1}, {1, 2, 3, 4}});
|
||||
}
|
||||
{
|
||||
// 'views::chunk_by(pred)' - const&
|
||||
auto const partial = std::views::chunk_by(pred);
|
||||
std::same_as<Result> decltype(auto) result = range | partial;
|
||||
compareViews(result, {{-4, -3, -2, -1}, {1, 2, 3, 4}});
|
||||
}
|
||||
}
|
||||
|
||||
// Test `views::chunk_by(v, pred)` range adaptor object
|
||||
{
|
||||
using Result = std::ranges::chunk_by_view<Range, Pred>;
|
||||
Range const range(buff, buff + 8);
|
||||
Pred pred;
|
||||
|
||||
{
|
||||
// 'views::chunk_by' - &&
|
||||
auto range_adaptor = std::views::chunk_by;
|
||||
std::same_as<Result> decltype(auto) result = std::move(range_adaptor)(range, pred);
|
||||
compareViews(result, {{-4, -3, -2, -1}, {1, 2, 3, 4}});
|
||||
}
|
||||
{
|
||||
// 'views::chunk_by' - const&&
|
||||
auto const range_adaptor = std::views::chunk_by;
|
||||
std::same_as<Result> decltype(auto) result = std::move(range_adaptor)(range, pred);
|
||||
compareViews(result, {{-4, -3, -2, -1}, {1, 2, 3, 4}});
|
||||
}
|
||||
{
|
||||
// 'views::chunk_by' - &
|
||||
auto range_adaptor = std::views::chunk_by;
|
||||
std::same_as<Result> decltype(auto) result = range_adaptor(range, pred);
|
||||
compareViews(result, {{-4, -3, -2, -1}, {1, 2, 3, 4}});
|
||||
}
|
||||
{
|
||||
// 'views::chunk_by' - const&
|
||||
auto const range_adaptor = std::views::chunk_by;
|
||||
std::same_as<Result> decltype(auto) result = range_adaptor(range, pred);
|
||||
compareViews(result, {{-4, -3, -2, -1}, {1, 2, 3, 4}});
|
||||
}
|
||||
}
|
||||
|
||||
// Test that one can call std::views::chunk_by with arbitrary stuff, as long as we
|
||||
// don't try to actually complete the call by passing it a range.
|
||||
//
|
||||
// That makes no sense and we can't do anything with the result, but it's valid.
|
||||
{
|
||||
int array[3] = {1, 2, 3};
|
||||
[[maybe_unused]] auto partial = std::views::chunk_by(std::move(array));
|
||||
}
|
||||
|
||||
// Test `adaptor | views::chunk_by(pred)`
|
||||
{
|
||||
Range const range(buff, buff + 8);
|
||||
|
||||
{
|
||||
auto pred1 = [](int i) { return absoluteValue(i) < 3; };
|
||||
Pred pred2;
|
||||
using Result = std::ranges::chunk_by_view<std::ranges::filter_view<Range, decltype(pred1)>, Pred>;
|
||||
std::same_as<Result> decltype(auto) result = range | std::views::filter(pred1) | std::views::chunk_by(pred2);
|
||||
compareViews(result, {{-2, -1}, {1, 2}});
|
||||
}
|
||||
{
|
||||
auto pred1 = [](int i) { return absoluteValue(i) < 3; };
|
||||
Pred pred2;
|
||||
using Result = std::ranges::chunk_by_view<std::ranges::filter_view<Range, decltype(pred1)>, Pred>;
|
||||
auto const partial = std::views::filter(pred1) | std::views::chunk_by(pred2);
|
||||
std::same_as<Result> decltype(auto) result = range | partial;
|
||||
compareViews(result, {{-2, -1}, {1, 2}});
|
||||
}
|
||||
}
|
||||
|
||||
// Test SFINAE friendliness
|
||||
{
|
||||
struct NotAView {};
|
||||
struct NotInvocable {};
|
||||
|
||||
static_assert(!CanBePiped<Range, decltype(std::views::chunk_by)>);
|
||||
static_assert(CanBePiped<Range, decltype(std::views::chunk_by(Pred{}))>);
|
||||
static_assert(!CanBePiped<NotAView, decltype(std::views::chunk_by(Pred{}))>);
|
||||
static_assert(!CanBePiped<std::initializer_list<int>, decltype(std::views::chunk_by(Pred{}))>);
|
||||
static_assert(!CanBePiped<Range, decltype(std::views::chunk_by(NotInvocable{}))>);
|
||||
|
||||
static_assert(!std::is_invocable_v<decltype(std::views::chunk_by)>);
|
||||
static_assert(!std::is_invocable_v<decltype(std::views::chunk_by), Pred, Range>);
|
||||
static_assert(std::is_invocable_v<decltype(std::views::chunk_by), Range, Pred>);
|
||||
static_assert(!std::is_invocable_v<decltype(std::views::chunk_by), Range, Pred, Pred>);
|
||||
static_assert(!std::is_invocable_v<decltype(std::views::chunk_by), NonCopyablePredicate>);
|
||||
}
|
||||
|
||||
{ static_assert(std::is_same_v<decltype(std::ranges::views::chunk_by), decltype(std::views::chunk_by)>); }
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,99 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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, c++20
|
||||
|
||||
// <ranges>
|
||||
|
||||
// constexpr View base() const& requires copy_constructible<View>;
|
||||
// constexpr View base() &&;
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include <cassert>
|
||||
#include <concepts>
|
||||
#include <utility>
|
||||
|
||||
struct Range : std::ranges::view_base {
|
||||
constexpr explicit Range(int* b, int* e) : begin_(b), end_(e) {}
|
||||
constexpr Range(Range const& other) : begin_(other.begin_), end_(other.end_), wasCopyInitialized(true) {}
|
||||
constexpr Range(Range&& other) : begin_(other.begin_), end_(other.end_), wasMoveInitialized(true) {}
|
||||
Range& operator=(Range const&) = default;
|
||||
Range& operator=(Range&&) = default;
|
||||
constexpr int* begin() const { return begin_; }
|
||||
constexpr int* end() const { return end_; }
|
||||
|
||||
int* begin_;
|
||||
int* end_;
|
||||
bool wasCopyInitialized = false;
|
||||
bool wasMoveInitialized = false;
|
||||
};
|
||||
|
||||
static_assert(std::ranges::view<Range>);
|
||||
static_assert(std::ranges::forward_range<Range>);
|
||||
|
||||
struct Pred {
|
||||
bool operator()(int, int) const;
|
||||
};
|
||||
|
||||
struct NonCopyableRange : std::ranges::view_base {
|
||||
explicit NonCopyableRange(int*, int*);
|
||||
NonCopyableRange(NonCopyableRange const&) = delete;
|
||||
NonCopyableRange(NonCopyableRange&&) = default;
|
||||
NonCopyableRange& operator=(NonCopyableRange const&) = default;
|
||||
NonCopyableRange& operator=(NonCopyableRange&&) = default;
|
||||
int* begin() const;
|
||||
int* end() const;
|
||||
};
|
||||
|
||||
static_assert(!std::copy_constructible<NonCopyableRange>);
|
||||
|
||||
template <typename T>
|
||||
concept CanCallBaseOn = requires(T t) { std::forward<T>(t).base(); };
|
||||
|
||||
constexpr bool test() {
|
||||
int buff[] = {1, 2, 3, 4};
|
||||
|
||||
// Check the const& overload
|
||||
{
|
||||
Range range(buff, buff + 4);
|
||||
std::ranges::chunk_by_view<Range, Pred> const view(range, Pred{});
|
||||
std::same_as<Range> decltype(auto) result = view.base();
|
||||
assert(result.wasCopyInitialized);
|
||||
assert(result.begin() == buff);
|
||||
assert(result.end() == buff + 4);
|
||||
}
|
||||
|
||||
// Check the && overload
|
||||
{
|
||||
Range range(buff, buff + 4);
|
||||
std::ranges::chunk_by_view<Range, Pred> view(range, Pred{});
|
||||
std::same_as<Range> decltype(auto) result = std::move(view).base();
|
||||
assert(result.wasMoveInitialized);
|
||||
assert(result.begin() == buff);
|
||||
assert(result.end() == buff + 4);
|
||||
}
|
||||
|
||||
// Ensure the const& overload is not considered when the base is not copy-constructible
|
||||
{
|
||||
static_assert(!CanCallBaseOn<std::ranges::chunk_by_view<NonCopyableRange, Pred> const&>);
|
||||
static_assert(!CanCallBaseOn<std::ranges::chunk_by_view<NonCopyableRange, Pred>&>);
|
||||
static_assert(!CanCallBaseOn<std::ranges::chunk_by_view<NonCopyableRange, Pred> const&&>);
|
||||
static_assert(CanCallBaseOn<std::ranges::chunk_by_view<NonCopyableRange, Pred>&&>);
|
||||
static_assert(CanCallBaseOn<std::ranges::chunk_by_view<NonCopyableRange, Pred>>);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,156 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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, c++20
|
||||
|
||||
// <ranges>
|
||||
|
||||
// constexpr iterator begin();
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include <cassert>
|
||||
#include <utility>
|
||||
|
||||
#include "test_iterators.h"
|
||||
#include "types.h"
|
||||
|
||||
struct Range : std::ranges::view_base {
|
||||
using Iterator = forward_iterator<int*>;
|
||||
using Sentinel = sentinel_wrapper<Iterator>;
|
||||
constexpr explicit Range(int* b, int* e) : begin_(b), end_(e) {}
|
||||
constexpr Iterator begin() const { return Iterator(begin_); }
|
||||
constexpr Sentinel end() const { return Sentinel(Iterator(end_)); }
|
||||
|
||||
private:
|
||||
int* begin_;
|
||||
int* end_;
|
||||
};
|
||||
|
||||
struct TrackingPred : TrackInitialization {
|
||||
using TrackInitialization::TrackInitialization;
|
||||
constexpr bool operator()(int x, int y) { return x != -y; }
|
||||
};
|
||||
|
||||
template <class T>
|
||||
concept HasBegin = requires(T t) { t.begin(); };
|
||||
|
||||
static_assert(HasBegin<std::ranges::chunk_by_view<Range, TrackingPred>>);
|
||||
static_assert(!HasBegin<const std::ranges::chunk_by_view<Range, TrackingPred>>);
|
||||
|
||||
constexpr bool test() {
|
||||
int buff[] = {-4, -3, -2, -1, 1, 2, 3, 4};
|
||||
|
||||
// Check the return type of `begin()`
|
||||
{
|
||||
Range range(buff, buff + 1);
|
||||
auto pred = [](int, int) { return true; };
|
||||
std::ranges::chunk_by_view view(range, pred);
|
||||
using ChunkByIterator = std::ranges::iterator_t<decltype(view)>;
|
||||
ASSERT_SAME_TYPE(ChunkByIterator, decltype(view.begin()));
|
||||
}
|
||||
|
||||
// begin() over an empty range
|
||||
{
|
||||
Range range(buff, buff);
|
||||
auto pred = [](int, int) { return true; };
|
||||
std::ranges::chunk_by_view view(range, pred);
|
||||
auto it = view.begin();
|
||||
assert(it == view.begin());
|
||||
assert(it == view.end());
|
||||
}
|
||||
|
||||
// begin() over a 1-element range
|
||||
{
|
||||
Range range(buff, buff + 1);
|
||||
auto pred = [](int x, int y) { return x == y; };
|
||||
std::ranges::chunk_by_view view(range, pred);
|
||||
auto it = view.begin();
|
||||
assert(base((*it).begin()) == buff);
|
||||
assert(base((*it).end()) == buff + 1);
|
||||
}
|
||||
|
||||
// begin() over a 2-element range
|
||||
{
|
||||
Range range(buff, buff + 2);
|
||||
auto pred = [](int x, int y) { return x == y; };
|
||||
std::ranges::chunk_by_view view(range, pred);
|
||||
auto it = view.begin();
|
||||
assert(base((*it).begin()) == buff);
|
||||
assert(base((*it).end()) == buff + 1);
|
||||
assert(base((*++it).begin()) == buff + 1);
|
||||
assert(base((*it).end()) == buff + 2);
|
||||
}
|
||||
|
||||
// begin() over a longer range
|
||||
{
|
||||
Range range(buff, buff + 8);
|
||||
auto pred = [](int x, int y) { return x != -y; };
|
||||
std::ranges::chunk_by_view view(range, pred);
|
||||
auto it = view.begin();
|
||||
assert(base((*it).end()) == buff + 4);
|
||||
}
|
||||
|
||||
// Make sure we do not make a copy of the predicate when we call begin()
|
||||
// (we should be passing it to ranges::adjacent_find using std::ref)
|
||||
{
|
||||
bool moved = false, copied = false;
|
||||
Range range(buff, buff + 2);
|
||||
std::ranges::chunk_by_view view(range, TrackingPred(&moved, &copied));
|
||||
std::exchange(moved, false);
|
||||
[[maybe_unused]] auto it = view.begin();
|
||||
assert(!moved);
|
||||
assert(!copied);
|
||||
}
|
||||
|
||||
// Test with a non-const predicate
|
||||
{
|
||||
Range range(buff, buff + 8);
|
||||
auto pred = [](int x, int y) mutable { return x != -y; };
|
||||
std::ranges::chunk_by_view view(range, pred);
|
||||
auto it = view.begin();
|
||||
assert(base((*it).end()) == buff + 4);
|
||||
}
|
||||
|
||||
// Test with a predicate that takes by non-const reference
|
||||
{
|
||||
Range range(buff, buff + 8);
|
||||
auto pred = [](int& x, int& y) { return x != -y; };
|
||||
std::ranges::chunk_by_view view(range, pred);
|
||||
auto it = view.begin();
|
||||
assert(base((*it).end()) == buff + 4);
|
||||
}
|
||||
|
||||
// Test caching
|
||||
{
|
||||
// Make sure that we cache the result of begin() on subsequent calls
|
||||
Range range(buff, buff + 8);
|
||||
int called = 0;
|
||||
auto pred = [&](int x, int y) {
|
||||
++called;
|
||||
return x != -y;
|
||||
};
|
||||
|
||||
std::ranges::chunk_by_view view(range, pred);
|
||||
assert(called == 0);
|
||||
for (int k = 0; k != 3; ++k) {
|
||||
auto it = view.begin();
|
||||
assert(base((*it).end()) == buff + 4);
|
||||
assert(called == 4); // 4, because the cached iterator is 'buff + 4' (end of the first chunk)
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,121 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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, c++20
|
||||
|
||||
// <ranges>
|
||||
|
||||
// Check constraints on the type itself.
|
||||
//
|
||||
// template <forward_range View, indirect_binary_predicate<iterator_t<View>, iterator_t<View>> Pred>
|
||||
// requires view<View> && is_object_v<Pred>
|
||||
// class chunk_by_view;
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include <concepts>
|
||||
#include <cstddef>
|
||||
#include <iterator>
|
||||
#include <type_traits>
|
||||
|
||||
#include "almost_satisfies_types.h"
|
||||
#include "test_iterators.h"
|
||||
|
||||
template <class View, class Pred>
|
||||
concept CanFormChunkByView = requires { typename std::ranges::chunk_by_view<View, Pred>; };
|
||||
|
||||
// chunk_by_view is not valid when the view is not a forward_range
|
||||
namespace test_when_view_is_not_a_forward_range {
|
||||
|
||||
struct View : std::ranges::view_base {
|
||||
ForwardIteratorNotDerivedFrom begin() const;
|
||||
ForwardIteratorNotDerivedFrom end() const;
|
||||
};
|
||||
struct Pred {
|
||||
bool operator()(int, int) const;
|
||||
};
|
||||
|
||||
static_assert(!std::ranges::forward_range<View>);
|
||||
static_assert(std::indirect_binary_predicate<Pred, int*, int*>);
|
||||
static_assert(std::ranges::view<View>);
|
||||
static_assert(std::is_object_v<Pred>);
|
||||
static_assert(!CanFormChunkByView<View, Pred>);
|
||||
|
||||
} // namespace test_when_view_is_not_a_forward_range
|
||||
|
||||
// chunk_by_view is not valid when the predicate is not indirect_binary_predicate
|
||||
namespace test_when_the_predicate_is_not_indirect_binary_predicate {
|
||||
|
||||
struct View : std::ranges::view_base {
|
||||
int* begin() const;
|
||||
int* end() const;
|
||||
};
|
||||
struct Pred {};
|
||||
|
||||
static_assert(std::ranges::forward_range<View>);
|
||||
static_assert(!std::indirect_binary_predicate<Pred, int*, int*>);
|
||||
static_assert(std::ranges::view<View>);
|
||||
static_assert(std::is_object_v<Pred>);
|
||||
static_assert(!CanFormChunkByView<View, Pred>);
|
||||
|
||||
} // namespace test_when_the_predicate_is_not_indirect_binary_predicate
|
||||
|
||||
// chunk_by_view is not valid when the view is not a view
|
||||
namespace test_when_the_view_param_is_not_a_view {
|
||||
|
||||
struct View {
|
||||
int* begin() const;
|
||||
int* end() const;
|
||||
};
|
||||
struct Pred {
|
||||
bool operator()(int, int) const;
|
||||
};
|
||||
|
||||
static_assert(std::ranges::input_range<View>);
|
||||
static_assert(std::indirect_binary_predicate<Pred, int*, int*>);
|
||||
static_assert(!std::ranges::view<View>);
|
||||
static_assert(std::is_object_v<Pred>);
|
||||
static_assert(!CanFormChunkByView<View, Pred>);
|
||||
|
||||
} // namespace test_when_the_view_param_is_not_a_view
|
||||
|
||||
// chunk_by_view is not valid when the predicate is not an object type
|
||||
namespace test_when_the_predicate_is_not_an_object_type {
|
||||
|
||||
struct View : std::ranges::view_base {
|
||||
int* begin() const;
|
||||
int* end() const;
|
||||
};
|
||||
using Pred = bool (&)(int, int);
|
||||
|
||||
static_assert(std::ranges::input_range<View>);
|
||||
static_assert(std::indirect_binary_predicate<Pred, int*, int*>);
|
||||
static_assert(std::ranges::view<View>);
|
||||
static_assert(!std::is_object_v<Pred>);
|
||||
static_assert(!CanFormChunkByView<View, Pred>);
|
||||
|
||||
} // namespace test_when_the_predicate_is_not_an_object_type
|
||||
|
||||
// chunk_by_view is valid when all the constraints are satisfied (test the test)
|
||||
namespace test_when_all_the_constraints_are_satisfied {
|
||||
|
||||
struct View : std::ranges::view_base {
|
||||
int* begin() const;
|
||||
int* end() const;
|
||||
};
|
||||
struct Pred {
|
||||
bool operator()(int, int) const;
|
||||
};
|
||||
|
||||
static_assert(std::ranges::input_range<View>);
|
||||
static_assert(std::indirect_binary_predicate<Pred, int*, int*>);
|
||||
static_assert(std::ranges::view<View>);
|
||||
static_assert(std::is_object_v<Pred>);
|
||||
static_assert(CanFormChunkByView<View, Pred>);
|
||||
|
||||
} // namespace test_when_all_the_constraints_are_satisfied
|
@ -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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
|
||||
|
||||
// <ranges>
|
||||
|
||||
// template <class Range, class Pred>
|
||||
// chunk_by_view(Range&&, Pred) -> chunk_by_view<views::all_t<Range>, Pred>;
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include <cassert>
|
||||
#include <type_traits>
|
||||
|
||||
#include "test_iterators.h"
|
||||
|
||||
struct View : std::ranges::view_base {
|
||||
View() = default;
|
||||
forward_iterator<int*> begin() const;
|
||||
sentinel_wrapper<forward_iterator<int*>> end() const;
|
||||
};
|
||||
static_assert(std::ranges::view<View>);
|
||||
|
||||
// A range that is not a view
|
||||
struct Range {
|
||||
Range() = default;
|
||||
forward_iterator<int*> begin() const;
|
||||
sentinel_wrapper<forward_iterator<int*>> end() const;
|
||||
};
|
||||
static_assert(std::ranges::range<Range>);
|
||||
static_assert(!std::ranges::view<Range>);
|
||||
|
||||
struct Pred {
|
||||
constexpr bool operator()(int x, int y) const { return x <= y; }
|
||||
};
|
||||
|
||||
constexpr bool test() {
|
||||
{
|
||||
View v;
|
||||
Pred pred;
|
||||
std::ranges::chunk_by_view view(v, pred);
|
||||
static_assert(std::is_same_v<decltype(view), std::ranges::chunk_by_view<View, Pred>>);
|
||||
}
|
||||
{
|
||||
Range r;
|
||||
Pred pred;
|
||||
std::ranges::chunk_by_view view(r, pred);
|
||||
static_assert(std::is_same_v<decltype(view), std::ranges::chunk_by_view<std::ranges::ref_view<Range>, Pred>>);
|
||||
}
|
||||
{
|
||||
Pred pred;
|
||||
std::ranges::chunk_by_view view(Range{}, pred);
|
||||
static_assert(std::is_same_v<decltype(view), std::ranges::chunk_by_view<std::ranges::owning_view<Range>, Pred>>);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
@ -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, c++20
|
||||
|
||||
// <ranges>
|
||||
|
||||
// chunk_by_view() requires std::default_initializable<View> &&
|
||||
// std::default_initializable<Pred> = default;
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include <cassert>
|
||||
#include <type_traits>
|
||||
|
||||
constexpr int buff[] = {-2, 1, -1, 2};
|
||||
|
||||
struct DefaultConstructibleView : std::ranges::view_base {
|
||||
DefaultConstructibleView() = default;
|
||||
constexpr int const* begin() const { return buff; }
|
||||
constexpr int const* end() const { return buff + 4; }
|
||||
};
|
||||
|
||||
struct DefaultConstructiblePredicate {
|
||||
DefaultConstructiblePredicate() = default;
|
||||
constexpr bool operator()(int x, int y) const { return x != -y; }
|
||||
};
|
||||
|
||||
struct NoDefaultView : std::ranges::view_base {
|
||||
NoDefaultView() = delete;
|
||||
int* begin() const;
|
||||
int* end() const;
|
||||
};
|
||||
|
||||
struct NoDefaultPredicate {
|
||||
NoDefaultPredicate() = delete;
|
||||
constexpr bool operator()(int, int) const;
|
||||
};
|
||||
|
||||
struct NoexceptView : std::ranges::view_base {
|
||||
NoexceptView() noexcept;
|
||||
int const* begin() const;
|
||||
int const* end() const;
|
||||
};
|
||||
|
||||
struct NoexceptPredicate {
|
||||
NoexceptPredicate() noexcept;
|
||||
bool operator()(int, int) const;
|
||||
};
|
||||
|
||||
struct MayThrowView : std::ranges::view_base {
|
||||
MayThrowView() noexcept(false);
|
||||
int const* begin() const;
|
||||
int const* end() const;
|
||||
};
|
||||
|
||||
struct MayThrowPredicate {
|
||||
MayThrowPredicate() noexcept(false);
|
||||
bool operator()(int, int) const;
|
||||
};
|
||||
|
||||
constexpr void compareRanges(std::ranges::subrange<const int*> v, std::initializer_list<int> list) {
|
||||
assert(v.size() == list.size());
|
||||
for (size_t i = 0; i < v.size(); ++i) {
|
||||
assert(v[i] == list.begin()[i]);
|
||||
}
|
||||
}
|
||||
|
||||
constexpr bool test() {
|
||||
// Check default constructor with default initialization
|
||||
{
|
||||
using View = std::ranges::chunk_by_view<DefaultConstructibleView, DefaultConstructiblePredicate>;
|
||||
View view;
|
||||
auto it = view.begin(), end = view.end();
|
||||
compareRanges(*it++, {-2, 1});
|
||||
compareRanges(*it++, {-1, 2});
|
||||
assert(it == end);
|
||||
}
|
||||
|
||||
// Check default construction with copy-list-initialization
|
||||
{
|
||||
using View = std::ranges::chunk_by_view<DefaultConstructibleView, DefaultConstructiblePredicate>;
|
||||
View view = {};
|
||||
auto it = view.begin(), end = view.end();
|
||||
compareRanges(*it++, {-2, 1});
|
||||
compareRanges(*it++, {-1, 2});
|
||||
assert(it == end);
|
||||
}
|
||||
|
||||
// Check cases where the default constructor isn't provided
|
||||
{
|
||||
static_assert(
|
||||
!std::is_default_constructible_v<std::ranges::chunk_by_view<NoDefaultView, DefaultConstructiblePredicate>>);
|
||||
static_assert(
|
||||
!std::is_default_constructible_v<std::ranges::chunk_by_view<DefaultConstructibleView, NoDefaultPredicate>>);
|
||||
static_assert(!std::is_default_constructible_v<std::ranges::chunk_by_view<NoDefaultView, NoDefaultPredicate>>);
|
||||
}
|
||||
|
||||
// Check noexcept-ness
|
||||
{
|
||||
{
|
||||
using View = std::ranges::chunk_by_view<MayThrowView, MayThrowPredicate>;
|
||||
static_assert(!noexcept(View()));
|
||||
}
|
||||
{
|
||||
using View = std::ranges::chunk_by_view<MayThrowView, NoexceptPredicate>;
|
||||
static_assert(!noexcept(View()));
|
||||
}
|
||||
{
|
||||
using View = std::ranges::chunk_by_view<NoexceptView, MayThrowPredicate>;
|
||||
static_assert(!noexcept(View()));
|
||||
}
|
||||
{
|
||||
using View = std::ranges::chunk_by_view<NoexceptView, NoexceptPredicate>;
|
||||
static_assert(noexcept(View()));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,109 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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, c++20
|
||||
|
||||
// <ranges>
|
||||
|
||||
// constexpr chunk_by_view(View, Pred);
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <utility>
|
||||
|
||||
#include "types.h"
|
||||
|
||||
struct Range : std::ranges::view_base {
|
||||
constexpr explicit Range(int* b, int* e) : begin_(b), end_(e) {}
|
||||
constexpr int* begin() const { return begin_; }
|
||||
constexpr int* end() const { return end_; }
|
||||
|
||||
private:
|
||||
int* begin_;
|
||||
int* end_;
|
||||
};
|
||||
|
||||
static_assert(std::ranges::view<Range>);
|
||||
static_assert(std::ranges::forward_range<Range>);
|
||||
|
||||
struct Pred {
|
||||
constexpr bool operator()(int x, int y) const { return x <= y; }
|
||||
};
|
||||
|
||||
struct TrackingPred : TrackInitialization {
|
||||
using TrackInitialization::TrackInitialization;
|
||||
constexpr bool operator()(int&, int&) const;
|
||||
};
|
||||
|
||||
struct TrackingRange : TrackInitialization, std::ranges::view_base {
|
||||
using TrackInitialization::TrackInitialization;
|
||||
int* begin() const;
|
||||
int* end() const;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
void implicitConstructionTest(T);
|
||||
|
||||
template <class T, class... Args>
|
||||
concept ImplicitConstructibleFrom =
|
||||
requires(Args&&... args) { implicitConstructionTest({std::forward<Args>(args)...}); };
|
||||
|
||||
constexpr bool test() {
|
||||
int buff[] = {1, 2, 3, 0, 1, 2, -1, -1, 0};
|
||||
|
||||
// Test explicit syntax
|
||||
{
|
||||
Range range(buff, buff + 9);
|
||||
Pred pred;
|
||||
std::ranges::chunk_by_view<Range, Pred> view(range, pred);
|
||||
auto it = view.begin(), end = view.end();
|
||||
assert(std::ranges::equal(*it++, std::array{1, 2, 3}));
|
||||
assert(std::ranges::equal(*it++, std::array{0, 1, 2}));
|
||||
assert(std::ranges::equal(*it++, std::array{-1, -1, 0}));
|
||||
assert(it == end);
|
||||
}
|
||||
|
||||
// Test implicit syntax
|
||||
{
|
||||
using ChunkByView = std::ranges::chunk_by_view<Range, Pred>;
|
||||
static_assert(!ImplicitConstructibleFrom<ChunkByView, Range, Pred>);
|
||||
static_assert(!ImplicitConstructibleFrom<ChunkByView, const Range&, const Pred&>);
|
||||
}
|
||||
|
||||
// Make sure we move the view
|
||||
{
|
||||
bool moved = false, copied = false;
|
||||
TrackingRange range(&moved, &copied);
|
||||
Pred pred;
|
||||
[[maybe_unused]] std::ranges::chunk_by_view<TrackingRange, Pred> view(std::move(range), pred);
|
||||
assert(moved);
|
||||
assert(!copied);
|
||||
}
|
||||
|
||||
// Make sure we move the predicate
|
||||
{
|
||||
bool moved = false, copied = false;
|
||||
Range range(buff, buff + 9);
|
||||
TrackingPred pred(&moved, &copied);
|
||||
[[maybe_unused]] std::ranges::chunk_by_view<Range, TrackingPred> view(range, std::move(pred));
|
||||
assert(moved);
|
||||
assert(!copied);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,121 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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, c++20
|
||||
|
||||
// <ranges>
|
||||
|
||||
// constexpr auto end();
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include <cassert>
|
||||
#include <concepts>
|
||||
#include <functional>
|
||||
|
||||
#include "test_iterators.h"
|
||||
|
||||
struct NonCommonRange : std::ranges::view_base {
|
||||
using Iterator = forward_iterator<int*>;
|
||||
using Sentinel = sentinel_wrapper<Iterator>;
|
||||
constexpr explicit NonCommonRange(int* b, int* e) : begin_(b), end_(e) {}
|
||||
constexpr Iterator begin() const { return Iterator(begin_); }
|
||||
constexpr Sentinel end() const { return Sentinel(Iterator(end_)); }
|
||||
|
||||
private:
|
||||
int* begin_;
|
||||
int* end_;
|
||||
};
|
||||
|
||||
static_assert(std::ranges::forward_range<NonCommonRange>);
|
||||
static_assert(!std::ranges::common_range<NonCommonRange>);
|
||||
|
||||
struct CommonRange : std::ranges::view_base {
|
||||
using Iterator = bidirectional_iterator<int*>;
|
||||
constexpr explicit CommonRange(int* b, int* e) : begin_(b), end_(e) {}
|
||||
constexpr Iterator begin() const { return Iterator(begin_); }
|
||||
constexpr Iterator end() const { return Iterator(end_); }
|
||||
|
||||
private:
|
||||
int* begin_;
|
||||
int* end_;
|
||||
};
|
||||
|
||||
static_assert(std::ranges::bidirectional_range<CommonRange>);
|
||||
static_assert(std::ranges::common_range<CommonRange>);
|
||||
|
||||
constexpr bool test() {
|
||||
int buff[] = {1, 0, 3, 1, 2, 3, 4, 5};
|
||||
|
||||
// Check the return type of `end()`
|
||||
{
|
||||
CommonRange range(buff, buff + 1);
|
||||
auto pred = [](int, int) { return true; };
|
||||
std::ranges::chunk_by_view view(range, pred);
|
||||
using ChunkByView = decltype(view);
|
||||
static_assert(std::ranges::common_range<ChunkByView>);
|
||||
ASSERT_SAME_TYPE(std::ranges::sentinel_t<ChunkByView>, decltype(view.end()));
|
||||
}
|
||||
|
||||
// end() on an empty range
|
||||
{
|
||||
CommonRange range(buff, buff);
|
||||
auto pred = [](int x, int y) { return x <= y; };
|
||||
std::ranges::chunk_by_view view(range, pred);
|
||||
auto end = view.end();
|
||||
assert(end == std::default_sentinel);
|
||||
}
|
||||
|
||||
// end() on a 1-element range
|
||||
{
|
||||
CommonRange range(buff, buff + 1);
|
||||
auto pred = [](int& x, int& y) { return x <= y; };
|
||||
std::ranges::chunk_by_view view(range, pred);
|
||||
auto end = view.end();
|
||||
assert(base((*--end).begin()) == buff);
|
||||
assert(base((*end).end()) == buff + 1);
|
||||
}
|
||||
|
||||
// end() on a 2-element range
|
||||
{
|
||||
CommonRange range(buff, buff + 2);
|
||||
auto pred = [](int const& x, int const& y) { return x <= y; };
|
||||
std::ranges::chunk_by_view view(range, pred);
|
||||
auto end = view.end();
|
||||
assert(base((*--end).begin()) == buff + 1);
|
||||
assert(base((*--end).end()) == buff + 1);
|
||||
}
|
||||
|
||||
// end() on a 8-element range
|
||||
{
|
||||
CommonRange range(buff, buff + 8);
|
||||
auto pred = [](const int x, const int y) { return x < y; };
|
||||
std::ranges::chunk_by_view view(range, pred);
|
||||
auto end = view.end();
|
||||
assert(base((*--end).end()) == buff + 8);
|
||||
assert(base((*--end).end()) == buff + 3);
|
||||
}
|
||||
|
||||
// end() on a non-common range
|
||||
{
|
||||
NonCommonRange range(buff, buff + 1);
|
||||
std::ranges::chunk_by_view view(range, std::ranges::less_equal{});
|
||||
auto end = view.end();
|
||||
ASSERT_SAME_TYPE(std::default_sentinel_t, std::ranges::sentinel_t<decltype(view)>);
|
||||
ASSERT_SAME_TYPE(std::default_sentinel_t, decltype(end));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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, c++20
|
||||
|
||||
// <ranges>
|
||||
|
||||
// constexpr Pred const& pred() const;
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include <cassert>
|
||||
#include <concepts>
|
||||
|
||||
struct Range : std::ranges::view_base {
|
||||
int* begin() const;
|
||||
int* end() const;
|
||||
};
|
||||
|
||||
struct Pred {
|
||||
bool operator()(int, int) const;
|
||||
int value;
|
||||
};
|
||||
|
||||
constexpr bool test() {
|
||||
{
|
||||
Pred pred{42};
|
||||
std::ranges::chunk_by_view<Range, Pred> const view(Range{}, pred);
|
||||
std::same_as<Pred const&> decltype(auto) result = view.pred();
|
||||
assert(result.value == 42);
|
||||
|
||||
// Make sure we're really holding a reference to something inside the view
|
||||
assert(&result == &view.pred());
|
||||
}
|
||||
|
||||
// Same, but calling on a non-const view
|
||||
{
|
||||
Pred pred{42};
|
||||
std::ranges::chunk_by_view<Range, Pred> view(Range{}, pred);
|
||||
std::same_as<Pred const&> decltype(auto) result = view.pred();
|
||||
assert(result.value == 42);
|
||||
|
||||
// Make sure we're really holding a reference to something inside the view
|
||||
assert(&result == &view.pred());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,113 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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, c++20
|
||||
|
||||
// <ranges>
|
||||
|
||||
// friend constexpr bool operator==(const iterator& x, const iterator& y);
|
||||
// friend constexpr bool operator==(const iterator& x, default_sentinel_t);
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <concepts>
|
||||
#include <functional>
|
||||
#include <utility>
|
||||
|
||||
#include "../types.h"
|
||||
#include "test_iterators.h"
|
||||
#include "test_macros.h"
|
||||
|
||||
template <class Iterator, class Sentinel = sentinel_wrapper<Iterator>>
|
||||
constexpr void test() {
|
||||
using Underlying = View<Iterator, Sentinel>;
|
||||
using ChunkByView = std::ranges::chunk_by_view<Underlying, std::ranges::less_equal>;
|
||||
using ChunkByIterator = std::ranges::iterator_t<ChunkByView>;
|
||||
|
||||
auto make_chunk_by_view = [](auto begin, auto end) {
|
||||
View view{Iterator(begin), Sentinel(Iterator(end))};
|
||||
return ChunkByView(std::move(view), std::ranges::less_equal{});
|
||||
};
|
||||
|
||||
// Test operator==
|
||||
{
|
||||
std::array array{0, 1, 2};
|
||||
ChunkByView view = make_chunk_by_view(array.begin(), array.end());
|
||||
ChunkByIterator i = view.begin();
|
||||
ChunkByIterator j = view.begin();
|
||||
|
||||
std::same_as<bool> decltype(auto) result = (i == j);
|
||||
assert(result);
|
||||
++i;
|
||||
assert(!(i == j));
|
||||
}
|
||||
|
||||
// Test synthesized operator!=
|
||||
{
|
||||
std::array array{0, 1, 2};
|
||||
ChunkByView view = make_chunk_by_view(array.begin(), array.end());
|
||||
ChunkByIterator i = view.begin();
|
||||
ChunkByIterator j = view.begin();
|
||||
|
||||
std::same_as<bool> decltype(auto) result = (i != j);
|
||||
assert(!result);
|
||||
++i;
|
||||
assert(i != j);
|
||||
}
|
||||
|
||||
// Test operator== with std::default_sentinel_t
|
||||
{
|
||||
std::array array{0, 1, 2};
|
||||
ChunkByView view = make_chunk_by_view(array.begin(), array.end());
|
||||
ChunkByIterator i = view.begin();
|
||||
|
||||
std::same_as<bool> decltype(auto) result = (i == std::default_sentinel);
|
||||
assert(!result);
|
||||
++i;
|
||||
assert(i == std::default_sentinel);
|
||||
}
|
||||
|
||||
// Test synthesized operator!= with std::default_sentinel_t
|
||||
{
|
||||
std::array array{0, 1, 2};
|
||||
ChunkByView view = make_chunk_by_view(array.begin(), array.end());
|
||||
ChunkByIterator i = view.begin();
|
||||
|
||||
std::same_as<bool> decltype(auto) result = (i != std::default_sentinel);
|
||||
assert(result);
|
||||
++i;
|
||||
assert(!(i != std::default_sentinel));
|
||||
}
|
||||
}
|
||||
|
||||
struct TestWithPair {
|
||||
template <class Iterator>
|
||||
constexpr void operator()() const {
|
||||
// Test with pair of iterators
|
||||
test<Iterator, Iterator>();
|
||||
|
||||
// Test with iterator-sentinel pair
|
||||
test<Iterator>();
|
||||
}
|
||||
};
|
||||
|
||||
constexpr bool tests() {
|
||||
TestWithPair tester;
|
||||
types::for_each(types::forward_iterator_list<int*>{}, tester);
|
||||
types::for_each(types::forward_iterator_list<int const*>{}, tester);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
tests();
|
||||
static_assert(tests());
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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, c++20
|
||||
|
||||
// <ranges>
|
||||
|
||||
// std::ranges::chunk_by_view<V>::<iterator>() = default;
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include <cassert>
|
||||
#include <functional>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "../types.h"
|
||||
#include "test_iterators.h"
|
||||
|
||||
template <class Iterator, bool IsNoexcept>
|
||||
constexpr void testDefaultConstructible() {
|
||||
// Make sure the iterator is default constructible.
|
||||
using ChunkByView = std::ranges::chunk_by_view<View<Iterator>, std::ranges::less_equal>;
|
||||
using ChunkByIterator = std::ranges::iterator_t<ChunkByView>;
|
||||
ChunkByIterator i{};
|
||||
ChunkByIterator j;
|
||||
assert(i == j);
|
||||
static_assert(noexcept(ChunkByIterator{}) == IsNoexcept);
|
||||
}
|
||||
|
||||
constexpr bool tests() {
|
||||
testDefaultConstructible<forward_iterator<int*>, /*IsNoexcept=*/false>();
|
||||
testDefaultConstructible<bidirectional_iterator<int*>, /*IsNoexcept=*/false>();
|
||||
testDefaultConstructible<random_access_iterator<int*>, /*IsNoexcept=*/false>();
|
||||
testDefaultConstructible<contiguous_iterator<int*>, /*IsNoexcept=*/false>();
|
||||
testDefaultConstructible<int*, /*IsNoexcept=*/true>();
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
tests();
|
||||
static_assert(tests());
|
||||
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,221 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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, c++20
|
||||
|
||||
// <ranges>
|
||||
|
||||
// constexpr iterator& operator--();
|
||||
// constexpr iterator operator--(int);
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <concepts>
|
||||
#include <functional>
|
||||
#include <span>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "../types.h"
|
||||
#include "test_iterators.h"
|
||||
#include "test_macros.h"
|
||||
|
||||
template <class T>
|
||||
concept HasPreDecrement = requires(T t) {
|
||||
{ --t };
|
||||
};
|
||||
|
||||
template <class T>
|
||||
concept HasPostDecrement = requires(T t) {
|
||||
{ t-- };
|
||||
};
|
||||
|
||||
struct TrackingPred : TrackInitialization {
|
||||
using TrackInitialization::TrackInitialization;
|
||||
constexpr bool operator()(int x, int y) const { return x <= y; }
|
||||
};
|
||||
|
||||
template <class Iterator, IsConst Constant, class Sentinel = sentinel_wrapper<Iterator>>
|
||||
constexpr void test() {
|
||||
using Underlying = View<Iterator, Sentinel>;
|
||||
using ChunkByView = std::ranges::chunk_by_view<Underlying, std::ranges::less_equal>;
|
||||
using ChunkByIterator = std::ranges::iterator_t<ChunkByView>;
|
||||
|
||||
static_assert(HasPostDecrement<ChunkByIterator>);
|
||||
static_assert(HasPreDecrement<ChunkByIterator>);
|
||||
|
||||
auto make_chunk_by_view = [](auto begin, auto end) {
|
||||
View view{Iterator{begin}, Sentinel{Iterator{end}}};
|
||||
return ChunkByView{std::move(view), std::ranges::less_equal{}};
|
||||
};
|
||||
|
||||
// Test with a single chunk
|
||||
{
|
||||
std::array array{0, 1, 2, 3, 4};
|
||||
ChunkByView view = make_chunk_by_view(array.begin(), array.end());
|
||||
ChunkByIterator it = std::ranges::next(view.begin(), view.end());
|
||||
|
||||
std::same_as<ChunkByIterator&> decltype(auto) result = --it;
|
||||
assert(&result == &it);
|
||||
assert(base((*result).begin()) == array.begin());
|
||||
}
|
||||
|
||||
// Test with two chunks
|
||||
{
|
||||
std::array array{0, 1, 2, 0, 1, 2};
|
||||
ChunkByView view = make_chunk_by_view(array.begin(), array.end());
|
||||
ChunkByIterator it = std::ranges::next(view.begin(), view.end());
|
||||
|
||||
std::same_as<ChunkByIterator&> decltype(auto) result = --it;
|
||||
assert(&result == &it);
|
||||
assert(base((*result).begin()) == array.begin() + 3);
|
||||
|
||||
--it;
|
||||
assert(base((*result).begin()) == array.begin());
|
||||
}
|
||||
|
||||
// Test going forward and then backward on the same iterator
|
||||
{
|
||||
std::array array{7, 8, 9, 4, 5, 6, 1, 2, 3, 0};
|
||||
ChunkByView view = make_chunk_by_view(array.begin(), array.end());
|
||||
ChunkByIterator it = view.begin();
|
||||
|
||||
++it;
|
||||
--it;
|
||||
assert(base((*it).begin()) == array.begin());
|
||||
assert(base((*it).end()) == array.begin() + 3);
|
||||
|
||||
++it;
|
||||
++it;
|
||||
--it;
|
||||
assert(base((*it).begin()) == array.begin() + 3);
|
||||
assert(base((*it).end()) == array.begin() + 6);
|
||||
|
||||
++it;
|
||||
++it;
|
||||
--it;
|
||||
assert(base((*it).begin()) == array.begin() + 6);
|
||||
assert(base((*it).end()) == array.begin() + 9);
|
||||
|
||||
++it;
|
||||
++it;
|
||||
--it;
|
||||
assert(base((*it).begin()) == array.begin() + 9);
|
||||
}
|
||||
|
||||
// Decrement an iterator multiple times
|
||||
if constexpr (std::ranges::common_range<Underlying>) {
|
||||
std::array array{1, 2, 1, 2, 1};
|
||||
ChunkByView view = make_chunk_by_view(array.begin(), array.end());
|
||||
|
||||
ChunkByIterator it = view.end();
|
||||
--it;
|
||||
--it;
|
||||
--it;
|
||||
assert(base((*it).begin()) == array.begin());
|
||||
}
|
||||
|
||||
// Test with a predicate that takes by non-const reference
|
||||
if constexpr (!std::to_underlying(Constant)) {
|
||||
std::array array{1, 2, 3, -3, -2, -1};
|
||||
View v{Iterator{array.begin()}, Sentinel{Iterator{array.end()}}};
|
||||
auto view = std::views::chunk_by(std::move(v), [](int& x, int& y) { return x <= y; });
|
||||
|
||||
auto it = std::ranges::next(view.begin());
|
||||
assert(base((*it).begin()) == array.begin() + 3);
|
||||
--it;
|
||||
assert(base((*it).begin()) == array.begin());
|
||||
}
|
||||
|
||||
// Test with a predicate that is invocable but not callable (i.e. cannot be called like regular function 'f()')
|
||||
{
|
||||
std::array array = {1, 2, 3, -3, -2, -1};
|
||||
auto v = View{Iterator{array.begin()}, Sentinel{Iterator{array.end()}}}
|
||||
| std::views::transform([](int x) { return IntWrapper{x}; });
|
||||
auto view = std::views::chunk_by(std::move(v), &IntWrapper::lessEqual);
|
||||
|
||||
auto it = std::ranges::next(view.begin());
|
||||
assert(base((*it).begin().base()) == array.begin() + 3);
|
||||
--it;
|
||||
assert(base((*it).begin().base()) == array.begin());
|
||||
}
|
||||
|
||||
// Make sure we do not make a copy of the predicate when we decrement
|
||||
if constexpr (std::ranges::common_range<Underlying>) {
|
||||
bool moved = false, copied = false;
|
||||
std::array array{1, 2, 1, 3};
|
||||
View v{Iterator(array.begin()), Sentinel(Iterator(array.end()))};
|
||||
auto view = std::views::chunk_by(std::move(v), TrackingPred(&moved, &copied));
|
||||
assert(std::exchange(moved, false));
|
||||
auto it = view.end();
|
||||
--it;
|
||||
it--;
|
||||
assert(!moved);
|
||||
assert(!copied);
|
||||
}
|
||||
|
||||
// Check post-decrement
|
||||
{
|
||||
std::array array{0, 1, 2, -3, -2, -1, -6, -5, -4};
|
||||
ChunkByView view = make_chunk_by_view(array.begin(), array.end());
|
||||
ChunkByIterator it = std::ranges::next(view.begin(), view.end());
|
||||
|
||||
std::same_as<ChunkByIterator> decltype(auto) result = it--;
|
||||
assert(result != it);
|
||||
assert(result == std::default_sentinel);
|
||||
assert(base((*it).begin()) == array.begin() + 6);
|
||||
|
||||
result = it--;
|
||||
assert(base((*it).begin()) == array.begin() + 3);
|
||||
assert(base((*result).begin()) == array.begin() + 6);
|
||||
|
||||
result = it--;
|
||||
assert(base((*it).begin()) == array.begin());
|
||||
assert(base((*result).begin()) == array.begin() + 3);
|
||||
}
|
||||
}
|
||||
|
||||
template <class Iterator, IsConst Constant>
|
||||
constexpr void test_with_pair() {
|
||||
// Test with pair of iterators
|
||||
test<Iterator, Constant>();
|
||||
|
||||
// Test with iterator-sentinel pair
|
||||
test<Iterator, Constant, Iterator>();
|
||||
}
|
||||
|
||||
constexpr bool tests() {
|
||||
test_with_pair<bidirectional_iterator<int*>, IsConst::no>();
|
||||
test_with_pair<random_access_iterator<int*>, IsConst::no>();
|
||||
test_with_pair<contiguous_iterator<int*>, IsConst::no>();
|
||||
test_with_pair<int*, IsConst::no>();
|
||||
|
||||
test_with_pair<bidirectional_iterator<int const*>, IsConst::yes>();
|
||||
test_with_pair<random_access_iterator<int const*>, IsConst::yes>();
|
||||
test_with_pair<contiguous_iterator<int const*>, IsConst::yes>();
|
||||
test_with_pair<int const*, IsConst::yes>();
|
||||
|
||||
// Make sure `operator--` isn't provided for non bidirectional ranges
|
||||
{
|
||||
using ForwardView = View<forward_iterator<int*>, sentinel_wrapper<forward_iterator<int*>>>;
|
||||
using ChunkByView = std::ranges::chunk_by_view<ForwardView, std::ranges::less_equal>;
|
||||
static_assert(!HasPreDecrement<std::ranges::iterator_t<ChunkByView>>);
|
||||
static_assert(!HasPostDecrement<std::ranges::iterator_t<ChunkByView>>);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
tests();
|
||||
static_assert(tests());
|
||||
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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, c++20
|
||||
|
||||
// <ranges>
|
||||
|
||||
// constexpr value_type operator*() const;
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <concepts>
|
||||
#include <functional>
|
||||
#include <utility>
|
||||
|
||||
#include "../types.h"
|
||||
#include "test_iterators.h"
|
||||
#include "test_macros.h"
|
||||
|
||||
template <class Iter, class Sent = sentinel_wrapper<Iter>>
|
||||
constexpr void test() {
|
||||
using Underlying = View<Iter, Sent>;
|
||||
using ChunkByView = std::ranges::chunk_by_view<Underlying, std::ranges::less_equal>;
|
||||
using ChunkByIterator = std::ranges::iterator_t<ChunkByView>;
|
||||
|
||||
std::array array{0, 1, 2, 3, -1, 0, 1, 2, -2, 3, 4, 5};
|
||||
std::array expected{std::array{0, 1, 2, 3}, std::array{-1, 0, 1, 2}, std::array{-2, 3, 4, 5}};
|
||||
Underlying underlying{Iter{array.begin()}, Sent{Iter{array.end()}}};
|
||||
ChunkByView view{underlying, std::ranges::less_equal{}};
|
||||
|
||||
size_t idx = 0;
|
||||
for (std::same_as<ChunkByIterator> auto iter = view.begin(); iter != view.end(); ++idx, ++iter) {
|
||||
std::same_as<typename ChunkByIterator::value_type> auto chunk = *iter;
|
||||
assert(std::ranges::equal(chunk, expected[idx]));
|
||||
}
|
||||
}
|
||||
|
||||
constexpr bool tests() {
|
||||
// Check iterator-sentinel pair
|
||||
test<forward_iterator<int*>>();
|
||||
test<bidirectional_iterator<int*>>();
|
||||
test<random_access_iterator<int*>>();
|
||||
test<contiguous_iterator<int*>>();
|
||||
test<int*>();
|
||||
|
||||
// Check iterator pair
|
||||
test<forward_iterator<int*>, forward_iterator<int*>>();
|
||||
test<bidirectional_iterator<int*>, bidirectional_iterator<int*>>();
|
||||
test<random_access_iterator<int*>, random_access_iterator<int*>>();
|
||||
test<contiguous_iterator<int*>, contiguous_iterator<int*>>();
|
||||
test<int*, int*>();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
tests();
|
||||
static_assert(tests());
|
||||
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,179 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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, c++20
|
||||
|
||||
// <ranges>
|
||||
|
||||
// constexpr iterator& operator++();
|
||||
// constexpr iterator operator++(int);
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <concepts>
|
||||
#include <functional>
|
||||
#include <span>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "../types.h"
|
||||
#include "test_iterators.h"
|
||||
#include "test_macros.h"
|
||||
|
||||
struct TrackingPred : TrackInitialization {
|
||||
using TrackInitialization::TrackInitialization;
|
||||
constexpr bool operator()(int x, int y) const { return x <= y; }
|
||||
};
|
||||
|
||||
template <class Iterator, IsConst Constant>
|
||||
constexpr void test() {
|
||||
using Sentinel = sentinel_wrapper<Iterator>;
|
||||
using Underlying = View<Iterator, Sentinel>;
|
||||
using ChunkByView = std::ranges::chunk_by_view<Underlying, std::ranges::less_equal>;
|
||||
using ChunkByIterator = std::ranges::iterator_t<ChunkByView>;
|
||||
|
||||
auto make_chunk_by_view = [](auto begin, auto end) {
|
||||
View view{Iterator{begin}, Sentinel{Iterator{end}}};
|
||||
return ChunkByView{std::move(view), std::ranges::less_equal{}};
|
||||
};
|
||||
|
||||
// Increment the iterator when it won't find another satisfied value after begin()
|
||||
{
|
||||
std::array array{0, 1, 2, 3, 4};
|
||||
ChunkByView view = make_chunk_by_view(array.begin(), array.end());
|
||||
ChunkByIterator it = view.begin();
|
||||
|
||||
std::same_as<ChunkByIterator&> decltype(auto) result = ++it;
|
||||
assert(&result == &it);
|
||||
assert(result == view.end());
|
||||
assert(result == std::default_sentinel);
|
||||
}
|
||||
|
||||
// Increment the iterator and it finds another value after begin()
|
||||
{
|
||||
std::array array{1, 2, 3, -1, -2, -3};
|
||||
int const* second_chunk = array.begin() + 3;
|
||||
ChunkByView view = make_chunk_by_view(array.begin(), array.end());
|
||||
|
||||
ChunkByIterator it = view.begin();
|
||||
++it;
|
||||
assert(base((*it).begin()) == second_chunk);
|
||||
}
|
||||
|
||||
// Increment advances all the way to the end of the range
|
||||
{
|
||||
std::array array{1, 2, 3, 4, 1};
|
||||
ChunkByView view = make_chunk_by_view(array.begin(), array.end());
|
||||
|
||||
ChunkByIterator it = view.begin();
|
||||
++it;
|
||||
assert(base((*it).begin()) == array.begin() + 4);
|
||||
}
|
||||
|
||||
// Increment an iterator multiple times
|
||||
{
|
||||
std::array array{0, 1, 0, 2, 0, 3, 0, 4};
|
||||
ChunkByView view = make_chunk_by_view(array.begin(), array.end());
|
||||
|
||||
ChunkByIterator it = view.begin();
|
||||
assert(base((*it).begin()) == array.begin());
|
||||
++it;
|
||||
assert(base((*it).begin()) == array.begin() + 2);
|
||||
++it;
|
||||
assert(base((*it).begin()) == array.begin() + 4);
|
||||
++it;
|
||||
assert(base((*it).begin()) == array.begin() + 6);
|
||||
++it;
|
||||
assert(it == std::default_sentinel);
|
||||
}
|
||||
|
||||
// Test with a predicate that takes by non-const reference
|
||||
if constexpr (!std::to_underlying(Constant)) {
|
||||
std::array array{1, 2, 3, -3, -2, -1};
|
||||
View v{Iterator{array.begin()}, Sentinel{Iterator{array.end()}}};
|
||||
auto view = std::views::chunk_by(std::move(v), [](int& x, int& y) { return x <= y; });
|
||||
|
||||
auto it = view.begin();
|
||||
assert(base((*it).begin()) == array.begin());
|
||||
++it;
|
||||
assert(base((*it).begin()) == array.begin() + 3);
|
||||
}
|
||||
|
||||
// Test with a predicate that is invocable but not callable (i.e. cannot be called like regular function 'f()')
|
||||
{
|
||||
std::array array = {1, 2, 3, -3, -2, -1};
|
||||
auto v = View{Iterator{array.begin()}, Sentinel{Iterator{array.end()}}}
|
||||
| std::views::transform([](int x) { return IntWrapper{x}; });
|
||||
auto view = std::views::chunk_by(std::move(v), &IntWrapper::lessEqual);
|
||||
|
||||
auto it = view.begin();
|
||||
assert(base((*it).begin().base()) == array.begin());
|
||||
++it;
|
||||
assert(base((*it).begin().base()) == array.begin() + 3);
|
||||
}
|
||||
|
||||
// Make sure we do not make a copy of the predicate when we increment
|
||||
// (we should be passing it to ranges::adjacent_find using std::ref)
|
||||
{
|
||||
bool moved = false, copied = false;
|
||||
std::array array{1, 2, 1, 3};
|
||||
View v{Iterator(array.begin()), Sentinel(Iterator(array.end()))};
|
||||
auto view = std::views::chunk_by(std::move(v), TrackingPred(&moved, &copied));
|
||||
assert(std::exchange(moved, false));
|
||||
auto it = view.begin();
|
||||
++it;
|
||||
it++;
|
||||
assert(!moved);
|
||||
assert(!copied);
|
||||
}
|
||||
|
||||
// Check post-increment
|
||||
{
|
||||
std::array array{0, 1, 2, -3, -2, -1, -6, -5, -4};
|
||||
ChunkByView view = make_chunk_by_view(array.begin(), array.end());
|
||||
ChunkByIterator it = view.begin();
|
||||
|
||||
std::same_as<ChunkByIterator> decltype(auto) result = it++;
|
||||
assert(result != it);
|
||||
assert(base((*result).begin()) == array.begin());
|
||||
assert(base((*it).begin()) == array.begin() + 3);
|
||||
|
||||
result = it++;
|
||||
assert(base((*result).begin()) == array.begin() + 3);
|
||||
assert(base((*it).begin()) == array.begin() + 6);
|
||||
|
||||
result = it++;
|
||||
assert(base((*result).begin()) == array.begin() + 6);
|
||||
assert(it == std::default_sentinel);
|
||||
}
|
||||
}
|
||||
|
||||
constexpr bool tests() {
|
||||
test<forward_iterator<int*>, IsConst::no>();
|
||||
test<bidirectional_iterator<int*>, IsConst::no>();
|
||||
test<random_access_iterator<int*>, IsConst::no>();
|
||||
test<contiguous_iterator<int*>, IsConst::no>();
|
||||
test<int*, IsConst::no>();
|
||||
|
||||
test<forward_iterator<int const*>, IsConst::yes>();
|
||||
test<bidirectional_iterator<int const*>, IsConst::yes>();
|
||||
test<random_access_iterator<int const*>, IsConst::yes>();
|
||||
test<contiguous_iterator<int const*>, IsConst::yes>();
|
||||
test<int const*, IsConst::yes>();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
tests();
|
||||
static_assert(tests());
|
||||
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,71 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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, c++20
|
||||
|
||||
// <ranges>
|
||||
|
||||
// std::ranges::chunk_by_view::<iterator>::value_type
|
||||
// std::ranges::chunk_by_view::<iterator>::difference_type
|
||||
// std::ranges::chunk_by_view::<iterator>::iterator_category
|
||||
// std::ranges::chunk_by_view::<iterator>::iterator_concept
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include <functional>
|
||||
#include <type_traits>
|
||||
|
||||
#include "../types.h"
|
||||
#include "test_iterators.h"
|
||||
|
||||
struct TestValueTypeAndDifferenceType {
|
||||
template <class Iter>
|
||||
constexpr void operator()() const {
|
||||
using Underlying = View<Iter>;
|
||||
using ChunkByView = std::ranges::chunk_by_view<Underlying, std::ranges::less_equal>;
|
||||
using ChunkByIterator = std::ranges::iterator_t<ChunkByView>;
|
||||
static_assert(std::same_as<typename ChunkByIterator::value_type, std::ranges::range_value_t<ChunkByView>>);
|
||||
static_assert(std::same_as<typename ChunkByIterator::value_type, std::ranges::subrange<Iter>>);
|
||||
static_assert(
|
||||
std::same_as<typename ChunkByIterator::difference_type, std::ranges::range_difference_t<ChunkByView>>);
|
||||
static_assert(std::same_as<typename ChunkByIterator::difference_type, std::ranges::range_difference_t<Underlying>>);
|
||||
}
|
||||
};
|
||||
|
||||
template <class Iter>
|
||||
using ChunkByIteratorFor = std::ranges::iterator_t<std::ranges::chunk_by_view<View<Iter>, std::ranges::less_equal>>;
|
||||
|
||||
constexpr void test() {
|
||||
// Check that value_type is range_value_t and difference_type is range_difference_t
|
||||
types::for_each(types::forward_iterator_list<int*>{}, TestValueTypeAndDifferenceType{});
|
||||
|
||||
// Check iterator_concept for various categories of ranges
|
||||
{
|
||||
static_assert(
|
||||
std::same_as<ChunkByIteratorFor<forward_iterator<int*>>::iterator_concept, std::forward_iterator_tag>);
|
||||
static_assert(std::same_as<ChunkByIteratorFor<bidirectional_iterator<int*>>::iterator_concept,
|
||||
std::bidirectional_iterator_tag>);
|
||||
static_assert(std::same_as<ChunkByIteratorFor<random_access_iterator<int*>>::iterator_concept,
|
||||
std::bidirectional_iterator_tag>);
|
||||
static_assert(
|
||||
std::same_as<ChunkByIteratorFor<contiguous_iterator<int*>>::iterator_concept, std::bidirectional_iterator_tag>);
|
||||
static_assert(std::same_as<ChunkByIteratorFor<int*>::iterator_concept, std::bidirectional_iterator_tag>);
|
||||
}
|
||||
|
||||
// Check iterator_category for various categories of ranges
|
||||
{
|
||||
static_assert(std::same_as<ChunkByIteratorFor<forward_iterator<int*>>::iterator_category, std::input_iterator_tag>);
|
||||
static_assert(
|
||||
std::same_as<ChunkByIteratorFor<bidirectional_iterator<int*>>::iterator_category, std::input_iterator_tag>);
|
||||
static_assert(
|
||||
std::same_as<ChunkByIteratorFor<random_access_iterator<int*>>::iterator_category, std::input_iterator_tag>);
|
||||
static_assert(
|
||||
std::same_as<ChunkByIteratorFor<contiguous_iterator<int*>>::iterator_category, std::input_iterator_tag>);
|
||||
static_assert(std::same_as<ChunkByIteratorFor<int*>::iterator_category, std::input_iterator_tag>);
|
||||
}
|
||||
}
|
54
libcxx/test/std/ranges/range.adaptors/range.chunk.by/types.h
Normal file
54
libcxx/test/std/ranges/range.adaptors/range.chunk.by/types.h
Normal file
@ -0,0 +1,54 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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 TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_CHUNK_BY_TYPES_H
|
||||
#define TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_CHUNK_BY_TYPES_H
|
||||
|
||||
#include <ranges>
|
||||
#include <utility>
|
||||
|
||||
#include "test_iterators.h"
|
||||
|
||||
struct TrackInitialization {
|
||||
constexpr explicit TrackInitialization(bool* moved, bool* copied) : moved_(moved), copied_(copied) {}
|
||||
constexpr TrackInitialization(TrackInitialization const& other) : moved_(other.moved_), copied_(other.copied_) {
|
||||
*copied_ = true;
|
||||
}
|
||||
constexpr TrackInitialization(TrackInitialization&& other) : moved_(other.moved_), copied_(other.copied_) {
|
||||
*moved_ = true;
|
||||
}
|
||||
TrackInitialization& operator=(TrackInitialization const&) = default;
|
||||
TrackInitialization& operator=(TrackInitialization&&) = default;
|
||||
bool* moved_;
|
||||
bool* copied_;
|
||||
};
|
||||
|
||||
enum class IsConst : bool { no, yes };
|
||||
|
||||
template <std::forward_iterator Iter, std::sentinel_for<Iter> Sent = sentinel_wrapper<Iter>>
|
||||
struct View : std::ranges::view_base {
|
||||
constexpr explicit View(Iter b, Sent e) : begin_(b), end_(e) {}
|
||||
constexpr Iter begin() { return begin_; }
|
||||
constexpr Sent end() { return end_; }
|
||||
|
||||
private:
|
||||
Iter begin_;
|
||||
Sent end_;
|
||||
};
|
||||
|
||||
template <class I, class S>
|
||||
View(I b, S e) -> View<I, S>;
|
||||
|
||||
struct IntWrapper {
|
||||
constexpr IntWrapper(int v) : value_(v) {}
|
||||
|
||||
int value_;
|
||||
constexpr bool lessEqual(IntWrapper other) const { return value_ <= other.value_; }
|
||||
};
|
||||
|
||||
#endif // TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_CHUNK_BY_TYPES_H
|
@ -801,7 +801,6 @@ feature_test_macros = [
|
||||
"name": "__cpp_lib_ranges_chunk_by",
|
||||
"values": {"c++23": 202202},
|
||||
"headers": ["ranges"],
|
||||
"unimplemented": True,
|
||||
},
|
||||
{
|
||||
"name": "__cpp_lib_ranges_iota",
|
||||
|
Loading…
x
Reference in New Issue
Block a user