forked from OSchip/llvm-project
[libc++][ranges] Implement `lazy_split_view`.
Note that this class was called just `split_view` in the original One Ranges Proposal and was renamed to `lazy_split_view` by [P2210](https://wg21.link/p2210). Co-authored-by: zoecarver <z.zoelec2@gmail.com> Differential Revision: https://reviews.llvm.org/D107500
This commit is contained in:
parent
0eb5891adc
commit
e53c461bf3
|
@ -155,7 +155,7 @@ Section,Description,Dependencies,Assignee,Complete
|
|||
`[range.transform] <https://wg21.link/range.transform>`_,`transform_view <https://llvm.org/D103056>`_,[range.all],Zoe Carver,✅
|
||||
`[range.take] <https://wg21.link/range.take>`_,`take_view <https://llvm.org/D106507>`_,[range.all],Zoe Carver,✅
|
||||
`[range.join] <https://wg21.link/range.join>`_,`join_view <https://llvm.org/D107671>`_,[range.all],Zoe Carver,✅
|
||||
`[range.split] <https://wg21.link/range.split>`_,`split_view (renamed to lazy_split_view by P2210) <https://llvm.org/D107500>`_,[range.all],Zoe Carver,In progress
|
||||
`[range.split] <https://wg21.link/range.split>`_,`split_view (renamed to lazy_split_view by P2210) <https://llvm.org/D107500>`_,[range.all],Zoe Carver and Konstantin Varlamov,✅
|
||||
`[range.counted] <https://wg21.link/range.counted>`_,`view::counted <https://llvm.org/D106923>`_,[range.subrange],Zoe Carver,✅
|
||||
`[range.common] <https://wg21.link/range.common>`_,`common_view <https://llvm.org/D105753>`_,[range.all],Zoe Carver,✅
|
||||
`[range.reverse] <https://wg21.link/range.reverse>`_,`reverse_view <https://llvm.org/D107096>`_,[range.all],Zoe Carver,✅
|
||||
|
|
|
|
@ -373,6 +373,7 @@ set(files
|
|||
__ranges/enable_view.h
|
||||
__ranges/iota_view.h
|
||||
__ranges/join_view.h
|
||||
__ranges/lazy_split_view.h
|
||||
__ranges/non_propagating_cache.h
|
||||
__ranges/owning_view.h
|
||||
__ranges/range_adaptor.h
|
||||
|
|
|
@ -0,0 +1,466 @@
|
|||
// -*- 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_LAZY_SPLIT_VIEW_H
|
||||
#define _LIBCPP___RANGES_LAZY_SPLIT_VIEW_H
|
||||
|
||||
#include <__algorithm/in_in_result.h>
|
||||
#include <__algorithm/ranges_find.h>
|
||||
#include <__algorithm/ranges_mismatch.h>
|
||||
#include <__concepts/constructible.h>
|
||||
#include <__concepts/convertible_to.h>
|
||||
#include <__concepts/derived_from.h>
|
||||
#include <__config>
|
||||
#include <__functional/bind_back.h>
|
||||
#include <__functional/ranges_operations.h>
|
||||
#include <__iterator/concepts.h>
|
||||
#include <__iterator/default_sentinel.h>
|
||||
#include <__iterator/incrementable_traits.h>
|
||||
#include <__iterator/indirectly_comparable.h>
|
||||
#include <__iterator/iter_move.h>
|
||||
#include <__iterator/iter_swap.h>
|
||||
#include <__iterator/iterator_traits.h>
|
||||
#include <__memory/addressof.h>
|
||||
#include <__ranges/access.h>
|
||||
#include <__ranges/all.h>
|
||||
#include <__ranges/concepts.h>
|
||||
#include <__ranges/non_propagating_cache.h>
|
||||
#include <__ranges/range_adaptor.h>
|
||||
#include <__ranges/single_view.h>
|
||||
#include <__ranges/subrange.h>
|
||||
#include <__ranges/view_interface.h>
|
||||
#include <__utility/forward.h>
|
||||
#include <__utility/move.h>
|
||||
#include <type_traits>
|
||||
|
||||
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
||||
# pragma GCC system_header
|
||||
#endif
|
||||
|
||||
_LIBCPP_BEGIN_NAMESPACE_STD
|
||||
|
||||
#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES)
|
||||
|
||||
namespace ranges {
|
||||
|
||||
template <auto> struct __require_constant;
|
||||
|
||||
template <class _Range>
|
||||
concept __tiny_range =
|
||||
sized_range<_Range> &&
|
||||
requires { typename __require_constant<remove_reference_t<_Range>::size()>; } &&
|
||||
(remove_reference_t<_Range>::size() <= 1);
|
||||
|
||||
template <input_range _View, forward_range _Pattern>
|
||||
requires view<_View> && view<_Pattern> &&
|
||||
indirectly_comparable<iterator_t<_View>, iterator_t<_Pattern>, ranges::equal_to> &&
|
||||
(forward_range<_View> || __tiny_range<_Pattern>)
|
||||
class lazy_split_view : public view_interface<lazy_split_view<_View, _Pattern>> {
|
||||
|
||||
_LIBCPP_NO_UNIQUE_ADDRESS _View __base_ = _View();
|
||||
_LIBCPP_NO_UNIQUE_ADDRESS _Pattern __pattern_ = _Pattern();
|
||||
|
||||
using _MaybeCurrent = _If<!forward_range<_View>, __non_propagating_cache<iterator_t<_View>>, __empty_cache>;
|
||||
_LIBCPP_NO_UNIQUE_ADDRESS _MaybeCurrent __current_ = _MaybeCurrent();
|
||||
|
||||
template <bool> struct __outer_iterator;
|
||||
template <bool> struct __inner_iterator;
|
||||
|
||||
public:
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
lazy_split_view()
|
||||
requires default_initializable<_View> && default_initializable<_Pattern> = default;
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
constexpr lazy_split_view(_View __base, _Pattern __pattern)
|
||||
: __base_(std::move(__base)), __pattern_(std::move(__pattern)) {}
|
||||
|
||||
template <input_range _Range>
|
||||
requires constructible_from<_View, views::all_t<_Range>> &&
|
||||
constructible_from<_Pattern, single_view<range_value_t<_Range>>>
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
constexpr lazy_split_view(_Range&& __r, range_value_t<_Range> __e)
|
||||
: __base_(views::all(std::forward<_Range>(__r)))
|
||||
// TODO(varconst): use `views::single` once it's implemented.
|
||||
, __pattern_(ranges::single_view(std::move(__e))) {}
|
||||
|
||||
_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 auto begin() {
|
||||
if constexpr (forward_range<_View>) {
|
||||
return __outer_iterator<__simple_view<_View> && __simple_view<_Pattern>>{*this, ranges::begin(__base_)};
|
||||
} else {
|
||||
__current_.__emplace(ranges::begin(__base_));
|
||||
return __outer_iterator<false>{*this};
|
||||
}
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
constexpr auto begin() const requires forward_range<_View> && forward_range<const _View> {
|
||||
return __outer_iterator<true>{*this, ranges::begin(__base_)};
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
constexpr auto end() requires forward_range<_View> && common_range<_View> {
|
||||
return __outer_iterator<__simple_view<_View> && __simple_view<_Pattern>>{*this, ranges::end(__base_)};
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
constexpr auto end() const {
|
||||
if constexpr (forward_range<_View> && forward_range<const _View> && common_range<const _View>) {
|
||||
return __outer_iterator<true>{*this, ranges::end(__base_)};
|
||||
} else {
|
||||
return default_sentinel;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
template <class>
|
||||
struct __outer_iterator_category {};
|
||||
|
||||
template <forward_range _Tp>
|
||||
struct __outer_iterator_category<_Tp> {
|
||||
using iterator_category = input_iterator_tag;
|
||||
};
|
||||
|
||||
template <bool _Const>
|
||||
struct __outer_iterator : __outer_iterator_category<__maybe_const<_Const, _View>> {
|
||||
private:
|
||||
template <bool>
|
||||
friend struct __inner_iterator;
|
||||
friend __outer_iterator<true>;
|
||||
|
||||
using _Parent = __maybe_const<_Const, lazy_split_view>;
|
||||
using _Base = __maybe_const<_Const, _View>;
|
||||
|
||||
_Parent* __parent_ = nullptr;
|
||||
using _MaybeCurrent = _If<forward_range<_View>, iterator_t<_Base>, __empty_cache>;
|
||||
_LIBCPP_NO_UNIQUE_ADDRESS _MaybeCurrent __current_ = _MaybeCurrent();
|
||||
bool __trailing_empty_ = false;
|
||||
|
||||
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI
|
||||
constexpr auto& __current() noexcept {
|
||||
if constexpr (forward_range<_View>) {
|
||||
return __current_;
|
||||
} else {
|
||||
return *__parent_->__current_;
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI
|
||||
constexpr const auto& __current() const noexcept {
|
||||
if constexpr (forward_range<_View>) {
|
||||
return __current_;
|
||||
} else {
|
||||
return *__parent_->__current_;
|
||||
}
|
||||
}
|
||||
|
||||
// Workaround for the GCC issue that doesn't allow calling `__parent_->__base_` from friend functions (because
|
||||
// `__base_` is private).
|
||||
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI
|
||||
constexpr auto& __parent_base() const noexcept {
|
||||
return __parent_->__base_;
|
||||
}
|
||||
|
||||
public:
|
||||
// using iterator_category = inherited;
|
||||
using iterator_concept = conditional_t<forward_range<_Base>, forward_iterator_tag, input_iterator_tag>;
|
||||
using difference_type = range_difference_t<_Base>;
|
||||
|
||||
struct value_type : view_interface<value_type> {
|
||||
private:
|
||||
__outer_iterator __i_ = __outer_iterator();
|
||||
|
||||
public:
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
value_type() = default;
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
constexpr explicit value_type(__outer_iterator __i)
|
||||
: __i_(std::move(__i)) {}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
constexpr __inner_iterator<_Const> begin() const { return __inner_iterator<_Const>{__i_}; }
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
constexpr default_sentinel_t end() const noexcept { return default_sentinel; }
|
||||
};
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
__outer_iterator() = default;
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
constexpr explicit __outer_iterator(_Parent& __parent)
|
||||
requires (!forward_range<_Base>)
|
||||
: __parent_(std::addressof(__parent)) {}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
constexpr __outer_iterator(_Parent& __parent, iterator_t<_Base> __current)
|
||||
requires forward_range<_Base>
|
||||
: __parent_(std::addressof(__parent)), __current_(std::move(__current)) {}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
constexpr __outer_iterator(__outer_iterator<!_Const> __i)
|
||||
requires _Const && convertible_to<iterator_t<_View>, iterator_t<_Base>>
|
||||
: __parent_(__i.__parent_), __current_(std::move(__i.__current_)) {}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
constexpr value_type operator*() const { return value_type{*this}; }
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
constexpr __outer_iterator& operator++() {
|
||||
const auto __end = ranges::end(__parent_->__base_);
|
||||
if (__current() == __end) {
|
||||
__trailing_empty_ = false;
|
||||
return *this;
|
||||
}
|
||||
|
||||
const auto [__pbegin, __pend] = ranges::subrange{__parent_->__pattern_};
|
||||
if (__pbegin == __pend) {
|
||||
// Empty pattern: split on every element in the input range
|
||||
++__current();
|
||||
|
||||
} else if constexpr (__tiny_range<_Pattern>) {
|
||||
// One-element pattern: we can use `ranges::find`.
|
||||
__current() = ranges::find(std::move(__current()), __end, *__pbegin);
|
||||
if (__current() != __end) {
|
||||
// Make sure we point to after the separator we just found.
|
||||
++__current();
|
||||
if (__current() == __end)
|
||||
__trailing_empty_ = true;
|
||||
}
|
||||
|
||||
} else {
|
||||
// General case for n-element pattern.
|
||||
do {
|
||||
const auto [__b, __p] = ranges::mismatch(__current(), __end, __pbegin, __pend);
|
||||
if (__p == __pend) {
|
||||
__current() = __b;
|
||||
if (__current() == __end) {
|
||||
__trailing_empty_ = true;
|
||||
}
|
||||
break; // The pattern matched; skip it.
|
||||
}
|
||||
} while (++__current() != __end);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
constexpr decltype(auto) operator++(int) {
|
||||
if constexpr (forward_range<_Base>) {
|
||||
auto __tmp = *this;
|
||||
++*this;
|
||||
return __tmp;
|
||||
|
||||
} else {
|
||||
++*this;
|
||||
}
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
friend constexpr bool operator==(const __outer_iterator& __x, const __outer_iterator& __y)
|
||||
requires forward_range<_Base> {
|
||||
return __x.__current_ == __y.__current_ && __x.__trailing_empty_ == __y.__trailing_empty_;
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
friend constexpr bool operator==(const __outer_iterator& __x, default_sentinel_t) {
|
||||
_LIBCPP_ASSERT(__x.__parent_, "Cannot call comparison on a default-constructed iterator.");
|
||||
return __x.__current() == ranges::end(__x.__parent_base()) && !__x.__trailing_empty_;
|
||||
}
|
||||
};
|
||||
|
||||
template <class>
|
||||
struct __inner_iterator_category {};
|
||||
|
||||
template <forward_range _Tp>
|
||||
struct __inner_iterator_category<_Tp> {
|
||||
using iterator_category = _If<
|
||||
derived_from<typename iterator_traits<iterator_t<_Tp>>::iterator_category, forward_iterator_tag>,
|
||||
forward_iterator_tag,
|
||||
typename iterator_traits<iterator_t<_Tp>>::iterator_category
|
||||
>;
|
||||
};
|
||||
|
||||
template <bool _Const>
|
||||
struct __inner_iterator : __inner_iterator_category<__maybe_const<_Const, _View>> {
|
||||
private:
|
||||
using _Base = __maybe_const<_Const, _View>;
|
||||
// Workaround for a GCC issue.
|
||||
static constexpr bool _OuterConst = _Const;
|
||||
__outer_iterator<_Const> __i_ = __outer_iterator<_OuterConst>();
|
||||
bool __incremented_ = false;
|
||||
|
||||
// Note: these private functions are necessary because GCC doesn't allow calls to private members of `__i_` from
|
||||
// free functions that are friends of `inner-iterator`.
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
constexpr bool __is_done() const {
|
||||
_LIBCPP_ASSERT(__i_.__parent_, "Cannot call comparison on a default-constructed iterator.");
|
||||
|
||||
auto [__pcur, __pend] = ranges::subrange{__i_.__parent_->__pattern_};
|
||||
auto __end = ranges::end(__i_.__parent_->__base_);
|
||||
|
||||
if constexpr (__tiny_range<_Pattern>) {
|
||||
const auto& __cur = __i_.__current();
|
||||
if (__cur == __end)
|
||||
return true;
|
||||
if (__pcur == __pend)
|
||||
return __incremented_;
|
||||
|
||||
return *__cur == *__pcur;
|
||||
|
||||
} else {
|
||||
auto __cur = __i_.__current();
|
||||
if (__cur == __end)
|
||||
return true;
|
||||
if (__pcur == __pend)
|
||||
return __incremented_;
|
||||
|
||||
do {
|
||||
if (*__cur != *__pcur)
|
||||
return false;
|
||||
if (++__pcur == __pend)
|
||||
return true;
|
||||
} while (++__cur != __end);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI
|
||||
constexpr auto& __outer_current() noexcept {
|
||||
return __i_.__current();
|
||||
}
|
||||
|
||||
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI
|
||||
constexpr const auto& __outer_current() const noexcept {
|
||||
return __i_.__current();
|
||||
}
|
||||
|
||||
public:
|
||||
// using iterator_category = inherited;
|
||||
using iterator_concept = typename __outer_iterator<_Const>::iterator_concept;
|
||||
using value_type = range_value_t<_Base>;
|
||||
using difference_type = range_difference_t<_Base>;
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
__inner_iterator() = default;
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
constexpr explicit __inner_iterator(__outer_iterator<_Const> __i)
|
||||
: __i_(std::move(__i)) {}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
constexpr const iterator_t<_Base>& base() const& noexcept { return __i_.__current(); }
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
constexpr iterator_t<_Base> base() &&
|
||||
requires forward_range<_View> { return std::move(__i_.__current()); }
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
constexpr decltype(auto) operator*() const { return *__i_.__current(); }
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
constexpr __inner_iterator& operator++() {
|
||||
__incremented_ = true;
|
||||
|
||||
if constexpr (!forward_range<_Base>) {
|
||||
if constexpr (_Pattern::size() == 0) {
|
||||
return *this;
|
||||
}
|
||||
}
|
||||
|
||||
++__i_.__current();
|
||||
return *this;
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
constexpr decltype(auto) operator++(int) {
|
||||
if constexpr (forward_range<_Base>) {
|
||||
auto __tmp = *this;
|
||||
++*this;
|
||||
return __tmp;
|
||||
|
||||
} else {
|
||||
++*this;
|
||||
}
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
friend constexpr bool operator==(const __inner_iterator& __x, const __inner_iterator& __y)
|
||||
requires forward_range<_Base> {
|
||||
return __x.__outer_current() == __y.__outer_current();
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
friend constexpr bool operator==(const __inner_iterator& __x, default_sentinel_t) {
|
||||
return __x.__is_done();
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
friend constexpr decltype(auto) iter_move(const __inner_iterator& __i)
|
||||
noexcept(noexcept(ranges::iter_move(__i.__outer_current()))) {
|
||||
return ranges::iter_move(__i.__outer_current());
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
friend constexpr void iter_swap(const __inner_iterator& __x, const __inner_iterator& __y)
|
||||
noexcept(noexcept(ranges::iter_swap(__x.__outer_current(), __y.__outer_current())))
|
||||
requires indirectly_swappable<iterator_t<_Base>> {
|
||||
ranges::iter_swap(__x.__outer_current(), __y.__outer_current());
|
||||
}
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
template <class _Range, class _Pattern>
|
||||
lazy_split_view(_Range&&, _Pattern&&) -> lazy_split_view<views::all_t<_Range>, views::all_t<_Pattern>>;
|
||||
|
||||
template <input_range _Range>
|
||||
lazy_split_view(_Range&&, range_value_t<_Range>)
|
||||
-> lazy_split_view<views::all_t<_Range>, single_view<range_value_t<_Range>>>;
|
||||
|
||||
namespace views {
|
||||
namespace __lazy_split_view {
|
||||
struct __fn : __range_adaptor_closure<__fn> {
|
||||
template <class _Range, class _Pattern>
|
||||
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI
|
||||
constexpr auto operator()(_Range&& __range, _Pattern&& __pattern) const
|
||||
noexcept(noexcept(lazy_split_view(std::forward<_Range>(__range), std::forward<_Pattern>(__pattern))))
|
||||
-> decltype( lazy_split_view(std::forward<_Range>(__range), std::forward<_Pattern>(__pattern)))
|
||||
{ return lazy_split_view(std::forward<_Range>(__range), std::forward<_Pattern>(__pattern)); }
|
||||
|
||||
template <class _Pattern>
|
||||
requires constructible_from<decay_t<_Pattern>, _Pattern>
|
||||
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI
|
||||
constexpr auto operator()(_Pattern&& __pattern) const
|
||||
noexcept(is_nothrow_constructible_v<decay_t<_Pattern>, _Pattern>) {
|
||||
return __range_adaptor_closure_t(std::__bind_back(*this, std::forward<_Pattern>(__pattern)));
|
||||
}
|
||||
};
|
||||
} // namespace __lazy_split_view
|
||||
|
||||
inline namespace __cpo {
|
||||
inline constexpr auto lazy_split = __lazy_split_view::__fn{};
|
||||
} // namespace __cpo
|
||||
} // namespace views
|
||||
|
||||
} // namespace ranges
|
||||
|
||||
#endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES)
|
||||
|
||||
_LIBCPP_END_NAMESPACE_STD
|
||||
|
||||
#endif // _LIBCPP___RANGES_LAZY_SPLIT_VIEW_H
|
|
@ -851,6 +851,7 @@ module std [system] {
|
|||
module enable_view { private header "__ranges/enable_view.h" }
|
||||
module iota_view { private header "__ranges/iota_view.h" }
|
||||
module join_view { private header "__ranges/join_view.h" }
|
||||
module lazy_split_view { private header "__ranges/lazy_split_view.h" }
|
||||
module non_propagating_cache { private header "__ranges/non_propagating_cache.h" }
|
||||
module owning_view { private header "__ranges/owning_view.h" }
|
||||
module range_adaptor { private header "__ranges/range_adaptor.h" }
|
||||
|
|
|
@ -204,6 +204,20 @@ namespace std::ranges {
|
|||
template<input_range V>
|
||||
requires view<V> && input_range<range_reference_t<V>>
|
||||
class join_view;
|
||||
|
||||
// [range.lazy.split], lazy split view
|
||||
template<class R>
|
||||
concept tiny-range = see below; // exposition only
|
||||
|
||||
template<input_range V, forward_range Pattern>
|
||||
requires view<V> && view<Pattern> &&
|
||||
indirectly_comparable<iterator_t<V>, iterator_t<Pattern>, ranges::equal_to> &&
|
||||
(forward_range<V> || tiny-range<Pattern>)
|
||||
class lazy_split_view;
|
||||
|
||||
namespace views {
|
||||
inline constexpr unspecified lazy_split = unspecified;
|
||||
}
|
||||
}
|
||||
|
||||
namespace std {
|
||||
|
@ -254,6 +268,7 @@ namespace std {
|
|||
#include <__ranges/enable_view.h>
|
||||
#include <__ranges/iota_view.h>
|
||||
#include <__ranges/join_view.h>
|
||||
#include <__ranges/lazy_split_view.h>
|
||||
#include <__ranges/rbegin.h>
|
||||
#include <__ranges/ref_view.h>
|
||||
#include <__ranges/rend.h>
|
||||
|
|
|
@ -404,6 +404,7 @@ END-SCRIPT
|
|||
#include <__ranges/enable_view.h> // expected-error@*:* {{use of private header from outside its module: '__ranges/enable_view.h'}}
|
||||
#include <__ranges/iota_view.h> // expected-error@*:* {{use of private header from outside its module: '__ranges/iota_view.h'}}
|
||||
#include <__ranges/join_view.h> // expected-error@*:* {{use of private header from outside its module: '__ranges/join_view.h'}}
|
||||
#include <__ranges/lazy_split_view.h> // expected-error@*:* {{use of private header from outside its module: '__ranges/lazy_split_view.h'}}
|
||||
#include <__ranges/non_propagating_cache.h> // expected-error@*:* {{use of private header from outside its module: '__ranges/non_propagating_cache.h'}}
|
||||
#include <__ranges/owning_view.h> // expected-error@*:* {{use of private header from outside its module: '__ranges/owning_view.h'}}
|
||||
#include <__ranges/range_adaptor.h> // expected-error@*:* {{use of private header from outside its module: '__ranges/range_adaptor.h'}}
|
||||
|
|
|
@ -0,0 +1,120 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||
// UNSUPPORTED: libcpp-has-no-incomplete-ranges
|
||||
|
||||
// clang-cl and cl currently don't support [[no_unique_address]]
|
||||
// XFAIL: msvc
|
||||
|
||||
// class lazy_split_view {
|
||||
// _LIBCPP_NO_UNIQUE_ADDRESS _View __base_ = _View();
|
||||
// _LIBCPP_NO_UNIQUE_ADDRESS _Pattern __pattern_ = _Pattern();
|
||||
// };
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include <string_view>
|
||||
#include "test_iterators.h"
|
||||
|
||||
// Verify the optimization that, if `View` is a forward range, the `lazy_split_view` itself doesn't store the `current`
|
||||
// iterator (instead, it's stored in the `outer-iterator`).
|
||||
//
|
||||
// Note that the Standard marks all data members of `lazy_split_view` as "exposition only", so this test has to be
|
||||
// libc++-specific.
|
||||
namespace test1 {
|
||||
|
||||
using SplitView = std::ranges::lazy_split_view<std::string_view, std::string_view>;
|
||||
// The `lazy_split_view` only stores the `View` and the `Pattern`, not an iterator.
|
||||
static_assert(sizeof(SplitView) == sizeof(std::string_view) * 2);
|
||||
|
||||
} // namespace test1
|
||||
|
||||
// Verify the optimization that, if `View` is an input range, the `outer-iterator` doesn't store the `current` iterator
|
||||
// (instead, it's stored in the `lazy_split_view` itself).
|
||||
//
|
||||
// Note that the Standard marks all data members of `outer-iterator` as "exposition only", so this test has to be
|
||||
// libc++-specific.
|
||||
namespace test2 {
|
||||
|
||||
struct InputView : std::ranges::view_base {
|
||||
int x;
|
||||
cpp20_input_iterator<int*> begin() const;
|
||||
sentinel_wrapper<cpp20_input_iterator<int*>> end() const;
|
||||
};
|
||||
static_assert( std::ranges::input_range<InputView>);
|
||||
static_assert(!std::ranges::forward_range<InputView>);
|
||||
static_assert( std::ranges::view<InputView>);
|
||||
|
||||
struct TinyView : std::ranges::view_base {
|
||||
int x;
|
||||
int* begin() const;
|
||||
int* end() const;
|
||||
constexpr static size_t size() { return 1; }
|
||||
};
|
||||
static_assert( std::ranges::forward_range<TinyView>);
|
||||
static_assert( std::ranges::__tiny_range<TinyView>);
|
||||
static_assert( std::ranges::view<TinyView>);
|
||||
|
||||
using SplitView = std::ranges::lazy_split_view<InputView, TinyView>;
|
||||
using OuterIter = std::ranges::iterator_t<SplitView>;
|
||||
// The `outer-iterator` only stores a pointer to the parent and a boolean (aligned to the size of a pointer), not an
|
||||
// iterator.
|
||||
static_assert(sizeof(OuterIter) == sizeof(void*) * 2);
|
||||
|
||||
} // namespace test2
|
||||
|
||||
// Verify the libc++-specific optimization that empty `View` and `Pattern` use the `[[no_unique_address]]` attribute.
|
||||
// Both `View` and `Pattern` are forward views.
|
||||
namespace test3 {
|
||||
|
||||
struct EmptyView1 : std::ranges::view_base {
|
||||
int* begin() const;
|
||||
int* end() const;
|
||||
};
|
||||
static_assert( std::ranges::forward_range<EmptyView1>);
|
||||
static_assert( std::ranges::view<EmptyView1>);
|
||||
|
||||
// Note: it's important to inherit `EmptyView1` and `EmptyView2` from different bases, otherwise they still cannot share
|
||||
// the same address regardless of whether `[[no_unique_address]]` is used.
|
||||
struct EmptyView2 : std::ranges::view_interface<EmptyView2> {
|
||||
int* begin() const;
|
||||
int* end() const;
|
||||
};
|
||||
static_assert( std::ranges::forward_range<EmptyView2>);
|
||||
static_assert( std::ranges::view<EmptyView2>);
|
||||
|
||||
static_assert(sizeof(std::ranges::lazy_split_view<EmptyView1, EmptyView2>) == 1);
|
||||
|
||||
} // namespace test3
|
||||
|
||||
// Verify the libc++-specific optimization that empty `View` and `Pattern` use the `[[no_unique_address]]` attribute.
|
||||
// `View` is an input view and `Pattern` is a tiny view.
|
||||
namespace test4 {
|
||||
|
||||
struct EmptyInputView : std::ranges::view_base {
|
||||
cpp20_input_iterator<int*> begin() const;
|
||||
sentinel_wrapper<cpp20_input_iterator<int*>> end() const;
|
||||
};
|
||||
static_assert( std::ranges::input_range<EmptyInputView>);
|
||||
static_assert(!std::ranges::forward_range<EmptyInputView>);
|
||||
static_assert( std::ranges::view<EmptyInputView>);
|
||||
|
||||
struct EmptyTinyView : std::ranges::view_base {
|
||||
int* begin() const;
|
||||
int* end() const;
|
||||
constexpr static size_t size() { return 1; }
|
||||
};
|
||||
static_assert( std::ranges::forward_range<EmptyTinyView>);
|
||||
static_assert( std::ranges::__tiny_range<EmptyTinyView>);
|
||||
static_assert( std::ranges::view<EmptyTinyView>);
|
||||
|
||||
static_assert(sizeof(std::ranges::lazy_split_view<EmptyInputView, EmptyTinyView>) ==
|
||||
sizeof(std::ranges::__non_propagating_cache<std::ranges::iterator_t<EmptyInputView>>));
|
||||
|
||||
} // namespace test4
|
|
@ -0,0 +1,36 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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, windows, libcxx-no-debug-mode
|
||||
// UNSUPPORTED: libcpp-has-no-incomplete-ranges
|
||||
// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1
|
||||
|
||||
// <ranges>
|
||||
|
||||
// friend constexpr bool operator==(const inner-iterator& x, default_sentinel_t);
|
||||
//
|
||||
// Can't compare a default-constructed `inner-iterator` with the default sentinel.
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include "check_assertion.h"
|
||||
#include "../types.h"
|
||||
|
||||
int main(int, char**) {
|
||||
{
|
||||
InnerIterForward i;
|
||||
TEST_LIBCPP_ASSERT_FAILURE(i == std::default_sentinel, "Cannot call comparison on a default-constructed iterator.");
|
||||
}
|
||||
|
||||
{
|
||||
InnerIterInput i;
|
||||
TEST_LIBCPP_ASSERT_FAILURE(i == std::default_sentinel, "Cannot call comparison on a default-constructed iterator.");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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, windows, libcxx-no-debug-mode
|
||||
// UNSUPPORTED: libcpp-has-no-incomplete-ranges
|
||||
// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1
|
||||
|
||||
// <ranges>
|
||||
|
||||
// friend constexpr bool operator==(const inner-iterator& x, default_sentinel_t);
|
||||
//
|
||||
// Can't compare a default-constructed `inner-iterator` with the default sentinel.
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include "check_assertion.h"
|
||||
#include "../types.h"
|
||||
|
||||
int main(int, char**) {
|
||||
{
|
||||
OuterIterForward i;
|
||||
TEST_LIBCPP_ASSERT_FAILURE(i == std::default_sentinel, "Cannot call comparison on a default-constructed iterator.");
|
||||
}
|
||||
|
||||
{
|
||||
OuterIterInput i;
|
||||
TEST_LIBCPP_ASSERT_FAILURE(i == std::default_sentinel, "Cannot call comparison on a default-constructed iterator.");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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_LAZY_SPLIT_TYPES_H
|
||||
#define TEST_LIBCXX_RANGES_RANGE_ADAPTORS_RANGE_LAZY_SPLIT_TYPES_H
|
||||
|
||||
#include <concepts>
|
||||
#include <ranges>
|
||||
#include <string_view>
|
||||
#include "test_iterators.h"
|
||||
|
||||
// ForwardView
|
||||
|
||||
struct ForwardView : std::ranges::view_base {
|
||||
constexpr explicit ForwardView() = default;
|
||||
constexpr ForwardView(ForwardView&&) = default;
|
||||
constexpr ForwardView& operator=(ForwardView&&) = default;
|
||||
constexpr forward_iterator<const char*> begin() const { return forward_iterator<const char*>(nullptr); }
|
||||
constexpr forward_iterator<const char*> end() const { return forward_iterator<const char*>(nullptr); }
|
||||
};
|
||||
static_assert( std::ranges::forward_range<ForwardView>);
|
||||
static_assert( std::ranges::forward_range<const ForwardView>);
|
||||
static_assert( std::ranges::view<ForwardView>);
|
||||
static_assert(!std::is_copy_constructible_v<ForwardView>);
|
||||
|
||||
// InputView
|
||||
|
||||
struct InputView : std::ranges::view_base {
|
||||
constexpr InputView() = default;
|
||||
|
||||
constexpr cpp20_input_iterator<char*> begin() { return cpp20_input_iterator<char*>(nullptr); }
|
||||
constexpr sentinel_wrapper<cpp20_input_iterator<char*>> end() {
|
||||
return sentinel_wrapper(cpp20_input_iterator<char*>(nullptr));
|
||||
}
|
||||
constexpr cpp20_input_iterator<const char*> begin() const { return cpp20_input_iterator<const char*>(nullptr); }
|
||||
constexpr sentinel_wrapper<cpp20_input_iterator<const char*>> end() const {
|
||||
return sentinel_wrapper(cpp20_input_iterator<const char*>(nullptr));
|
||||
}
|
||||
};
|
||||
|
||||
static_assert(std::ranges::input_range<InputView>);
|
||||
static_assert(std::ranges::input_range<const InputView>);
|
||||
static_assert(std::ranges::view<InputView>);
|
||||
|
||||
// ForwardTinyView
|
||||
|
||||
struct ForwardTinyView : std::ranges::view_base {
|
||||
constexpr ForwardTinyView() = default;
|
||||
constexpr forward_iterator<const char*> begin() const { return forward_iterator<const char*>(nullptr); }
|
||||
constexpr forward_iterator<const char*> end() const { return forward_iterator<const char*>(nullptr); }
|
||||
constexpr static size_t size() { return 1; }
|
||||
};
|
||||
static_assert(std::ranges::forward_range<ForwardTinyView>);
|
||||
static_assert(std::ranges::view<ForwardTinyView>);
|
||||
LIBCPP_STATIC_ASSERT(std::ranges::__tiny_range<ForwardTinyView>);
|
||||
|
||||
// Aliases
|
||||
|
||||
using SplitViewForward = std::ranges::lazy_split_view<ForwardView, ForwardView>;
|
||||
using OuterIterForward = std::ranges::iterator_t<SplitViewForward>;
|
||||
using InnerIterForward = std::ranges::iterator_t<OuterIterForward::value_type>;
|
||||
|
||||
using SplitViewInput = std::ranges::lazy_split_view<InputView, ForwardTinyView>;
|
||||
using OuterIterInput = std::ranges::iterator_t<SplitViewInput>;
|
||||
using InnerIterInput = std::ranges::iterator_t<OuterIterInput::value_type>;
|
||||
|
||||
#endif // TEST_LIBCXX_RANGES_RANGE_ADAPTORS_RANGE_LAZY_SPLIT_TYPES_H
|
|
@ -91,8 +91,8 @@ static_assert(test(std::views::counted, a, 10));
|
|||
//static_assert(test(std::views::elements<0>, pairs));
|
||||
//static_assert(test(std::views::filter, a, [](int x){ return x < 10; }));
|
||||
//static_assert(test(std::views::join, arrays));
|
||||
static_assert(test(std::views::lazy_split, a, 4));
|
||||
static_assert(test(std::views::reverse, a));
|
||||
//static_assert(test(std::views::split, a, 4));
|
||||
//static_assert(test(std::views::take, a, 10));
|
||||
//static_assert(test(std::views::take_while, a, [](int x){ return x < 10; }));
|
||||
static_assert(test(std::views::transform, a, [](int x){ return x + 1; }));
|
||||
|
|
|
@ -0,0 +1,128 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||
// UNSUPPORTED: libcpp-has-no-incomplete-ranges
|
||||
|
||||
// std::views::lazy_split
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <concepts>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
|
||||
#include "test_iterators.h"
|
||||
#include "types.h"
|
||||
|
||||
template <class View, class T>
|
||||
concept CanBePiped = requires (View&& view, T&& t) {
|
||||
{ std::forward<View>(view) | std::forward<T>(t) };
|
||||
};
|
||||
|
||||
struct SomeView : std::ranges::view_base {
|
||||
const std::string_view* v_;
|
||||
constexpr SomeView(const std::string_view& v) : v_(&v) {}
|
||||
constexpr auto begin() const { return v_->begin(); }
|
||||
constexpr auto end() const { return v_->end(); }
|
||||
};
|
||||
|
||||
struct NotAView { };
|
||||
|
||||
static_assert(!std::is_invocable_v<decltype(std::views::lazy_split)>);
|
||||
static_assert(!std::is_invocable_v<decltype(std::views::lazy_split), SomeView, NotAView>);
|
||||
static_assert(!std::is_invocable_v<decltype(std::views::lazy_split), NotAView, SomeView>);
|
||||
static_assert( std::is_invocable_v<decltype(std::views::lazy_split), SomeView, SomeView>);
|
||||
|
||||
static_assert( CanBePiped<SomeView&, decltype(std::views::lazy_split)>);
|
||||
static_assert( CanBePiped<char(&)[10], decltype(std::views::lazy_split)>);
|
||||
static_assert(!CanBePiped<char(&&)[10], decltype(std::views::lazy_split)>);
|
||||
static_assert(!CanBePiped<NotAView, decltype(std::views::lazy_split)>);
|
||||
|
||||
static_assert(std::same_as<decltype(std::views::lazy_split), decltype(std::ranges::views::lazy_split)>);
|
||||
|
||||
constexpr bool test() {
|
||||
std::string_view input = "abc";
|
||||
std::string_view sep = "a";
|
||||
|
||||
// Test that `std::views::lazy_split` is a range adaptor.
|
||||
|
||||
// Test `views::lazy_split(input, sep)`.
|
||||
{
|
||||
SomeView view(input);
|
||||
|
||||
using Result = std::ranges::lazy_split_view<SomeView, std::string_view>;
|
||||
std::same_as<Result> decltype(auto) result = std::views::lazy_split(view, sep);
|
||||
assert(result.base().begin() == input.begin());
|
||||
assert(result.base().end() == input.end());
|
||||
}
|
||||
|
||||
// Test `views::lazy_split(sep)(input)`.
|
||||
{
|
||||
SomeView view(input);
|
||||
|
||||
using Result = std::ranges::lazy_split_view<SomeView, std::string_view>;
|
||||
std::same_as<Result> decltype(auto) result = std::views::lazy_split(sep)(view);
|
||||
assert(result.base().begin() == input.begin());
|
||||
assert(result.base().end() == input.end());
|
||||
}
|
||||
|
||||
// Test `view | views::lazy_split`.
|
||||
{
|
||||
SomeView view(input);
|
||||
|
||||
using Result = std::ranges::lazy_split_view<SomeView, std::string_view>;
|
||||
std::same_as<Result> decltype(auto) result = view | std::views::lazy_split(sep);
|
||||
assert(result.base().begin() == input.begin());
|
||||
assert(result.base().end() == input.end());
|
||||
}
|
||||
|
||||
// Test `adaptor | views::lazy_split`.
|
||||
{
|
||||
SomeView view(input);
|
||||
auto f = [](char c) { return c; };
|
||||
auto partial = std::views::transform(f) | std::views::lazy_split(sep);
|
||||
|
||||
using Result = std::ranges::lazy_split_view<std::ranges::transform_view<SomeView, decltype(f)>, std::string_view>;
|
||||
std::same_as<Result> decltype(auto) result = partial(view);
|
||||
assert(result.base().base().begin() == input.begin());
|
||||
assert(result.base().base().end() == input.end());
|
||||
}
|
||||
|
||||
// Test `views::lazy_split | adaptor`.
|
||||
{
|
||||
SomeView view(input);
|
||||
auto f = [](auto v) { return v; };
|
||||
auto partial = std::views::lazy_split(sep) | std::views::transform(f);
|
||||
|
||||
using Result = std::ranges::transform_view<std::ranges::lazy_split_view<SomeView, std::string_view>, decltype(f)>;
|
||||
std::same_as<Result> decltype(auto) result = partial(view);
|
||||
assert(result.base().base().begin() == input.begin());
|
||||
assert(result.base().base().end() == input.end());
|
||||
}
|
||||
|
||||
// Test that one can call `std::views::lazy_split` 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.
|
||||
{
|
||||
struct X { };
|
||||
[[maybe_unused]] auto partial = std::views::lazy_split(X{});
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,126 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||
// UNSUPPORTED: libcpp-has-no-incomplete-ranges
|
||||
|
||||
// constexpr View base() const& requires copy_constructible<_View>;
|
||||
// constexpr View base() &&;
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include <cassert>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
#include "types.h"
|
||||
|
||||
struct MoveOnlyView : std::ranges::view_base {
|
||||
std::string_view view_;
|
||||
constexpr MoveOnlyView() = default;
|
||||
constexpr MoveOnlyView(const char* ptr) : view_(ptr) {}
|
||||
constexpr MoveOnlyView(std::string_view v) : view_(v) {}
|
||||
constexpr MoveOnlyView(MoveOnlyView&&) = default;
|
||||
constexpr MoveOnlyView& operator=(MoveOnlyView&&) = default;
|
||||
constexpr const char* begin() const { return view_.begin(); }
|
||||
constexpr const char* end() const { return view_.end(); }
|
||||
constexpr bool operator==(MoveOnlyView rhs) const { return view_ == rhs.view_; }
|
||||
};
|
||||
static_assert( std::ranges::view<MoveOnlyView>);
|
||||
static_assert( std::ranges::contiguous_range<MoveOnlyView>);
|
||||
static_assert(!std::copyable<MoveOnlyView>);
|
||||
|
||||
struct ViewWithInitTracking : std::ranges::view_base {
|
||||
enum class InitializedBy {
|
||||
Copy,
|
||||
Move,
|
||||
Invalid
|
||||
};
|
||||
|
||||
std::string_view v_;
|
||||
InitializedBy initialized_by = InitializedBy::Invalid;
|
||||
constexpr ViewWithInitTracking(std::string_view v) : v_(v) {}
|
||||
|
||||
constexpr auto begin() const { return v_.begin(); }
|
||||
constexpr auto end() const { return v_.end(); }
|
||||
|
||||
constexpr ViewWithInitTracking(const ViewWithInitTracking& rhs) : v_(rhs.v_) { initialized_by = InitializedBy::Copy; }
|
||||
constexpr ViewWithInitTracking(ViewWithInitTracking&& rhs) : v_(rhs.v_) { initialized_by = InitializedBy::Move; }
|
||||
constexpr ViewWithInitTracking& operator=(const ViewWithInitTracking& rhs) = default;
|
||||
constexpr ViewWithInitTracking& operator=(ViewWithInitTracking&& rhs) = default;
|
||||
constexpr bool operator==(const ViewWithInitTracking& rhs) const { return v_ == rhs.v_; }
|
||||
};
|
||||
|
||||
template <class View>
|
||||
concept CanCallBase = requires(View v) { std::forward<View>(v).base(); };
|
||||
|
||||
static_assert( CanCallBase<std::ranges::lazy_split_view<MoveOnlyView, ForwardView>&&>);
|
||||
static_assert(!CanCallBase<std::ranges::lazy_split_view<MoveOnlyView, ForwardView>&>);
|
||||
static_assert(!CanCallBase<std::ranges::lazy_split_view<MoveOnlyView, ForwardView> const &>);
|
||||
static_assert(!CanCallBase<std::ranges::lazy_split_view<MoveOnlyView, ForwardView> const &&>);
|
||||
|
||||
constexpr bool test() {
|
||||
using View = ViewWithInitTracking;
|
||||
|
||||
// Copyable input -- both lvalue and rvalue overloads of `base` are available.
|
||||
{
|
||||
// Non-const lvalue.
|
||||
{
|
||||
View str("abc def");
|
||||
std::ranges::lazy_split_view<View, std::string_view> v(str, " ");
|
||||
|
||||
std::same_as<View> decltype(auto) result = v.base();
|
||||
assert(result == str);
|
||||
assert(result.initialized_by == View::InitializedBy::Copy);
|
||||
}
|
||||
|
||||
// Const lvalue.
|
||||
{
|
||||
View str("abc def");
|
||||
const std::ranges::lazy_split_view<View, std::string_view> v(str, " ");
|
||||
|
||||
std::same_as<View> decltype(auto) result = v.base();
|
||||
assert(result == str);
|
||||
assert(result.initialized_by == View::InitializedBy::Copy);
|
||||
}
|
||||
|
||||
// Non-const rvalue.
|
||||
{
|
||||
View str("abc def");
|
||||
std::ranges::lazy_split_view<View, std::string_view> v(str, " ");
|
||||
|
||||
std::same_as<View> decltype(auto) result = std::move(v).base();
|
||||
assert(result == str);
|
||||
assert(result.initialized_by == View::InitializedBy::Move);
|
||||
}
|
||||
|
||||
// Const rvalue.
|
||||
{
|
||||
View str("abc def");
|
||||
const std::ranges::lazy_split_view<View, std::string_view> v(str, " ");
|
||||
|
||||
std::same_as<View> decltype(auto) result = std::move(v).base();
|
||||
assert(result == str);
|
||||
assert(result.initialized_by == View::InitializedBy::Copy);
|
||||
}
|
||||
}
|
||||
|
||||
// Move-only input -- only the rvalue overload of `base` is available.
|
||||
{
|
||||
std::ranges::lazy_split_view<MoveOnlyView, ForwardView> v;
|
||||
assert(std::move(v).base() == MoveOnlyView());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,149 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||
// UNSUPPORTED: libcpp-has-no-incomplete-ranges
|
||||
|
||||
// constexpr auto begin();
|
||||
// constexpr auto begin() const requires forward_range<View> && forward_range<const View>;
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include <cassert>
|
||||
#include <utility>
|
||||
#include "test_iterators.h"
|
||||
#include "types.h"
|
||||
|
||||
template <class View>
|
||||
concept ConstBeginDisabled = !requires (const View v) {
|
||||
{ (*v.begin()) };
|
||||
};
|
||||
|
||||
constexpr bool test() {
|
||||
// non-const: forward_range<View> && simple-view<View> -> outer-iterator<Const = true>
|
||||
// const: forward_range<View> && forward_range<const View> -> outer-iterator<Const = true>
|
||||
{
|
||||
using V = ForwardView;
|
||||
using P = V;
|
||||
|
||||
static_assert(std::ranges::forward_range<V>);
|
||||
static_assert(std::ranges::forward_range<const V>);
|
||||
LIBCPP_STATIC_ASSERT(std::ranges::__simple_view<V>);
|
||||
LIBCPP_STATIC_ASSERT(std::ranges::__simple_view<P>);
|
||||
|
||||
{
|
||||
std::ranges::lazy_split_view<V, P> v;
|
||||
auto it = v.begin();
|
||||
static_assert(std::is_same_v<decltype(it)::iterator_concept, std::forward_iterator_tag>);
|
||||
static_assert(std::is_same_v<decltype(*(*it).begin()), const char&>);
|
||||
}
|
||||
|
||||
{
|
||||
const std::ranges::lazy_split_view<V, P> cv;
|
||||
auto it = cv.begin();
|
||||
static_assert(std::is_same_v<decltype(it)::iterator_concept, std::forward_iterator_tag>);
|
||||
static_assert(std::is_same_v<decltype(*(*it).begin()), const char&>);
|
||||
}
|
||||
}
|
||||
|
||||
// non-const: forward_range<View> && !simple-view<View> -> outer-iterator<Const = false>
|
||||
// const: forward_range<View> && forward_range<const View> -> outer-iterator<Const = true>
|
||||
{
|
||||
using V = ForwardDiffView;
|
||||
using P = V;
|
||||
|
||||
static_assert(std::ranges::forward_range<V>);
|
||||
static_assert(std::ranges::forward_range<const V>);
|
||||
LIBCPP_STATIC_ASSERT(!std::ranges::__simple_view<V>);
|
||||
LIBCPP_STATIC_ASSERT(!std::ranges::__simple_view<P>);
|
||||
|
||||
{
|
||||
std::ranges::lazy_split_view<V, P> v;
|
||||
auto it = v.begin();
|
||||
static_assert(std::is_same_v<decltype(it)::iterator_concept, std::forward_iterator_tag>);
|
||||
static_assert(std::is_same_v<decltype(*(*it).begin()), char&>);
|
||||
}
|
||||
|
||||
{
|
||||
const std::ranges::lazy_split_view<V, P> cv;
|
||||
auto it = cv.begin();
|
||||
static_assert(std::is_same_v<decltype(it)::iterator_concept, std::forward_iterator_tag>);
|
||||
static_assert(std::is_same_v<decltype(*(*it).begin()), const char&>);
|
||||
}
|
||||
}
|
||||
|
||||
// non-const: forward_range<View> && !simple-view<View> -> outer-iterator<Const = false>
|
||||
// const: forward_range<View> && !forward_range<const View> -> disabled
|
||||
{
|
||||
using V = ForwardOnlyIfNonConstView;
|
||||
using P = V;
|
||||
static_assert(std::ranges::forward_range<V>);
|
||||
static_assert(!std::ranges::forward_range<const V>);
|
||||
LIBCPP_STATIC_ASSERT(!std::ranges::__simple_view<V>);
|
||||
LIBCPP_STATIC_ASSERT(!std::ranges::__simple_view<P>);
|
||||
|
||||
std::ranges::lazy_split_view<V, P> v;
|
||||
auto it = v.begin();
|
||||
static_assert(std::is_same_v<decltype(it)::iterator_concept, std::forward_iterator_tag>);
|
||||
static_assert(std::is_same_v<decltype(*(*it).begin()), const char&>);
|
||||
|
||||
static_assert(ConstBeginDisabled<decltype(v)>);
|
||||
}
|
||||
|
||||
// non-const: forward_range<View> && simple-view<View> && !simple-view<Pattern> -> outer-iterator<Const = false>
|
||||
// const: forward_range<View> && forward_range<const View> -> outer-iterator<Const = true>
|
||||
{
|
||||
using V = ForwardView;
|
||||
using P = ForwardOnlyIfNonConstView;
|
||||
|
||||
static_assert(std::ranges::forward_range<V>);
|
||||
static_assert(std::ranges::forward_range<const V>);
|
||||
LIBCPP_STATIC_ASSERT(std::ranges::__simple_view<V>);
|
||||
LIBCPP_STATIC_ASSERT(!std::ranges::__simple_view<P>);
|
||||
|
||||
{
|
||||
std::ranges::lazy_split_view<V, P> v;
|
||||
auto it = v.begin();
|
||||
static_assert(std::is_same_v<decltype(it)::iterator_concept, std::forward_iterator_tag>);
|
||||
static_assert(std::is_same_v<decltype(*(*it).begin()), const char&>);
|
||||
}
|
||||
|
||||
{
|
||||
const std::ranges::lazy_split_view<V, P> cv;
|
||||
auto it = cv.begin();
|
||||
static_assert(std::is_same_v<decltype(it)::iterator_concept, std::forward_iterator_tag>);
|
||||
static_assert(std::is_same_v<decltype(*(*it).begin()), const char&>);
|
||||
}
|
||||
}
|
||||
|
||||
// non-const: !forward_range<View> && tiny-range<Pattern> -> outer-iterator<Const = false>
|
||||
// const: !forward_range<View> -> disabled
|
||||
{
|
||||
using V = InputView;
|
||||
using P = ForwardTinyView;
|
||||
|
||||
static_assert(!std::ranges::forward_range<V>);
|
||||
static_assert(std::ranges::forward_range<P>);
|
||||
|
||||
std::ranges::lazy_split_view<V, P> v;
|
||||
auto it = v.begin();
|
||||
static_assert(std::is_same_v<decltype(it)::iterator_concept, std::input_iterator_tag>);
|
||||
static_assert(std::is_same_v<decltype(*(*it).begin()), char&>);
|
||||
|
||||
static_assert(ConstBeginDisabled<decltype(v)>);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,210 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||
// UNSUPPORTED: libcpp-has-no-incomplete-ranges
|
||||
|
||||
// template<input_range V, forward_range Pattern>
|
||||
// requires view<V> && view<Pattern> &&
|
||||
// indirectly_comparable<iterator_t<V>, iterator_t<Pattern>, ranges::equal_to> &&
|
||||
// (forward_range<V> || tiny-range<Pattern>)
|
||||
// class lazy_split_view;
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include "test_iterators.h"
|
||||
#include "types.h"
|
||||
|
||||
struct ForwardRange {
|
||||
forward_iterator<int*> begin() const;
|
||||
forward_iterator<int*> end() const;
|
||||
};
|
||||
static_assert( std::ranges::forward_range<ForwardRange>);
|
||||
|
||||
template <class View, class Pattern>
|
||||
concept CanInstantiate = requires {
|
||||
typename std::ranges::lazy_split_view<View, Pattern>;
|
||||
};
|
||||
|
||||
// All constraints satisfied (`View` and `Pattern` are forward views).
|
||||
namespace test1 {
|
||||
|
||||
using View = ForwardView;
|
||||
using Pattern = ForwardView;
|
||||
static_assert( std::ranges::forward_range<View>);
|
||||
static_assert( std::ranges::forward_range<Pattern>);
|
||||
static_assert( std::ranges::view<View>);
|
||||
static_assert( std::ranges::view<Pattern>);
|
||||
static_assert( std::indirectly_comparable<
|
||||
std::ranges::iterator_t<View>, std::ranges::iterator_t<Pattern>, std::ranges::equal_to>);
|
||||
static_assert( CanInstantiate<View, Pattern>);
|
||||
|
||||
} // namespace test1
|
||||
|
||||
// All constraints satisfied (`View` is an input view and `Pattern` is a tiny view).
|
||||
namespace test2 {
|
||||
|
||||
using View = InputView;
|
||||
using Pattern = ForwardTinyView;
|
||||
static_assert( std::ranges::input_range<View>);
|
||||
static_assert( std::ranges::forward_range<Pattern>);
|
||||
static_assert( std::ranges::view<View>);
|
||||
static_assert( std::ranges::view<Pattern>);
|
||||
static_assert( std::indirectly_comparable<
|
||||
std::ranges::iterator_t<View>, std::ranges::iterator_t<Pattern>, std::ranges::equal_to>);
|
||||
static_assert( CanInstantiate<View, Pattern>);
|
||||
|
||||
} // namespace test2
|
||||
|
||||
// `View` is not an input range.
|
||||
namespace test3 {
|
||||
|
||||
struct AlmostInputIterator {
|
||||
using value_type = char;
|
||||
using difference_type = ptrdiff_t;
|
||||
using iterator_concept = int;
|
||||
|
||||
constexpr const char& operator*() const;
|
||||
constexpr AlmostInputIterator& operator++();
|
||||
constexpr void operator++(int);
|
||||
constexpr bool operator==(const AlmostInputIterator&) const;
|
||||
};
|
||||
|
||||
static_assert( std::input_or_output_iterator<AlmostInputIterator>);
|
||||
static_assert(!std::input_iterator<AlmostInputIterator>);
|
||||
|
||||
struct NonInputView : std::ranges::view_base {
|
||||
AlmostInputIterator begin() const;
|
||||
AlmostInputIterator end() const;
|
||||
};
|
||||
|
||||
using View = NonInputView;
|
||||
using Pattern = ForwardTinyView;
|
||||
static_assert(!std::ranges::input_range<View>);
|
||||
static_assert( std::ranges::forward_range<Pattern>);
|
||||
static_assert( std::ranges::view<View>);
|
||||
static_assert( std::ranges::view<Pattern>);
|
||||
static_assert( std::indirectly_comparable<
|
||||
std::ranges::iterator_t<View>, std::ranges::iterator_t<Pattern>, std::ranges::equal_to>);
|
||||
static_assert(!CanInstantiate<View, Pattern>);
|
||||
|
||||
} // namespace test3
|
||||
|
||||
// `View` is not a view.
|
||||
namespace test4 {
|
||||
|
||||
using View = ForwardRange;
|
||||
using Pattern = ForwardView;
|
||||
static_assert( std::ranges::input_range<View>);
|
||||
static_assert( std::ranges::forward_range<Pattern>);
|
||||
static_assert(!std::ranges::view<View>);
|
||||
static_assert( std::ranges::view<Pattern>);
|
||||
static_assert( std::indirectly_comparable<
|
||||
std::ranges::iterator_t<View>, std::ranges::iterator_t<Pattern>, std::ranges::equal_to>);
|
||||
static_assert(!CanInstantiate<View, Pattern>);
|
||||
|
||||
} // namespace test4
|
||||
|
||||
// `Pattern` is not a forward range.
|
||||
namespace test5 {
|
||||
|
||||
using View = ForwardView;
|
||||
using Pattern = InputView;
|
||||
static_assert( std::ranges::input_range<View>);
|
||||
static_assert(!std::ranges::forward_range<Pattern>);
|
||||
static_assert( std::ranges::view<View>);
|
||||
static_assert( std::ranges::view<Pattern>);
|
||||
static_assert( std::indirectly_comparable<
|
||||
std::ranges::iterator_t<View>, std::ranges::iterator_t<Pattern>, std::ranges::equal_to>);
|
||||
static_assert(!CanInstantiate<View, Pattern>);
|
||||
|
||||
} // namespace test5
|
||||
|
||||
// Not indirectly comparable.
|
||||
namespace test6 {
|
||||
|
||||
struct Empty{};
|
||||
struct IntForwardView : std::ranges::view_base {
|
||||
constexpr forward_iterator<Empty*> begin() const { return {}; }
|
||||
constexpr forward_iterator<Empty*> end() const { return {}; }
|
||||
};
|
||||
|
||||
using View = ForwardView;
|
||||
using Pattern = IntForwardView;
|
||||
static_assert( std::ranges::input_range<View>);
|
||||
static_assert( std::ranges::forward_range<Pattern>);
|
||||
static_assert( std::ranges::view<View>);
|
||||
static_assert( std::ranges::view<Pattern>);
|
||||
static_assert(!std::indirectly_comparable<
|
||||
std::ranges::iterator_t<View>, std::ranges::iterator_t<Pattern>, std::ranges::equal_to>);
|
||||
static_assert(!CanInstantiate<View, Pattern>);
|
||||
|
||||
} // namespace test6
|
||||
|
||||
// `View` is an input range and `Pattern` is not a tiny range.
|
||||
namespace test7 {
|
||||
|
||||
using View = InputView;
|
||||
using Pattern = ForwardView;
|
||||
static_assert( std::ranges::input_range<View>);
|
||||
static_assert(!std::ranges::forward_range<View>);
|
||||
static_assert( std::ranges::forward_range<Pattern>);
|
||||
LIBCPP_STATIC_ASSERT(!std::ranges::__tiny_range<Pattern>);
|
||||
static_assert( std::ranges::view<View>);
|
||||
static_assert( std::ranges::view<Pattern>);
|
||||
static_assert( std::indirectly_comparable<
|
||||
std::ranges::iterator_t<View>, std::ranges::iterator_t<Pattern>, std::ranges::equal_to>);
|
||||
static_assert(!CanInstantiate<View, Pattern>);
|
||||
|
||||
} // namespace test7
|
||||
|
||||
// `View` is an input range and `Pattern` is almost a tiny range, except the `size()` function is not `constexpr`.
|
||||
namespace test8 {
|
||||
|
||||
struct AlmostTinyRange : std::ranges::view_base {
|
||||
int* begin() const;
|
||||
int* end() const;
|
||||
static size_t size() { return 1; }
|
||||
};
|
||||
|
||||
using View = InputView;
|
||||
using Pattern = AlmostTinyRange;
|
||||
static_assert( std::ranges::input_range<View>);
|
||||
static_assert(!std::ranges::forward_range<View>);
|
||||
static_assert( std::ranges::forward_range<Pattern>);
|
||||
LIBCPP_STATIC_ASSERT(!std::ranges::__tiny_range<Pattern>);
|
||||
static_assert( std::ranges::view<View>);
|
||||
static_assert( std::ranges::view<Pattern>);
|
||||
static_assert( std::indirectly_comparable<
|
||||
std::ranges::iterator_t<View>, std::ranges::iterator_t<Pattern>, std::ranges::equal_to>);
|
||||
static_assert(!CanInstantiate<View, Pattern>);
|
||||
|
||||
} // namespace test8
|
||||
|
||||
// `View` is an input range and `Pattern` is almost a tiny range, except the `size()` returns a number `>2`.
|
||||
namespace test9 {
|
||||
|
||||
struct AlmostTinyRange : std::ranges::view_base {
|
||||
int* begin() const;
|
||||
int* end() const;
|
||||
constexpr static size_t size() { return 2; }
|
||||
};
|
||||
|
||||
using View = InputView;
|
||||
using Pattern = ForwardView;
|
||||
static_assert( std::ranges::input_range<View>);
|
||||
static_assert(!std::ranges::forward_range<View>);
|
||||
static_assert( std::ranges::forward_range<Pattern>);
|
||||
LIBCPP_STATIC_ASSERT(!std::ranges::__tiny_range<Pattern>);
|
||||
static_assert( std::ranges::view<View>);
|
||||
static_assert( std::ranges::view<Pattern>);
|
||||
static_assert( std::indirectly_comparable<
|
||||
std::ranges::iterator_t<View>, std::ranges::iterator_t<Pattern>, std::ranges::equal_to>);
|
||||
static_assert(!CanInstantiate<View, Pattern>);
|
||||
|
||||
} // namespace test9
|
|
@ -0,0 +1,65 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||
// UNSUPPORTED: libcpp-has-no-incomplete-ranges
|
||||
|
||||
// template <class R, class P>
|
||||
// lazy_split_view(R&&, P&&) -> lazy_split_view<views::all_t<R>, views::all_t<P>>;
|
||||
//
|
||||
// template <input_range R>
|
||||
// lazy_split_view(R&&, range_value_t<R>) -> lazy_split_view<views::all_t<R>, single_view<range_value_t<R>>>;
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include <concepts>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include "types.h"
|
||||
|
||||
struct ForwardRange {
|
||||
forward_iterator<const char*> begin() const;
|
||||
forward_iterator<const char*> end() const;
|
||||
};
|
||||
static_assert( std::ranges::forward_range<ForwardRange>);
|
||||
|
||||
struct InputRange {
|
||||
cpp20_input_iterator<const char*> begin() const;
|
||||
sentinel_wrapper<cpp20_input_iterator<const char*>> end() const;
|
||||
};
|
||||
static_assert(std::ranges::input_range<InputRange>);
|
||||
|
||||
template <class I1, class I2, class ExpectedView, class ExpectedPattern>
|
||||
constexpr void test() {
|
||||
I1 i1{};
|
||||
I2 i2{};
|
||||
|
||||
std::ranges::lazy_split_view v(std::move(i1), std::move(i2));
|
||||
static_assert(std::same_as<decltype(v), std::ranges::lazy_split_view<ExpectedView, ExpectedPattern>>);
|
||||
using O = decltype(std::move(v).base());
|
||||
static_assert(std::same_as<O, ExpectedView>);
|
||||
}
|
||||
|
||||
constexpr void testCtad() {
|
||||
// (Range, Pattern)
|
||||
test<ForwardView, ForwardView, ForwardView, ForwardView>();
|
||||
test<ForwardRange, ForwardRange, std::ranges::views::all_t<ForwardRange>, std::ranges::views::all_t<ForwardRange>>();
|
||||
|
||||
// (Range, RangeElement)
|
||||
test<ForwardRange, char, std::ranges::views::all_t<ForwardRange>, std::ranges::single_view<char>>();
|
||||
test<InputRange, char, std::ranges::views::all_t<InputRange>, std::ranges::single_view<char>>();
|
||||
|
||||
// (Range, RangeElement) with implicit conversion.
|
||||
test<ForwardRange, bool, std::ranges::views::all_t<ForwardRange>, std::ranges::single_view<char>>();
|
||||
test<InputRange, bool, std::ranges::views::all_t<InputRange>, std::ranges::single_view<char>>();
|
||||
|
||||
// Note: CTAD from (InputRange, ForwardTinyRange) doesn't work -- the deduction guide wraps the pattern in
|
||||
// `views::all_t`, resulting in `views::owning_view<ForwardTinyRange>`. That type would never satisfy `tiny-range`
|
||||
// because `views::owning_view` contains a member function `size()` that shadows the static `size()` in
|
||||
// `ForwardTinyRange`.
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||
// UNSUPPORTED: libcpp-has-no-incomplete-ranges
|
||||
|
||||
// Test the implicitly-generated copy and move constructors since `lazy_split_view` has non-trivial members.
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include <cassert>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
#include "small_string.h"
|
||||
#include "types.h"
|
||||
|
||||
constexpr bool operator==(const InputView& lhs, const InputView& rhs) {
|
||||
return SmallString(lhs) == SmallString(rhs);
|
||||
}
|
||||
|
||||
constexpr bool test() {
|
||||
// Can copy `lazy_split_view`.
|
||||
{
|
||||
// Forward range.
|
||||
{
|
||||
std::ranges::lazy_split_view<std::string_view, std::string_view> v1("abc def", " ");
|
||||
auto v2 = v1;
|
||||
assert(v2.base() == v1.base());
|
||||
}
|
||||
|
||||
// Input range.
|
||||
{
|
||||
SplitViewInput v1("abc def", ' ');
|
||||
auto v2 = v1;
|
||||
assert(v2.base() == v1.base());
|
||||
}
|
||||
}
|
||||
|
||||
// Can move `lazy_split_view`.
|
||||
{
|
||||
// Forward range.
|
||||
{
|
||||
std::string_view base = "abc def";
|
||||
std::ranges::lazy_split_view<std::string_view, std::string_view> v1(base, " ");
|
||||
auto v2 = std::move(v1);
|
||||
assert(v2.base() == base);
|
||||
}
|
||||
|
||||
// Input range.
|
||||
{
|
||||
InputView base("abc def");
|
||||
SplitViewInput v1(base, ' ');
|
||||
auto v2 = std::move(v1);
|
||||
assert(v2.base() == base);
|
||||
}
|
||||
}
|
||||
|
||||
// `non-propagating-cache` is not copied.
|
||||
{
|
||||
SplitViewInput v1("abc def ghi", ' ');
|
||||
auto outer_iter1 = v1.begin();
|
||||
++outer_iter1;
|
||||
auto val1 = *outer_iter1;
|
||||
auto i1 = val1.begin();
|
||||
assert(*i1 == 'd');
|
||||
++i1;
|
||||
assert(*i1 == 'e');
|
||||
|
||||
auto v2 = v1;
|
||||
auto val2 = *v2.begin();
|
||||
auto i2 = val2.begin();
|
||||
assert(*i2 == 'a');
|
||||
++i2;
|
||||
assert(*i2 == 'b');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||
// UNSUPPORTED: libcpp-has-no-incomplete-ranges
|
||||
|
||||
// lazy_split_view() requires default_initializable<V> && default_initializable<P> = default;
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include <cassert>
|
||||
#include "types.h"
|
||||
|
||||
struct ThrowingDefaultCtorForwardView : std::ranges::view_base {
|
||||
ThrowingDefaultCtorForwardView() noexcept(false);
|
||||
forward_iterator<int*> begin() const;
|
||||
forward_iterator<int*> end() const;
|
||||
};
|
||||
|
||||
struct NoDefaultCtorForwardView : std::ranges::view_base {
|
||||
NoDefaultCtorForwardView() = delete;
|
||||
forward_iterator<int*> begin() const;
|
||||
forward_iterator<int*> end() const;
|
||||
};
|
||||
|
||||
static_assert( std::is_default_constructible_v<std::ranges::lazy_split_view<ForwardView, ForwardView>>);
|
||||
static_assert(!std::is_default_constructible_v<std::ranges::lazy_split_view<NoDefaultCtorForwardView, ForwardView>>);
|
||||
static_assert(!std::is_default_constructible_v<std::ranges::lazy_split_view<ForwardView, NoDefaultCtorForwardView>>);
|
||||
|
||||
static_assert( std::is_nothrow_default_constructible_v<std::ranges::lazy_split_view<ForwardView, ForwardView>>);
|
||||
static_assert(!std::is_nothrow_default_constructible_v<ThrowingDefaultCtorForwardView>);
|
||||
static_assert(!std::is_nothrow_default_constructible_v<
|
||||
std::ranges::lazy_split_view<ThrowingDefaultCtorForwardView, ForwardView>>);
|
||||
|
||||
constexpr bool test() {
|
||||
{
|
||||
std::ranges::lazy_split_view<CopyableView, ForwardView> v;
|
||||
assert(v.base() == CopyableView());
|
||||
}
|
||||
|
||||
{
|
||||
std::ranges::lazy_split_view<CopyableView, ForwardView> v = {};
|
||||
assert(v.base() == CopyableView());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,168 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||
// UNSUPPORTED: libcpp-has-no-incomplete-ranges
|
||||
|
||||
// template <input_range Range>
|
||||
// requires constructible_from<View, views::all_t<Range>> &&
|
||||
// constructible_from<Pattern, single_view<range_value_t<Range>>>
|
||||
// constexpr lazy_split_view(Range&& r, range_value_t<Range> e);
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include <cassert>
|
||||
#include <string_view>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include "small_string.h"
|
||||
#include "types.h"
|
||||
|
||||
struct ElementWithCounting {
|
||||
int* times_copied = nullptr;
|
||||
int* times_moved = nullptr;
|
||||
|
||||
constexpr ElementWithCounting(int& copies_ctr, int& moves_ctr) : times_copied(&copies_ctr), times_moved(&moves_ctr) {}
|
||||
|
||||
constexpr ElementWithCounting(const ElementWithCounting& rhs)
|
||||
: times_copied(rhs.times_copied)
|
||||
, times_moved(rhs.times_moved) {
|
||||
++(*times_copied);
|
||||
}
|
||||
constexpr ElementWithCounting(ElementWithCounting&& rhs)
|
||||
: times_copied(rhs.times_copied)
|
||||
, times_moved(rhs.times_moved) {
|
||||
++(*times_moved);
|
||||
}
|
||||
|
||||
constexpr bool operator==(const ElementWithCounting&) const { return true; }
|
||||
};
|
||||
|
||||
struct RangeWithCounting {
|
||||
using value_type = ElementWithCounting;
|
||||
|
||||
int* times_copied = nullptr;
|
||||
int* times_moved = nullptr;
|
||||
|
||||
constexpr RangeWithCounting(int& copies_ctr, int& moves_ctr) : times_copied(&copies_ctr), times_moved(&moves_ctr) {}
|
||||
|
||||
constexpr RangeWithCounting(const RangeWithCounting& rhs)
|
||||
: times_copied(rhs.times_copied)
|
||||
, times_moved(rhs.times_moved) {
|
||||
++(*times_copied);
|
||||
}
|
||||
constexpr RangeWithCounting(RangeWithCounting&& rhs)
|
||||
: times_copied(rhs.times_copied)
|
||||
, times_moved(rhs.times_moved) {
|
||||
++(*times_moved);
|
||||
}
|
||||
|
||||
constexpr const ElementWithCounting* begin() const { return nullptr; }
|
||||
constexpr const ElementWithCounting* end() const { return nullptr; }
|
||||
|
||||
constexpr RangeWithCounting& operator=(const RangeWithCounting&) = default;
|
||||
constexpr RangeWithCounting& operator=(RangeWithCounting&&) = default;
|
||||
constexpr bool operator==(const RangeWithCounting&) const { return true; }
|
||||
};
|
||||
static_assert( std::ranges::forward_range<RangeWithCounting>);
|
||||
static_assert(!std::ranges::view<RangeWithCounting>);
|
||||
|
||||
struct StrRange {
|
||||
SmallString buffer_;
|
||||
constexpr explicit StrRange() = default;
|
||||
constexpr StrRange(const char* ptr) : buffer_(ptr) {}
|
||||
constexpr const char* begin() const { return buffer_.begin(); }
|
||||
constexpr const char* end() const { return buffer_.end(); }
|
||||
constexpr bool operator==(const StrRange& rhs) const { return buffer_ == rhs.buffer_; }
|
||||
};
|
||||
static_assert( std::ranges::random_access_range<StrRange>);
|
||||
static_assert(!std::ranges::view<StrRange>);
|
||||
static_assert( std::is_copy_constructible_v<StrRange>);
|
||||
|
||||
struct StrView : std::ranges::view_base {
|
||||
SmallString buffer_;
|
||||
constexpr explicit StrView() = default;
|
||||
constexpr StrView(const char* ptr) : buffer_(ptr) {}
|
||||
template <std::ranges::range R>
|
||||
constexpr StrView(R&& r) : buffer_(std::forward<R>(r)) {}
|
||||
constexpr const char* begin() const { return buffer_.begin(); }
|
||||
constexpr const char* end() const { return buffer_.end(); }
|
||||
constexpr bool operator==(const StrView& rhs) const { return buffer_ == rhs.buffer_; }
|
||||
};
|
||||
static_assert( std::ranges::random_access_range<StrView>);
|
||||
static_assert( std::ranges::view<StrView>);
|
||||
static_assert( std::is_copy_constructible_v<StrView>);
|
||||
|
||||
constexpr bool test() {
|
||||
{
|
||||
using V = std::ranges::lazy_split_view<StrView, StrView>;
|
||||
|
||||
// Calling the constructor with `(StrRange, range_value_t)`.
|
||||
{
|
||||
StrRange input;
|
||||
V v(input, ' ');
|
||||
assert(v.base() == input);
|
||||
}
|
||||
|
||||
// Calling the constructor with `(StrView, range_value_t)`.
|
||||
{
|
||||
StrView input("abc def");
|
||||
V v(input, ' ');
|
||||
assert(v.base() == input);
|
||||
}
|
||||
|
||||
struct Empty {};
|
||||
static_assert(!std::is_constructible_v<V, Empty, std::string_view>);
|
||||
static_assert(!std::is_constructible_v<V, std::string_view, Empty>);
|
||||
}
|
||||
|
||||
// Make sure the arguments are moved, not copied.
|
||||
{
|
||||
using Range = RangeWithCounting;
|
||||
using Element = ElementWithCounting;
|
||||
// TODO(varconst): use `views::single` once it's implemented.
|
||||
using Pattern = std::ranges::single_view<Element>;
|
||||
|
||||
// Arguments are lvalues.
|
||||
{
|
||||
using View = std::ranges::ref_view<Range>;
|
||||
|
||||
int range_copied = 0, range_moved = 0, element_copied = 0, element_moved = 0;
|
||||
Range range(range_copied, range_moved);
|
||||
Element element(element_copied, element_moved);
|
||||
|
||||
std::ranges::lazy_split_view<View, Pattern> v(range, element);
|
||||
assert(range_copied == 0); // `ref_view` does neither copy...
|
||||
assert(range_moved == 0); // ...nor move the element.
|
||||
assert(element_copied == 1); // The element is copied into the argument...
|
||||
assert(element_moved == 1); // ...and moved into the member variable.
|
||||
}
|
||||
|
||||
// Arguments are rvalues.
|
||||
{
|
||||
using View = std::ranges::owning_view<Range>;
|
||||
|
||||
int range_copied = 0, range_moved = 0, element_copied = 0, element_moved = 0;
|
||||
std::ranges::lazy_split_view<View, Pattern> v(
|
||||
Range(range_copied, range_moved), Element(element_copied, element_moved));
|
||||
assert(range_copied == 0);
|
||||
assert(range_moved == 1); // `owning_view` moves the given argument.
|
||||
assert(element_copied == 0);
|
||||
assert(element_moved == 1);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,102 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||
// UNSUPPORTED: libcpp-has-no-incomplete-ranges
|
||||
|
||||
// constexpr lazy_split_view(View base, Pattern pattern);
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include <cassert>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
#include "types.h"
|
||||
|
||||
struct ViewWithCounting : std::ranges::view_base {
|
||||
int* times_copied = nullptr;
|
||||
int* times_moved = nullptr;
|
||||
|
||||
constexpr ViewWithCounting(int& copies_ctr, int& moves_ctr) : times_copied(&copies_ctr), times_moved(&moves_ctr) {}
|
||||
|
||||
constexpr ViewWithCounting(const ViewWithCounting& rhs)
|
||||
: times_copied(rhs.times_copied)
|
||||
, times_moved(rhs.times_moved) {
|
||||
++(*times_copied);
|
||||
}
|
||||
constexpr ViewWithCounting(ViewWithCounting&& rhs)
|
||||
: times_copied(rhs.times_copied)
|
||||
, times_moved(rhs.times_moved) {
|
||||
++(*times_moved);
|
||||
}
|
||||
|
||||
constexpr const char* begin() const { return nullptr; }
|
||||
constexpr const char* end() const { return nullptr; }
|
||||
|
||||
constexpr ViewWithCounting& operator=(const ViewWithCounting&) = default;
|
||||
constexpr ViewWithCounting& operator=(ViewWithCounting&&) = default;
|
||||
constexpr bool operator==(const ViewWithCounting&) const { return true; }
|
||||
};
|
||||
static_assert(std::ranges::forward_range<ViewWithCounting>);
|
||||
static_assert(std::ranges::view<ViewWithCounting>);
|
||||
|
||||
constexpr bool test() {
|
||||
// Calling the constructor with `(ForwardView, ForwardView)`.
|
||||
{
|
||||
CopyableView input = "abc def";
|
||||
std::ranges::lazy_split_view<CopyableView, CopyableView> v(input, " ");
|
||||
assert(v.base() == input);
|
||||
}
|
||||
|
||||
// Calling the constructor with `(InputView, TinyView)`.
|
||||
{
|
||||
InputView input = "abc def";
|
||||
std::ranges::lazy_split_view<InputView, ForwardTinyView> v(input, ' ');
|
||||
// Note: `InputView` isn't equality comparable.
|
||||
(void)v;
|
||||
}
|
||||
|
||||
// Make sure the arguments are moved, not copied.
|
||||
{
|
||||
using View = ViewWithCounting;
|
||||
using Pattern = ViewWithCounting;
|
||||
|
||||
// Arguments are lvalues.
|
||||
{
|
||||
int view_copied = 0, view_moved = 0, pattern_copied = 0, pattern_moved = 0;
|
||||
View view(view_copied, view_moved);
|
||||
Pattern pattern(pattern_copied, pattern_moved);
|
||||
|
||||
std::ranges::lazy_split_view<View, Pattern> v(view, pattern);
|
||||
assert(view_copied == 1); // The local variable is copied into the argument.
|
||||
assert(view_moved == 1);
|
||||
assert(pattern_copied == 1);
|
||||
assert(pattern_moved == 1);
|
||||
}
|
||||
|
||||
// Arguments are rvalues.
|
||||
{
|
||||
int view_copied = 0, view_moved = 0, pattern_copied = 0, pattern_moved = 0;
|
||||
std::ranges::lazy_split_view<View, Pattern> v(
|
||||
View(view_copied, view_moved), Pattern(pattern_copied, pattern_moved));
|
||||
assert(view_copied == 0);
|
||||
assert(view_moved == 1);
|
||||
assert(pattern_copied == 0);
|
||||
assert(pattern_moved == 1);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,167 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||
// UNSUPPORTED: libcpp-has-no-incomplete-ranges
|
||||
|
||||
// constexpr auto end() requires forward_range<View> && common_range<View>;
|
||||
// constexpr auto end() const;
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include <cassert>
|
||||
#include <utility>
|
||||
#include "test_iterators.h"
|
||||
#include "types.h"
|
||||
|
||||
struct ForwardViewCommonIfConst : std::ranges::view_base {
|
||||
std::string_view view_;
|
||||
constexpr explicit ForwardViewCommonIfConst() = default;
|
||||
constexpr ForwardViewCommonIfConst(const char* ptr) : view_(ptr) {}
|
||||
constexpr ForwardViewCommonIfConst(std::string_view v) : view_(v) {}
|
||||
constexpr ForwardViewCommonIfConst(ForwardViewCommonIfConst&&) = default;
|
||||
constexpr ForwardViewCommonIfConst& operator=(ForwardViewCommonIfConst&&) = default;
|
||||
constexpr ForwardViewCommonIfConst(const ForwardViewCommonIfConst&) = default;
|
||||
constexpr ForwardViewCommonIfConst& operator=(const ForwardViewCommonIfConst&) = default;
|
||||
constexpr forward_iterator<char*> begin() { return forward_iterator<char*>(nullptr); }
|
||||
constexpr std::default_sentinel_t end() { return std::default_sentinel; }
|
||||
constexpr forward_iterator<const char*> begin() const { return forward_iterator<const char*>(view_.begin()); }
|
||||
constexpr forward_iterator<const char*> end() const { return forward_iterator<const char*>(view_.end()); }
|
||||
};
|
||||
bool operator==(forward_iterator<char*>, std::default_sentinel_t) { return false; }
|
||||
|
||||
struct ForwardViewNonCommonRange : std::ranges::view_base {
|
||||
std::string_view view_;
|
||||
constexpr explicit ForwardViewNonCommonRange() = default;
|
||||
constexpr ForwardViewNonCommonRange(const char* ptr) : view_(ptr) {}
|
||||
constexpr ForwardViewNonCommonRange(std::string_view v) : view_(v) {}
|
||||
constexpr ForwardViewNonCommonRange(ForwardViewNonCommonRange&&) = default;
|
||||
constexpr ForwardViewNonCommonRange& operator=(ForwardViewNonCommonRange&&) = default;
|
||||
constexpr ForwardViewNonCommonRange(const ForwardViewNonCommonRange&) = default;
|
||||
constexpr ForwardViewNonCommonRange& operator=(const ForwardViewNonCommonRange&) = default;
|
||||
constexpr forward_iterator<char*> begin() { return forward_iterator<char*>(nullptr); }
|
||||
constexpr std::default_sentinel_t end() { return std::default_sentinel; }
|
||||
constexpr forward_iterator<const char*> begin() const { return forward_iterator<const char*>(view_.begin()); }
|
||||
constexpr std::default_sentinel_t end() const { return std::default_sentinel; }
|
||||
};
|
||||
bool operator==(forward_iterator<const char*>, std::default_sentinel_t) { return false; }
|
||||
|
||||
constexpr bool test() {
|
||||
// non-const: forward_range<V> && simple_view<V> && simple_view<P> -> outer-iterator<Const = true>
|
||||
// const: forward_range<V> && common_range<V> -> outer-iterator<Const = true>
|
||||
{
|
||||
using V = ForwardView;
|
||||
using P = V;
|
||||
|
||||
static_assert(std::ranges::forward_range<V>);
|
||||
static_assert(std::ranges::common_range<const V>);
|
||||
LIBCPP_STATIC_ASSERT(std::ranges::__simple_view<V>);
|
||||
LIBCPP_STATIC_ASSERT(std::ranges::__simple_view<P>);
|
||||
|
||||
{
|
||||
std::ranges::lazy_split_view<V, P> v;
|
||||
auto it = v.end();
|
||||
static_assert(std::is_same_v<decltype(it)::iterator_concept, std::forward_iterator_tag>);
|
||||
static_assert(std::is_same_v<decltype(*(*it).begin()), const char&>);
|
||||
}
|
||||
|
||||
{
|
||||
const std::ranges::lazy_split_view<V, P> cv;
|
||||
auto it = cv.end();
|
||||
static_assert(std::is_same_v<decltype(it)::iterator_concept, std::forward_iterator_tag>);
|
||||
static_assert(std::is_same_v<decltype(*(*it).begin()), const char&>);
|
||||
}
|
||||
}
|
||||
|
||||
// non-const: forward_range<V> && common_range<V> && simple_view<V> && !simple_view<P> -> outer-iterator<Const=false>
|
||||
// const: forward_range<V> && forward_range<const V> && common_range<const V> -> outer-iterator<Const = false>
|
||||
{
|
||||
using V = ForwardView;
|
||||
using P = ForwardDiffView;
|
||||
|
||||
static_assert(std::ranges::forward_range<V>);
|
||||
static_assert(std::ranges::common_range<V>);
|
||||
LIBCPP_STATIC_ASSERT(std::ranges::__simple_view<V>);
|
||||
LIBCPP_STATIC_ASSERT(!std::ranges::__simple_view<P>);
|
||||
static_assert(std::ranges::forward_range<const V>);
|
||||
static_assert(std::ranges::common_range<const V>);
|
||||
|
||||
{
|
||||
std::ranges::lazy_split_view<V, P> v;
|
||||
auto it = v.end();
|
||||
static_assert(std::is_same_v<decltype(it)::iterator_concept, std::forward_iterator_tag>);
|
||||
static_assert(std::is_same_v<decltype(*(*it).begin()), const char&>);
|
||||
}
|
||||
|
||||
{
|
||||
const std::ranges::lazy_split_view<V, P> cv;
|
||||
auto it = cv.end();
|
||||
static_assert(std::is_same_v<decltype(it)::iterator_concept, std::forward_iterator_tag>);
|
||||
static_assert(std::is_same_v<decltype(*(*it).begin()), const char&>);
|
||||
}
|
||||
}
|
||||
|
||||
// non-const: forward_range<V> && !common_range<V> -> disabled
|
||||
// const: forward_range<V> && forward_range<const V> && common_range<const V> -> outer-iterator<Const = true>
|
||||
{
|
||||
using V = ForwardViewCommonIfConst;
|
||||
using P = V;
|
||||
|
||||
static_assert(std::ranges::forward_range<V>);
|
||||
static_assert(!std::ranges::common_range<V>);
|
||||
static_assert(std::ranges::forward_range<const V>);
|
||||
static_assert(std::ranges::common_range<const V>);
|
||||
|
||||
{
|
||||
std::ranges::lazy_split_view<V, P> v;
|
||||
auto it = v.begin();
|
||||
static_assert(std::is_same_v<decltype(it)::iterator_concept, std::forward_iterator_tag>);
|
||||
static_assert(std::is_same_v<decltype(*(*it).begin()), char&>);
|
||||
}
|
||||
|
||||
{
|
||||
const std::ranges::lazy_split_view<V, P> cv;
|
||||
auto it = cv.begin();
|
||||
static_assert(std::is_same_v<decltype(it)::iterator_concept, std::forward_iterator_tag>);
|
||||
static_assert(std::is_same_v<decltype(*(*it).begin()), const char&>);
|
||||
}
|
||||
}
|
||||
|
||||
// non-const: forward_range<V> && !common_range<V> -> disabled
|
||||
// const: forward_range<V> && forward_range<const V> && !common_range<const V> -> outer-iterator<Const = false>
|
||||
{
|
||||
using V = ForwardViewNonCommonRange;
|
||||
using P = V;
|
||||
|
||||
static_assert(std::ranges::forward_range<V>);
|
||||
static_assert(!std::ranges::common_range<V>);
|
||||
static_assert(std::ranges::forward_range<const V>);
|
||||
static_assert(!std::ranges::common_range<const V>);
|
||||
|
||||
{
|
||||
std::ranges::lazy_split_view<V, P> v;
|
||||
auto it = v.end();
|
||||
static_assert(std::same_as<decltype(it), std::default_sentinel_t>);
|
||||
}
|
||||
|
||||
{
|
||||
const std::ranges::lazy_split_view<V, P> cv;
|
||||
auto it = cv.end();
|
||||
static_assert(std::same_as<decltype(it), std::default_sentinel_t>);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,401 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||
// UNSUPPORTED: libcpp-has-no-incomplete-ranges
|
||||
|
||||
// template <class View, class Pattern>
|
||||
// class std::ranges::lazy_split_view;
|
||||
//
|
||||
// These test check the output `lazy_split_view` produces for a variety of inputs, including many corner cases, with no
|
||||
// restrictions on which member functions can be called.
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include "small_string.h"
|
||||
#include "types.h"
|
||||
|
||||
template <std::ranges::view View, std::ranges::range Expected>
|
||||
constexpr bool is_equal(View& view, const Expected& expected) {
|
||||
using Char = std::ranges::range_value_t<std::ranges::range_value_t<View>>;
|
||||
using Str = BasicSmallString<Char>;
|
||||
|
||||
auto actual_it = view.begin();
|
||||
auto expected_it = expected.begin();
|
||||
for (; actual_it != view.end() && expected_it != expected.end(); ++actual_it, ++expected_it) {
|
||||
if (Str(*actual_it) != Str(*expected_it))
|
||||
return false;
|
||||
}
|
||||
|
||||
return actual_it == view.end() && expected_it == expected.end();
|
||||
}
|
||||
|
||||
template <class T, class Separator, class U, size_t M>
|
||||
constexpr bool test_function_call(T&& input, Separator&& separator, std::array<U, M> expected) {
|
||||
std::ranges::lazy_split_view v(input, separator);
|
||||
return is_equal(v, expected);
|
||||
}
|
||||
|
||||
template <class T, class Separator, class U, size_t M>
|
||||
constexpr bool test_with_piping(T&& input, Separator&& separator, std::array<U, M> expected) {
|
||||
auto expected_it = expected.begin();
|
||||
for (auto e : input | std::ranges::views::lazy_split(separator)) {
|
||||
if (expected_it == expected.end())
|
||||
return false;
|
||||
if (SmallString(e) != *expected_it)
|
||||
return false;
|
||||
|
||||
++expected_it;
|
||||
}
|
||||
|
||||
return expected_it == expected.end();
|
||||
}
|
||||
|
||||
constexpr bool test_l_r_values() {
|
||||
using namespace std::string_view_literals;
|
||||
|
||||
// Both lvalues and rvalues can be used as input.
|
||||
{
|
||||
// Lvalues.
|
||||
{
|
||||
auto input = "abc"sv;
|
||||
auto sep = " "sv;
|
||||
[[maybe_unused]] std::ranges::lazy_split_view v(input, sep);
|
||||
}
|
||||
|
||||
// Const lvalues.
|
||||
{
|
||||
const auto input = "abc"sv;
|
||||
const auto sep = " "sv;
|
||||
[[maybe_unused]] std::ranges::lazy_split_view v(input, sep);
|
||||
}
|
||||
|
||||
// Rvalues.
|
||||
{
|
||||
auto input = "abc"sv;
|
||||
auto sep = " "sv;
|
||||
[[maybe_unused]] std::ranges::lazy_split_view v(std::move(input), std::move(sep));
|
||||
}
|
||||
|
||||
// Const rvalues.
|
||||
{
|
||||
const auto input = "abc"sv;
|
||||
const auto sep = " "sv;
|
||||
[[maybe_unused]] std::ranges::lazy_split_view v(std::move(input), std::move(sep));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
constexpr bool test_string_literal_separator() {
|
||||
using namespace std::string_view_literals;
|
||||
|
||||
// Splitting works as expected when the separator is a single character literal.
|
||||
{
|
||||
std::ranges::lazy_split_view v("abc def"sv, ' ');
|
||||
assert(is_equal(v, std::array{"abc"sv, "def"sv}));
|
||||
}
|
||||
|
||||
// Counterintuitively, a seemingly equivalent separator expressed as a string literal doesn't match anything. This is
|
||||
// because of the implicit terminating null in the literal.
|
||||
{
|
||||
std::ranges::lazy_split_view v("abc def"sv, " ");
|
||||
assert(is_equal(v, std::array{"abc def"sv}));
|
||||
}
|
||||
|
||||
// To illustrate the previous point further, the separator is actually a two-character string literal: `{' ', '\0'}`.
|
||||
// Should the input string contain that two-character sequence, the separator would match.
|
||||
{
|
||||
std::ranges::lazy_split_view v("abc \0def"sv, " ");
|
||||
assert(is_equal(v, std::array{"abc"sv, "def"sv}));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Make sure that a string literal and a `string_view` produce the same results (which isn't always the case, see
|
||||
// below).
|
||||
template <class T>
|
||||
constexpr std::string_view sv(T&& str) {
|
||||
return std::string_view(str);
|
||||
};
|
||||
|
||||
template <class T, class Separator, class U, size_t M>
|
||||
constexpr void test_one(T&& input, Separator&& separator, std::array<U, M> expected) {
|
||||
assert(test_function_call(input, separator, expected));
|
||||
assert(test_with_piping(input, separator, expected));
|
||||
|
||||
// In addition to the `(ForwardView, ForwardView)` case, test the `(ForwardView, tiny-range)` and `(InputView,
|
||||
// tiny-range)` cases (all of which have unique code paths).
|
||||
if constexpr (std::is_same_v<std::remove_reference_t<Separator>, char>) {
|
||||
assert(test_function_call(CopyableView(input), ForwardTinyView(separator), expected));
|
||||
assert(test_with_piping(CopyableView(input), ForwardTinyView(separator), expected));
|
||||
|
||||
assert(test_function_call(InputView(input), ForwardTinyView(separator), expected));
|
||||
assert(test_with_piping(InputView(input), ForwardTinyView(separator), expected));
|
||||
}
|
||||
}
|
||||
|
||||
constexpr bool test_string_literals() {
|
||||
// These tests show characteristic examples of how using string literals with `lazy_split_view` produces unexpected
|
||||
// results due to the implicit terminating null that is treated as part of the range.
|
||||
|
||||
using namespace std::string_view_literals;
|
||||
|
||||
char short_sep = ' ';
|
||||
auto long_sep = "12"sv;
|
||||
|
||||
// When splitting a string literal, only the last segment will be null-terminated (getting the terminating null from
|
||||
// the original range).
|
||||
{
|
||||
std::array expected = {"abc"sv, std::string_view("def", sizeof("def"))};
|
||||
|
||||
assert(test_function_call("abc def", short_sep, expected));
|
||||
assert(test_with_piping("abc def", short_sep, expected));
|
||||
assert(test_function_call("abc12def", long_sep, expected));
|
||||
assert(test_with_piping("abc12def", long_sep, expected));
|
||||
}
|
||||
|
||||
// Empty string.
|
||||
{
|
||||
// Because an empty string literal contains an implicit terminating null, the output will contain one segment.
|
||||
std::array expected = {std::string_view("", 1)};
|
||||
|
||||
assert(test_function_call("", short_sep, expected));
|
||||
assert(test_with_piping("", short_sep, expected));
|
||||
assert(test_function_call("", long_sep, expected));
|
||||
assert(test_with_piping("", long_sep, expected));
|
||||
}
|
||||
|
||||
// Terminating null in the separator -- the character literal `' '` and the seemingly equivalent string literal `" "`
|
||||
// are treated differently due to the presence of an implicit `\0` in the latter.
|
||||
{
|
||||
const char input[] = "abc def";
|
||||
std::array expected_unsplit = {std::string_view(input, sizeof(input))};
|
||||
std::array expected_split = {"abc"sv, std::string_view("def", sizeof("def"))};
|
||||
|
||||
assert(test_function_call(input, " ", expected_unsplit));
|
||||
assert(test_function_call("abc \0def", " ", expected_split));
|
||||
// Note: string literals don't work with piping because arrays decay to pointers, and pointers don't model `range`.
|
||||
}
|
||||
|
||||
// Empty separator.
|
||||
{
|
||||
auto empty_sep = ""sv;
|
||||
std::array expected = {"a"sv, "b"sv, "c"sv, "\0"sv};
|
||||
|
||||
assert(test_function_call("abc", empty_sep, expected));
|
||||
assert(test_with_piping("abc", empty_sep, expected));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool test_nontrivial_characters() {
|
||||
// Try a deliberately heavyweight "character" type to see if it triggers any corner cases.
|
||||
|
||||
using Map = std::map<std::string, int>;
|
||||
using Vec = std::vector<Map>;
|
||||
|
||||
Map sep = {{"yyy", 999}};
|
||||
Map m1 = {
|
||||
{"a", 1},
|
||||
{"bc", 2},
|
||||
};
|
||||
Map m2 = {
|
||||
{"def", 3},
|
||||
};
|
||||
Map m3 = {
|
||||
{"g", 4},
|
||||
{"hijk", 5},
|
||||
};
|
||||
|
||||
Vec expected1 = {m1, m2};
|
||||
Vec expected2 = {m3};
|
||||
|
||||
std::ranges::lazy_split_view v(Vec{m1, m2, sep, m3}, sep);
|
||||
|
||||
// Segment 1: {m1, m2}
|
||||
auto outer = v.begin();
|
||||
assert(outer != v.end());
|
||||
auto inner = (*outer).begin();
|
||||
assert(*inner++ == m1);
|
||||
assert(*inner++ == m2);
|
||||
assert(inner == (*outer).end());
|
||||
|
||||
// Segment 2: {m3}
|
||||
++outer;
|
||||
assert(outer != v.end());
|
||||
inner = (*outer).begin();
|
||||
assert(*inner++ == m3);
|
||||
assert(inner == (*outer).end());
|
||||
|
||||
++outer;
|
||||
assert(outer == v.end());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
constexpr bool main_test() {
|
||||
using namespace std::string_view_literals;
|
||||
|
||||
char short_sep = ' ';
|
||||
auto long_sep = "12"sv;
|
||||
|
||||
// One separator.
|
||||
{
|
||||
std::array expected = {"abc"sv, "def"sv};
|
||||
test_one("abc def"sv, short_sep, expected);
|
||||
test_one("abc12def"sv, long_sep, expected);
|
||||
}
|
||||
|
||||
// Several separators in a row.
|
||||
{
|
||||
std::array expected = {"abc"sv, ""sv, ""sv, ""sv, "def"sv};
|
||||
test_one("abc def"sv, short_sep, expected);
|
||||
test_one("abc12121212def"sv, long_sep, expected);
|
||||
}
|
||||
|
||||
// Trailing separator.
|
||||
{
|
||||
std::array expected = {"abc"sv, "def"sv, ""sv};
|
||||
test_one("abc def "sv, short_sep, expected);
|
||||
test_one("abc12def12"sv, long_sep, expected);
|
||||
}
|
||||
|
||||
// Leading separator.
|
||||
{
|
||||
std::array expected = {""sv, "abc"sv, "def"sv};
|
||||
test_one(" abc def"sv, short_sep, expected);
|
||||
test_one("12abc12def"sv, long_sep, expected);
|
||||
}
|
||||
|
||||
// No separator.
|
||||
{
|
||||
std::array expected = {"abc"sv};
|
||||
test_one("abc"sv, short_sep, expected);
|
||||
test_one("abc"sv, long_sep, expected);
|
||||
}
|
||||
|
||||
// Input consisting of a single separator.
|
||||
{
|
||||
std::array expected = {""sv, ""sv};
|
||||
test_one(" "sv, short_sep, expected);
|
||||
test_one("12"sv, long_sep, expected);
|
||||
}
|
||||
|
||||
// Input consisting of only separators.
|
||||
{
|
||||
std::array expected = {""sv, ""sv, ""sv, ""sv};
|
||||
test_one(" "sv, short_sep, expected);
|
||||
test_one("121212"sv, long_sep, expected);
|
||||
}
|
||||
|
||||
// The separator and the string use the same character only.
|
||||
{
|
||||
auto overlapping_sep = "aaa"sv;
|
||||
std::array expected = {""sv, "aa"sv};
|
||||
test_one("aaaaa"sv, overlapping_sep, expected);
|
||||
}
|
||||
|
||||
// Many redundant separators.
|
||||
{
|
||||
std::array expected = {""sv, ""sv, "abc"sv, ""sv, ""sv, "def"sv, ""sv, ""sv};
|
||||
test_one(" abc def "sv, short_sep, expected);
|
||||
test_one("1212abc121212def1212"sv, long_sep, expected);
|
||||
}
|
||||
|
||||
// Separators after every character.
|
||||
{
|
||||
std::array expected = {""sv, "a"sv, "b"sv, "c"sv, ""sv};
|
||||
test_one(" a b c "sv, short_sep, expected);
|
||||
test_one("12a12b12c12"sv, long_sep, expected);
|
||||
}
|
||||
|
||||
// Overlap between the separator and the string (see https://wg21.link/lwg3505).
|
||||
{
|
||||
auto overlapping_sep = "ab"sv;
|
||||
std::array expected = {"a"sv, "aa"sv, ""sv, "b"sv};
|
||||
test_one("aabaaababb"sv, overlapping_sep, expected);
|
||||
}
|
||||
|
||||
// Empty input.
|
||||
{
|
||||
std::array<std::string_view, 0> expected = {};
|
||||
test_one(""sv, short_sep, expected);
|
||||
test_one(""sv, long_sep, expected);
|
||||
}
|
||||
|
||||
// Empty separator.
|
||||
{
|
||||
auto empty_sep = ""sv;
|
||||
std::array expected = {"a"sv, "b"sv, "c"sv};
|
||||
test_one("abc"sv, empty_sep, expected);
|
||||
test_one("abc"sv, empty_sep, expected);
|
||||
}
|
||||
|
||||
// Terminating null as a separator.
|
||||
{
|
||||
std::array expected = {"abc"sv, "def"sv};
|
||||
test_one("abc\0def"sv, '\0', expected);
|
||||
test_one("abc\0\0def"sv, "\0\0"sv, expected);
|
||||
}
|
||||
|
||||
// Different character types.
|
||||
{
|
||||
// `char`.
|
||||
test_function_call("abc def", ' ', std::array{"abc", "def"});
|
||||
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
|
||||
// `wchar_t`.
|
||||
test_function_call(L"abc def", L' ', std::array{L"abc", L"def"});
|
||||
#endif
|
||||
// `char8_t`.
|
||||
test_function_call(u8"abc def", u8' ', std::array{u8"abc", u8"def"});
|
||||
// `char16_t`.
|
||||
test_function_call(u"abc def", u' ', std::array{u"abc", u"def"});
|
||||
// `char32_t`.
|
||||
test_function_call(U"abc def", U' ', std::array{U"abc", U"def"});
|
||||
}
|
||||
|
||||
// Non-character input.
|
||||
{
|
||||
std::array expected = {std::array{1, 2, 3}, std::array{4, 5, 6}};
|
||||
test_one(std::array{1, 2, 3, 0, 4, 5, 6}, 0, expected);
|
||||
test_one(std::array{1, 2, 3, 0, 0, 0, 4, 5, 6}, std::array{0, 0, 0}, expected);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
main_test();
|
||||
static_assert(main_test());
|
||||
|
||||
test_string_literals();
|
||||
static_assert(test_string_literals());
|
||||
|
||||
test_l_r_values();
|
||||
static_assert(test_l_r_values());
|
||||
|
||||
test_string_literal_separator();
|
||||
static_assert(test_string_literal_separator());
|
||||
|
||||
// Note: map is not `constexpr`, so this test is runtime-only.
|
||||
test_nontrivial_characters();
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,103 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||
// UNSUPPORTED: libcpp-has-no-incomplete-ranges
|
||||
|
||||
// constexpr const iterator_t<Base>& inner-iterator::base() const& noexcept;
|
||||
//
|
||||
// constexpr iterator_t<Base> inner-iterator::base() &&
|
||||
// requires forward_range<View>;
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include <concepts>
|
||||
#include <utility>
|
||||
#include "../types.h"
|
||||
|
||||
static_assert( noexcept(std::declval<InnerIterForward&>().base()));
|
||||
static_assert( noexcept(std::declval<InnerIterForward const &>().base()));
|
||||
static_assert( noexcept(std::declval<InnerIterForward const &&>().base()));
|
||||
static_assert( noexcept(std::declval<InnerIterInput&>().base()));
|
||||
static_assert( noexcept(std::declval<InnerIterInput const &>().base()));
|
||||
static_assert( noexcept(std::declval<InnerIterInput const &&>().base()));
|
||||
|
||||
constexpr bool test() {
|
||||
// `base` works with a forward view (two different overloads based on ref-qualification of the `inner-iterator`).
|
||||
{
|
||||
using BaseIter = std::ranges::iterator_t<CopyableView>;
|
||||
CopyableView input("abc def");
|
||||
std::ranges::lazy_split_view<CopyableView, ForwardView> v(input, " ");
|
||||
auto i = (*v.begin()).begin();
|
||||
const auto ci = i;
|
||||
|
||||
// Note: some macOS platforms seem to have trouble deducing the type when using `std::same_as` -- use the equivalent
|
||||
// `ASSERT_SAME_TYPE` instead.
|
||||
{
|
||||
decltype(auto) b = i.base();
|
||||
ASSERT_SAME_TYPE(decltype(b), const BaseIter&);
|
||||
assert(b == input.begin());
|
||||
}
|
||||
|
||||
{
|
||||
decltype(auto) b = ci.base();
|
||||
ASSERT_SAME_TYPE(decltype(b), const BaseIter&);
|
||||
assert(b == input.begin());
|
||||
}
|
||||
|
||||
{
|
||||
decltype(auto) b = std::move(i).base();
|
||||
ASSERT_SAME_TYPE(decltype(b), BaseIter);
|
||||
assert(b == input.begin());
|
||||
}
|
||||
|
||||
{
|
||||
decltype(auto) b = std::move(ci).base();
|
||||
ASSERT_SAME_TYPE(decltype(b), const BaseIter&);
|
||||
assert(b == input.begin());
|
||||
}
|
||||
}
|
||||
|
||||
// `base` works with an input view (no overloads).
|
||||
{
|
||||
using BaseIter = std::ranges::iterator_t<InputView>;
|
||||
InputView input("abc def");
|
||||
std::ranges::lazy_split_view<InputView, ForwardTinyView> v(input, ' ');
|
||||
auto i = (*v.begin()).begin();
|
||||
const auto ci = i;
|
||||
|
||||
{
|
||||
decltype(auto) b = i.base();
|
||||
ASSERT_SAME_TYPE(decltype(b), const BaseIter&);
|
||||
}
|
||||
|
||||
{
|
||||
decltype(auto) b = ci.base();
|
||||
ASSERT_SAME_TYPE(decltype(b), const BaseIter&);
|
||||
}
|
||||
|
||||
{
|
||||
decltype(auto) b = std::move(i).base();
|
||||
ASSERT_SAME_TYPE(decltype(b), const BaseIter&);
|
||||
}
|
||||
|
||||
{
|
||||
decltype(auto) b = std::move(ci).base();
|
||||
ASSERT_SAME_TYPE(decltype(b), const BaseIter&);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||
// UNSUPPORTED: libcpp-has-no-incomplete-ranges
|
||||
|
||||
// constexpr inner-iterator::inner-iterator() = default;
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include "../types.h"
|
||||
|
||||
constexpr bool test() {
|
||||
{
|
||||
[[maybe_unused]] InnerIterForward i;
|
||||
}
|
||||
|
||||
{
|
||||
[[maybe_unused]] InnerIterInput i;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||
// UNSUPPORTED: libcpp-has-no-incomplete-ranges
|
||||
|
||||
// constexpr explicit inner-iterator::inner-iterator(outer-iterator<Const> i);
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include "../types.h"
|
||||
|
||||
static_assert(!std::is_constructible_v<InnerIterNonConst, OuterIterConst>);
|
||||
|
||||
template <class Inner, class Outer>
|
||||
constexpr void test_impl() {
|
||||
[[maybe_unused]] Inner i(Outer{});
|
||||
// Verify that the constructor is `explicit`.
|
||||
static_assert(!std::is_convertible_v<Outer, Inner>);
|
||||
}
|
||||
|
||||
constexpr bool test() {
|
||||
test_impl<InnerIterForward, OuterIterForward>();
|
||||
test_impl<InnerIterInput, OuterIterInput>();
|
||||
// Is only constructible if both the outer and the inner iterators have the same constness.
|
||||
test_impl<InnerIterConst, OuterIterConst>();
|
||||
// Note: this works because of an implicit conversion (`OuterIterNonConst` is converted to `OuterIterConst`).
|
||||
test_impl<InnerIterConst, OuterIterNonConst>();
|
||||
test_impl<InnerIterNonConst, OuterIterNonConst>();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||
// UNSUPPORTED: libcpp-has-no-incomplete-ranges
|
||||
|
||||
// constexpr decltype(auto) inner-iterator::operator*() const;
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include "../types.h"
|
||||
|
||||
constexpr bool test() {
|
||||
// Can call `inner-iterator::operator*`; `View` is a forward range.
|
||||
{
|
||||
SplitViewDiff v("abc def", " ");
|
||||
auto val = *v.begin();
|
||||
|
||||
// Non-const iterator.
|
||||
{
|
||||
auto i = val.begin();
|
||||
static_assert(std::same_as<decltype(*i), char&>);
|
||||
assert(*i == 'a');
|
||||
assert(*(++i) == 'b');
|
||||
assert(*(++i) == 'c');
|
||||
}
|
||||
|
||||
// Const iterator.
|
||||
{
|
||||
const auto ci = val.begin();
|
||||
static_assert(std::same_as<decltype(*ci), char&>);
|
||||
assert(*ci == 'a');
|
||||
}
|
||||
}
|
||||
|
||||
// Can call `inner-iterator::operator*`; `View` is an input range.
|
||||
{
|
||||
SplitViewInput v("abc def", ' ');
|
||||
auto val = *v.begin();
|
||||
|
||||
// Non-const iterator.
|
||||
{
|
||||
auto i = val.begin();
|
||||
static_assert(std::same_as<decltype(*i), char&>);
|
||||
assert(*i == 'a');
|
||||
assert(*(++i) == 'b');
|
||||
assert(*(++i) == 'c');
|
||||
}
|
||||
|
||||
// Const iterator.
|
||||
{
|
||||
const auto ci = val.begin();
|
||||
static_assert(std::same_as<decltype(*ci), char&>);
|
||||
// Note: when the underlying range is an input range, `current` is stored in the `lazy_split_view` itself and
|
||||
// shared between `inner-iterator`s. Consequently, incrementing one iterator effectively increments all of them.
|
||||
assert(*ci == 'c');
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||
// UNSUPPORTED: libcpp-has-no-incomplete-ranges
|
||||
|
||||
// friend constexpr bool operator==(const inner-iterator& x, const inner-iterator& y);
|
||||
// requires forward_range<Base>;
|
||||
//
|
||||
// friend constexpr bool operator==(const inner-iterator& x, default_sentinel_t);
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include <concepts>
|
||||
#include <string_view>
|
||||
#include "../types.h"
|
||||
|
||||
template <class Iter>
|
||||
concept CanCallEquals = requires(const Iter& i) {
|
||||
i == i;
|
||||
i != i;
|
||||
};
|
||||
|
||||
constexpr bool test() {
|
||||
// When `View` is a forward range, `inner-iterator` supports both overloads of `operator==`.
|
||||
{
|
||||
SplitViewForward v("abc def", " ");
|
||||
auto val = *v.begin();
|
||||
auto b = val.begin();
|
||||
std::same_as<std::default_sentinel_t> decltype(auto) e = val.end();
|
||||
|
||||
// inner-iterator == inner-iterator
|
||||
{
|
||||
assert(b == b);
|
||||
assert(!(b != b));
|
||||
}
|
||||
|
||||
// inner-iterator == default_sentinel
|
||||
{
|
||||
assert(!(b == e));
|
||||
assert(b != e);
|
||||
|
||||
assert(!(b == std::default_sentinel));
|
||||
assert(b != std::default_sentinel);
|
||||
}
|
||||
}
|
||||
|
||||
// When `View` is an input range, `inner-iterator only supports comparing an `inner-iterator` to the default sentinel.
|
||||
{
|
||||
SplitViewInput v("abc def", ' ');
|
||||
auto val = *v.begin();
|
||||
auto b = val.begin();
|
||||
std::same_as<std::default_sentinel_t> decltype(auto) e = val.end();
|
||||
|
||||
static_assert(!CanCallEquals<decltype(b)>);
|
||||
|
||||
assert(!(b == std::default_sentinel));
|
||||
assert(b != std::default_sentinel);
|
||||
assert(!(b == e));
|
||||
assert(b != e);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,133 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||
// UNSUPPORTED: libcpp-has-no-incomplete-ranges
|
||||
|
||||
// constexpr inner-iterator& inner-iterator::operator++();
|
||||
//
|
||||
// constexpr decltype(auto) inner-iterator::operator++(int);
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include <cassert>
|
||||
#include <type_traits>
|
||||
#include "test_macros.h"
|
||||
#include "../types.h"
|
||||
|
||||
struct EmptyView : std::ranges::view_base {
|
||||
constexpr int* begin() const { return nullptr; }
|
||||
constexpr int* end() const { return nullptr; }
|
||||
constexpr static size_t size() { return 0; }
|
||||
};
|
||||
static_assert(std::ranges::forward_range<EmptyView>);
|
||||
static_assert(std::ranges::view<EmptyView>);
|
||||
LIBCPP_STATIC_ASSERT(std::ranges::__tiny_range<EmptyView>);
|
||||
|
||||
constexpr bool test() {
|
||||
// Can call `inner-iterator::operator++`; `View` is a forward range.
|
||||
{
|
||||
SplitViewForward v("abc def", " ");
|
||||
auto val = *v.begin();
|
||||
|
||||
// ++i
|
||||
{
|
||||
auto i = val.begin();
|
||||
assert(*i == 'a');
|
||||
|
||||
decltype(auto) i2 = ++i;
|
||||
static_assert(std::is_lvalue_reference_v<decltype(i2)>);
|
||||
assert(&i2 == &i);
|
||||
assert(*i2 == 'b');
|
||||
}
|
||||
|
||||
// i++
|
||||
{
|
||||
auto i = val.begin();
|
||||
assert(*i == 'a');
|
||||
|
||||
decltype(auto) i2 = i++;
|
||||
static_assert(!std::is_reference_v<decltype(i2)>);
|
||||
assert(*i2 == 'a');
|
||||
assert(*i == 'b');
|
||||
}
|
||||
}
|
||||
|
||||
// Can call `inner-iterator::operator++`; `View` is an input range.
|
||||
{
|
||||
// ++i
|
||||
{
|
||||
SplitViewInput v("abc def", ' ');
|
||||
auto val = *v.begin();
|
||||
|
||||
auto i = val.begin();
|
||||
assert(*i == 'a');
|
||||
|
||||
decltype(auto) i2 = ++i;
|
||||
static_assert(std::is_lvalue_reference_v<decltype(i2)>);
|
||||
assert(&i2 == &i);
|
||||
assert(*i2 == 'b');
|
||||
}
|
||||
|
||||
// i++
|
||||
{
|
||||
SplitViewInput v("abc def", ' ');
|
||||
auto val = *v.begin();
|
||||
|
||||
auto i = val.begin();
|
||||
assert(*i == 'a');
|
||||
|
||||
static_assert(std::is_void_v<decltype(i++)>);
|
||||
i++;
|
||||
assert(*i == 'b');
|
||||
}
|
||||
}
|
||||
|
||||
// Can call `inner-iterator::operator++`; `View` is an input range and `Pattern` is an "empty" range.
|
||||
{
|
||||
// ++i
|
||||
{
|
||||
std::ranges::lazy_split_view<InputView, EmptyView> v("a", EmptyView());
|
||||
auto val = *v.begin();
|
||||
|
||||
auto i = val.begin();
|
||||
assert(*i.base() == 'a');
|
||||
assert(i != std::default_sentinel);
|
||||
|
||||
// The iterator doesn't move to the next character but is considered to point to the end.
|
||||
decltype(auto) i2 = ++i;
|
||||
assert(&i2 == &i);
|
||||
assert(*i2.base() == 'a');
|
||||
assert(i2 == std::default_sentinel);
|
||||
}
|
||||
|
||||
// i++
|
||||
{
|
||||
std::ranges::lazy_split_view<InputView, EmptyView> v("a", EmptyView());
|
||||
auto val = *v.begin();
|
||||
|
||||
auto i = val.begin();
|
||||
assert(*i.base() == 'a');
|
||||
assert(i != std::default_sentinel);
|
||||
|
||||
// The iterator doesn't move to the next character but is considered to point to the end.
|
||||
i++;
|
||||
assert(*i.base() == 'a');
|
||||
assert(i == std::default_sentinel);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,158 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||
// UNSUPPORTED: libcpp-has-no-incomplete-ranges
|
||||
|
||||
// friend constexpr decltype(auto) iter_move(const inner-iterator& i)
|
||||
// noexcept(noexcept(ranges::iter_move(i.i_.<current>)));
|
||||
|
||||
#include <iterator>
|
||||
|
||||
#include <cassert>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include "../types.h"
|
||||
|
||||
namespace adl {
|
||||
|
||||
template <bool IsNoexcept = false>
|
||||
struct Iterator {
|
||||
using value_type = int;
|
||||
using difference_type = ptrdiff_t;
|
||||
|
||||
value_type* ptr_ = nullptr;
|
||||
int* iter_move_invocations_ = nullptr;
|
||||
|
||||
constexpr Iterator() = default;
|
||||
constexpr explicit Iterator(int* p, int& iter_moves) : ptr_(p), iter_move_invocations_(&iter_moves) {}
|
||||
|
||||
constexpr value_type& operator*() const { return *ptr_; }
|
||||
|
||||
Iterator& operator++() { ++ptr_; return *this; }
|
||||
Iterator operator++(int) {
|
||||
Iterator prev = *this;
|
||||
++ptr_;
|
||||
return prev;
|
||||
}
|
||||
|
||||
constexpr Iterator& operator--() { --ptr_; return *this; }
|
||||
constexpr Iterator operator--(int) {
|
||||
Iterator prev = *this;
|
||||
--ptr_;
|
||||
return prev;
|
||||
}
|
||||
|
||||
constexpr friend value_type&& iter_move(Iterator iter) noexcept(IsNoexcept) {
|
||||
if (iter.iter_move_invocations_) {
|
||||
++(*iter.iter_move_invocations_);
|
||||
}
|
||||
return std::move(*iter);
|
||||
}
|
||||
|
||||
friend bool operator==(const Iterator& lhs, const Iterator& rhs) { return lhs.ptr_ == rhs.ptr_; }
|
||||
};
|
||||
|
||||
template <bool IsNoexcept = false>
|
||||
struct View : std::ranges::view_base {
|
||||
static constexpr int N = 3;
|
||||
int a[N] = {0, 1, 2};
|
||||
int* iter_moves = nullptr;
|
||||
|
||||
constexpr View() = default;
|
||||
constexpr View(int& iter_move_invocations) : iter_moves(&iter_move_invocations) {
|
||||
}
|
||||
|
||||
constexpr adl::Iterator<IsNoexcept> begin() { return adl::Iterator<IsNoexcept>(a, *iter_moves); }
|
||||
constexpr adl::Iterator<IsNoexcept> end() { return adl::Iterator<IsNoexcept>(a + N, *iter_moves); }
|
||||
};
|
||||
|
||||
} // namespace adl
|
||||
|
||||
constexpr bool test() {
|
||||
// Can use `iter_move` with `inner-iterator`; `View` is a forward range.
|
||||
{
|
||||
SplitViewForward v("abc def", " ");
|
||||
auto segment = *v.begin();
|
||||
|
||||
// Non-const iterator.
|
||||
{
|
||||
auto i = segment.begin();
|
||||
static_assert(std::same_as<decltype(iter_move(i)), const char &&>);
|
||||
assert(iter_move(i) == 'a');
|
||||
}
|
||||
|
||||
// Const iterator.
|
||||
{
|
||||
const auto i = segment.begin();
|
||||
static_assert(std::same_as<decltype(iter_move(i)), const char &&>);
|
||||
assert(iter_move(i) == 'a');
|
||||
}
|
||||
}
|
||||
|
||||
// Can use `iter_move` with `inner-iterator`, `View` is an input range.
|
||||
{
|
||||
SplitViewInput v("abc def", ' ');
|
||||
auto segment = *v.begin();
|
||||
|
||||
// Non-const iterator.
|
||||
{
|
||||
auto i = segment.begin();
|
||||
static_assert(std::same_as<decltype(iter_move(i)), char &&>);
|
||||
assert(iter_move(i) == 'a');
|
||||
}
|
||||
|
||||
// Const iterator.
|
||||
{
|
||||
const auto i = segment.begin();
|
||||
static_assert(std::same_as<decltype(iter_move(i)), char &&>);
|
||||
assert(iter_move(i) == 'a');
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure the `iter_move` customization point is being used.
|
||||
{
|
||||
int iter_move_invocations = 0;
|
||||
adl::View<> input(iter_move_invocations);
|
||||
std::ranges::lazy_split_view<adl::View<>, adl::View<>> v(input, adl::View<>());
|
||||
|
||||
auto segment = *v.begin();
|
||||
auto i = segment.begin();
|
||||
int x = iter_move(i);
|
||||
assert(x == 0);
|
||||
assert(iter_move_invocations == 1);
|
||||
}
|
||||
|
||||
// Check the `noexcept` specification.
|
||||
{
|
||||
{
|
||||
using ThrowingSplitView = std::ranges::lazy_split_view<adl::View<false>, adl::View<false>>;
|
||||
using ThrowingValueType = std::ranges::iterator_t<ThrowingSplitView>::value_type;
|
||||
using ThrowingIter = std::ranges::iterator_t<ThrowingValueType>;
|
||||
ASSERT_NOT_NOEXCEPT(std::ranges::iter_move(std::declval<adl::Iterator<false>>()));
|
||||
ASSERT_NOT_NOEXCEPT(iter_move(std::declval<ThrowingIter>()));
|
||||
}
|
||||
|
||||
{
|
||||
using NoexceptSplitView = std::ranges::lazy_split_view<adl::View<true>, adl::View<true>>;
|
||||
using NoexceptValueType = std::ranges::iterator_t<NoexceptSplitView>::value_type;
|
||||
using NoexceptIter = std::ranges::iterator_t<NoexceptValueType>;
|
||||
ASSERT_NOEXCEPT(std::ranges::iter_move(std::declval<adl::Iterator<true>>()));
|
||||
ASSERT_NOEXCEPT(iter_move(std::declval<NoexceptIter>()));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,215 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||
// UNSUPPORTED: libcpp-has-no-incomplete-ranges
|
||||
|
||||
// friend constexpr void iter_swap(const inner-iterator& x, const inner-iterator& y)
|
||||
// noexcept(noexcept(ranges::iter_swap(x.i_.<current>, y.i_.<current>)))
|
||||
// requires indirectly_swappable<iterator_t<Base>>;
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include <cassert>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include "../types.h"
|
||||
|
||||
namespace adl {
|
||||
|
||||
template <bool IsNoexcept = false>
|
||||
struct Iterator {
|
||||
using value_type = int;
|
||||
using difference_type = ptrdiff_t;
|
||||
|
||||
value_type* ptr_ = nullptr;
|
||||
int* iter_swap_invocations_ = nullptr;
|
||||
|
||||
constexpr Iterator() = default;
|
||||
constexpr explicit Iterator(int& iter_swaps) : iter_swap_invocations_(&iter_swaps) {}
|
||||
|
||||
value_type& operator*() const { return *ptr_; }
|
||||
|
||||
Iterator& operator++() { ++ptr_; return *this; }
|
||||
Iterator operator++(int) {
|
||||
Iterator prev = *this;
|
||||
++ptr_;
|
||||
return prev;
|
||||
}
|
||||
|
||||
Iterator& operator--() { --ptr_; return *this; }
|
||||
Iterator operator--(int) {
|
||||
Iterator prev = *this;
|
||||
--ptr_;
|
||||
return prev;
|
||||
}
|
||||
|
||||
constexpr friend void iter_swap(Iterator a, Iterator) noexcept(IsNoexcept) {
|
||||
if (a.iter_swap_invocations_) {
|
||||
++(*a.iter_swap_invocations_);
|
||||
}
|
||||
}
|
||||
|
||||
friend bool operator==(const Iterator& lhs, const Iterator& rhs) { return lhs.ptr_ == rhs.ptr_; }
|
||||
};
|
||||
|
||||
template <bool IsNoexcept = false>
|
||||
struct View : std::ranges::view_base {
|
||||
int* iter_swaps = nullptr;
|
||||
|
||||
constexpr View() = default;
|
||||
constexpr View(int& iter_swap_invocations) : iter_swaps(&iter_swap_invocations) {
|
||||
}
|
||||
|
||||
constexpr adl::Iterator<IsNoexcept> begin() { return adl::Iterator<IsNoexcept>(*iter_swaps); }
|
||||
constexpr adl::Iterator<IsNoexcept> end() { return adl::Iterator<IsNoexcept>(*iter_swaps); }
|
||||
};
|
||||
|
||||
} // namespace adl
|
||||
|
||||
constexpr bool test() {
|
||||
// Can use `iter_swap` with `inner-iterator`; `View` is a forward range.
|
||||
{
|
||||
// Non-const iterator.
|
||||
{
|
||||
SplitViewDiff v("abc def", " ");
|
||||
auto segment = *v.begin();
|
||||
|
||||
auto i1 = segment.begin();
|
||||
auto i2 = i1++;
|
||||
static_assert(std::is_void_v<decltype(iter_swap(i1, i2))>);
|
||||
assert(*i1 == 'b');
|
||||
assert(*i2 == 'a');
|
||||
|
||||
iter_swap(i1, i2);
|
||||
assert(*i1 == 'a');
|
||||
assert(*i2 == 'b');
|
||||
// Note that `iter_swap` swaps characters in the actual underlying range.
|
||||
assert(*v.base().begin() == 'b');
|
||||
}
|
||||
|
||||
// Const iterator.
|
||||
{
|
||||
SplitViewDiff v("abc def", " ");
|
||||
auto segment = *v.begin();
|
||||
|
||||
auto i1 = segment.begin();
|
||||
const auto i2 = i1++;
|
||||
static_assert(std::is_void_v<decltype(iter_swap(i1, i2))>);
|
||||
static_assert(std::is_void_v<decltype(iter_swap(i2, i2))>);
|
||||
assert(*i1 == 'b');
|
||||
assert(*i2 == 'a');
|
||||
|
||||
iter_swap(i1, i2);
|
||||
assert(*i1 == 'a');
|
||||
assert(*i2 == 'b');
|
||||
assert(*v.base().begin() == 'b');
|
||||
}
|
||||
}
|
||||
|
||||
// Can use `iter_swap` with `inner-iterator`; `View` is an input range.
|
||||
{
|
||||
|
||||
// Non-const iterator.
|
||||
{
|
||||
// Iterators belong to the same view.
|
||||
{
|
||||
SplitViewInput v("abc def", ' ');
|
||||
auto segment = *v.begin();
|
||||
|
||||
auto i1 = segment.begin();
|
||||
auto i2 = i1;
|
||||
++i1;
|
||||
static_assert(std::is_void_v<decltype(iter_swap(i1, i2))>);
|
||||
assert(*i1 == 'b');
|
||||
// For an input view, all inner iterators are essentially thin proxies to the same underlying iterator.
|
||||
assert(*i2 == 'b');
|
||||
|
||||
iter_swap(i1, i2);
|
||||
assert(*i1 == 'b');
|
||||
assert(*i2 == 'b');
|
||||
}
|
||||
|
||||
// Iterators belong to different views.
|
||||
{
|
||||
SplitViewInput v1("abc def", ' ');
|
||||
auto val1 = *v1.begin();
|
||||
SplitViewInput v2 = v1;
|
||||
auto val2 = *v2.begin();
|
||||
|
||||
auto i1 = val1.begin();
|
||||
auto i2 = val2.begin();
|
||||
++i1;
|
||||
assert(*i1 == 'b');
|
||||
assert(*i2 == 'a');
|
||||
|
||||
iter_swap(i1, i2);
|
||||
assert(*i1 == 'a');
|
||||
assert(*i2 == 'b');
|
||||
}
|
||||
}
|
||||
|
||||
// Const iterator.
|
||||
{
|
||||
SplitViewInput v("abc def", ' ');
|
||||
auto segment = *v.begin();
|
||||
|
||||
const auto i1 = segment.begin();
|
||||
const auto i2 = i1;
|
||||
static_assert(std::is_void_v<decltype(iter_swap(i1, i2))>);
|
||||
assert(*i1 == 'a');
|
||||
assert(*i2 == 'a');
|
||||
|
||||
iter_swap(i1, i2);
|
||||
assert(*i1 == 'a');
|
||||
assert(*i2 == 'a');
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure the `iter_swap` customization point is being used.
|
||||
{
|
||||
int iter_swap_invocations = 0;
|
||||
adl::View<> input(iter_swap_invocations);
|
||||
std::ranges::lazy_split_view<adl::View<>, adl::View<>> v(input, adl::View<>());
|
||||
|
||||
auto segment = *v.begin();
|
||||
auto i = segment.begin();
|
||||
iter_swap(i, i);
|
||||
assert(iter_swap_invocations == 1);
|
||||
}
|
||||
|
||||
// Check the `noexcept` specification.
|
||||
{
|
||||
{
|
||||
using ThrowingSplitView = std::ranges::lazy_split_view<adl::View<false>, adl::View<false>>;
|
||||
using ThrowingValueType = std::ranges::iterator_t<ThrowingSplitView>::value_type;
|
||||
using ThrowingIter = std::ranges::iterator_t<ThrowingValueType>;
|
||||
ASSERT_NOT_NOEXCEPT(
|
||||
std::ranges::iter_swap(std::declval<adl::Iterator<false>>(), std::declval<adl::Iterator<false>>()));
|
||||
ASSERT_NOT_NOEXCEPT(iter_swap(std::declval<ThrowingIter>(), std::declval<ThrowingIter>()));
|
||||
}
|
||||
|
||||
{
|
||||
using NoexceptSplitView = std::ranges::lazy_split_view<adl::View<true>, adl::View<true>>;
|
||||
using NoexceptValueType = std::ranges::iterator_t<NoexceptSplitView>::value_type;
|
||||
using NoexceptIter = std::ranges::iterator_t<NoexceptValueType>;
|
||||
ASSERT_NOEXCEPT(
|
||||
std::ranges::iter_swap(std::declval<adl::Iterator<true>>(), std::declval<adl::Iterator<true>>()));
|
||||
ASSERT_NOEXCEPT(iter_swap(std::declval<NoexceptIter>(), std::declval<NoexceptIter>()));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||
// UNSUPPORTED: libcpp-has-no-incomplete-ranges
|
||||
|
||||
// using iterator_category = If<
|
||||
// derived_from<typename iterator_traits<iterator_t<Base>>::iterator_category, forward_iterator_tag>,
|
||||
// forward_iterator_tag,
|
||||
// typename iterator_traits<iterator_t<Base>>::iterator_category
|
||||
// >;
|
||||
// using iterator_concept = typename outer-iterator<Const>::iterator_concept;
|
||||
// using value_type = range_value_t<Base>;
|
||||
// using difference_type = range_difference_t<Base>;
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include <concepts>
|
||||
#include <iterator>
|
||||
#include "../types.h"
|
||||
|
||||
template <class Range, class Pattern>
|
||||
using OuterIter = std::ranges::iterator_t<std::ranges::lazy_split_view<Range, Pattern>>;
|
||||
template <class Range, class Pattern>
|
||||
using InnerIter = std::ranges::iterator_t<decltype(*OuterIter<Range, Pattern>())>;
|
||||
|
||||
// iterator_concept
|
||||
|
||||
static_assert(std::same_as<typename InnerIter<ForwardView, ForwardView>::iterator_concept,
|
||||
typename OuterIter<ForwardView, ForwardView>::iterator_concept>);
|
||||
static_assert(std::same_as<typename InnerIter<InputView, ForwardTinyView>::iterator_concept,
|
||||
typename OuterIter<InputView, ForwardTinyView>::iterator_concept>);
|
||||
|
||||
// iterator_category
|
||||
|
||||
static_assert(std::same_as<typename InnerIter<ForwardView, ForwardView>::iterator_category, std::forward_iterator_tag>);
|
||||
|
||||
template <class Range, class Pattern>
|
||||
concept NoIteratorCategory = !requires { typename InnerIter<Range, Pattern>::iterator_category; };
|
||||
static_assert(NoIteratorCategory<InputView, ForwardTinyView>);
|
||||
|
||||
// value_type
|
||||
|
||||
static_assert(std::same_as<typename InnerIter<ForwardView, ForwardView>::value_type,
|
||||
std::ranges::range_value_t<ForwardView>>);
|
||||
|
||||
// difference_type
|
||||
|
||||
static_assert(std::same_as<typename InnerIter<ForwardView, ForwardView>::difference_type,
|
||||
std::ranges::range_difference_t<ForwardView>>);
|
|
@ -0,0 +1,68 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||
// UNSUPPORTED: libcpp-has-no-incomplete-ranges
|
||||
|
||||
// std::ranges::lazy_split_view::outer-iterator::value_type::begin()
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include <cassert>
|
||||
#include "../types.h"
|
||||
|
||||
constexpr bool test() {
|
||||
// `View` is a forward range.
|
||||
{
|
||||
CopyableView input("a");
|
||||
|
||||
// Non-const.
|
||||
{
|
||||
SplitViewCopyable v(input, "b");
|
||||
auto val = *v.begin();
|
||||
assert(val.begin().base() == input.begin());
|
||||
}
|
||||
|
||||
// Const.
|
||||
{
|
||||
SplitViewCopyable v(input, "b");
|
||||
const auto val = *v.begin();
|
||||
assert(val.begin().base() == input.begin());
|
||||
}
|
||||
}
|
||||
|
||||
// `View` is an input range.
|
||||
{
|
||||
InputView input("a");
|
||||
|
||||
// Non-const.
|
||||
{
|
||||
SplitViewInput v(input, 'b');
|
||||
auto val = *v.begin();
|
||||
// Copies of `InputView` are independent and the iterators won't compare the same.
|
||||
assert(*val.begin().base() == *input.begin());
|
||||
}
|
||||
|
||||
// Const.
|
||||
{
|
||||
SplitViewInput v(input, 'b');
|
||||
const auto val = *v.begin();
|
||||
// Copies of `InputView` are independent and the iterators won't compare the same.
|
||||
assert(*val.begin().base() == *input.begin());
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
assert(test());
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||
// UNSUPPORTED: libcpp-has-no-incomplete-ranges
|
||||
|
||||
// std::ranges::lazy_split_view::outer-iterator::value_type::value_type()
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include "../types.h"
|
||||
|
||||
constexpr bool test() {
|
||||
{
|
||||
[[maybe_unused]] ValueTypeForward val;
|
||||
}
|
||||
|
||||
{
|
||||
[[maybe_unused]] ValueTypeForward val = {};
|
||||
}
|
||||
|
||||
{
|
||||
[[maybe_unused]] ValueTypeInput val;
|
||||
}
|
||||
|
||||
{
|
||||
[[maybe_unused]] ValueTypeInput val = {};
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||
// UNSUPPORTED: libcpp-has-no-incomplete-ranges
|
||||
|
||||
// explicit outer-iterator::value_type::value_type(outer-iterator i)
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include <cassert>
|
||||
#include "../types.h"
|
||||
|
||||
// Verify that the constructor is `explicit`.
|
||||
static_assert(!std::is_convertible_v<OuterIterForward, ValueTypeForward>);
|
||||
static_assert(!std::is_convertible_v<OuterIterInput, ValueTypeInput>);
|
||||
|
||||
constexpr bool test() {
|
||||
// `View` is a forward range.
|
||||
{
|
||||
CopyableView input = "a";
|
||||
SplitViewCopyable v(input, "b");
|
||||
ValueTypeCopyable val(v.begin());
|
||||
assert(val.begin().base() == input.begin());
|
||||
}
|
||||
|
||||
// `View` is an input range.
|
||||
{
|
||||
InputView input = "a";
|
||||
SplitViewInput v(input, 'b');
|
||||
ValueTypeInput val(v.begin());
|
||||
assert(*val.begin().base() == *input.begin());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||
// UNSUPPORTED: libcpp-has-no-incomplete-ranges
|
||||
|
||||
// std::ranges::lazy_split_view::outer-iterator::value_type::end()
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include <cassert>
|
||||
#include "../types.h"
|
||||
|
||||
constexpr bool test() {
|
||||
// `View` is a forward range.
|
||||
{
|
||||
CopyableView input("a");
|
||||
|
||||
// Non-const.
|
||||
{
|
||||
SplitViewCopyable v(input, "b");
|
||||
auto val = *v.begin();
|
||||
|
||||
static_assert(std::same_as<decltype(val.end()), std::default_sentinel_t>);
|
||||
static_assert(noexcept(val.end()));
|
||||
[[maybe_unused]] auto e = val.end();
|
||||
}
|
||||
|
||||
// Const.
|
||||
{
|
||||
SplitViewCopyable v(input, "b");
|
||||
const auto val = *v.begin();
|
||||
|
||||
static_assert(std::same_as<decltype(val.end()), std::default_sentinel_t>);
|
||||
static_assert(noexcept(val.end()));
|
||||
[[maybe_unused]] auto e = val.end();
|
||||
}
|
||||
}
|
||||
|
||||
// `View` is an input range.
|
||||
{
|
||||
InputView input("a");
|
||||
|
||||
// Non-const.
|
||||
{
|
||||
SplitViewInput v(input, 'b');
|
||||
auto val = *v.begin();
|
||||
|
||||
static_assert(std::same_as<decltype(val.end()), std::default_sentinel_t>);
|
||||
static_assert(noexcept(val.end()));
|
||||
[[maybe_unused]] auto e = val.end();
|
||||
}
|
||||
|
||||
// Const.
|
||||
{
|
||||
SplitViewInput v(input, 'b');
|
||||
const auto val = *v.begin();
|
||||
|
||||
static_assert(std::same_as<decltype(val.end()), std::default_sentinel_t>);
|
||||
static_assert(noexcept(val.end()));
|
||||
[[maybe_unused]] auto e = val.end();
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
assert(test());
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||
// UNSUPPORTED: libcpp-has-no-incomplete-ranges
|
||||
|
||||
// class std::ranges::lazy_split_view::outer-iterator::value_type;
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include <cassert>
|
||||
#include <concepts>
|
||||
#include "../types.h"
|
||||
|
||||
using V = ValueTypeForward;
|
||||
static_assert(std::ranges::forward_range<V>);
|
||||
static_assert(std::ranges::view<V>);
|
||||
|
||||
static_assert(std::is_base_of_v<std::ranges::view_interface<ValueTypeForward>, ValueTypeForward>);
|
||||
|
||||
constexpr bool test() {
|
||||
// empty()
|
||||
{
|
||||
{
|
||||
SplitViewForward v("abc def", " ");
|
||||
auto val = *v.begin();
|
||||
assert(!val.empty());
|
||||
}
|
||||
|
||||
{
|
||||
SplitViewForward v;
|
||||
auto val = *v.begin();
|
||||
assert(val.empty());
|
||||
}
|
||||
}
|
||||
|
||||
// operator bool()
|
||||
{
|
||||
{
|
||||
SplitViewForward v("abc def", " ");
|
||||
auto val = *v.begin();
|
||||
assert(val);
|
||||
}
|
||||
|
||||
{
|
||||
SplitViewForward v;
|
||||
auto val = *v.begin();
|
||||
assert(!val);
|
||||
}
|
||||
}
|
||||
|
||||
// front()
|
||||
{
|
||||
SplitViewForward v("abc def", " ");
|
||||
auto val = *v.begin();
|
||||
assert(val.front() == 'a');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||
// UNSUPPORTED: libcpp-has-no-incomplete-ranges
|
||||
|
||||
// constexpr outer-iterator(outer-iterator<!Const> i)
|
||||
// requires Const && convertible_to<iterator_t<View>, iterator_t<Base>>
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include <string_view>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include "../types.h"
|
||||
|
||||
// outer-iterator<Const = true>
|
||||
|
||||
template <class Iter>
|
||||
concept IsConstOuterIter = requires (Iter i) {
|
||||
{ *(*i).begin() } -> std::same_as<const char&>;
|
||||
};
|
||||
static_assert( IsConstOuterIter<OuterIterConst>);
|
||||
|
||||
static_assert( std::convertible_to<
|
||||
std::ranges::iterator_t<SplitViewDiff>, std::ranges::iterator_t<const SplitViewDiff>>);
|
||||
|
||||
// outer-iterator<Const = false>
|
||||
|
||||
template <class Iter>
|
||||
concept IsNonConstOuterIter = requires (Iter i) {
|
||||
{ *(*i).begin() } -> std::same_as<char&>;
|
||||
};
|
||||
static_assert( IsNonConstOuterIter<OuterIterNonConst>);
|
||||
|
||||
static_assert(!std::is_constructible_v<OuterIterNonConst, OuterIterConst>);
|
||||
|
||||
constexpr bool test() {
|
||||
[[maybe_unused]] OuterIterConst i(OuterIterNonConst{});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||
// UNSUPPORTED: libcpp-has-no-incomplete-ranges
|
||||
|
||||
// std::ranges::lazy_split_view::outer-iterator::outer-iterator()
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include "../types.h"
|
||||
|
||||
constexpr bool test() {
|
||||
// `View` is a forward range.
|
||||
{
|
||||
[[maybe_unused]] OuterIterForward i;
|
||||
}
|
||||
|
||||
{
|
||||
[[maybe_unused]] OuterIterForward i = {};
|
||||
}
|
||||
|
||||
// `View` is an input range.
|
||||
{
|
||||
[[maybe_unused]] OuterIterInput i;
|
||||
}
|
||||
|
||||
{
|
||||
[[maybe_unused]] OuterIterInput i = {};
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||
// UNSUPPORTED: libcpp-has-no-incomplete-ranges
|
||||
|
||||
// explicit std::ranges::lazy_split_view::outer-iterator::outer-iterator(Parent& parent)
|
||||
// requires (!forward_range<Base>)
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include "../types.h"
|
||||
|
||||
// Verify that the constructor is `explicit`.
|
||||
static_assert(!std::is_convertible_v<SplitViewInput&, OuterIterInput>);
|
||||
|
||||
static_assert( std::ranges::forward_range<SplitViewForward>);
|
||||
static_assert(!std::is_constructible_v<OuterIterForward, SplitViewForward&>);
|
||||
|
||||
constexpr bool test() {
|
||||
InputView input;
|
||||
SplitViewInput v(input, ForwardTinyView());
|
||||
[[maybe_unused]] OuterIterInput i(v);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||
// UNSUPPORTED: libcpp-has-no-incomplete-ranges
|
||||
|
||||
// constexpr outer-iterator(Parent& parent, iterator_t<Base> current);
|
||||
// requires forward_range<Base>
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include "../types.h"
|
||||
|
||||
static_assert(!std::ranges::forward_range<SplitViewInput>);
|
||||
static_assert(!std::is_constructible_v<OuterIterInput, SplitViewInput&, std::ranges::iterator_t<InputView>>);
|
||||
|
||||
constexpr bool test() {
|
||||
ForwardView input("abc");
|
||||
SplitViewForward v(std::move(input), " ");
|
||||
[[maybe_unused]] OuterIterForward i(v, input.begin());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||
// UNSUPPORTED: libcpp-has-no-incomplete-ranges
|
||||
|
||||
// constexpr outer-iterator::value-type outer-iterator::operator*() const;
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include <cassert>
|
||||
#include <string_view>
|
||||
#include <type_traits>
|
||||
#include "../small_string.h"
|
||||
#include "../types.h"
|
||||
|
||||
template <class View, class Separator>
|
||||
constexpr void test_one(Separator sep) {
|
||||
using namespace std::string_view_literals;
|
||||
|
||||
View v("abc def ghi"sv, sep);
|
||||
|
||||
// Non-const iterator.
|
||||
{
|
||||
auto i = v.begin();
|
||||
static_assert(!std::is_reference_v<decltype(*i)>);
|
||||
assert(SmallString(*i) == "abc"_str);
|
||||
assert(SmallString(*(++i)) == "def"_str);
|
||||
assert(SmallString(*(++i)) == "ghi"_str);
|
||||
}
|
||||
|
||||
// Const iterator.
|
||||
{
|
||||
const auto ci = v.begin();
|
||||
static_assert(!std::is_reference_v<decltype(*ci)>);
|
||||
assert(SmallString(*ci) == "abc"_str);
|
||||
}
|
||||
}
|
||||
|
||||
constexpr bool test() {
|
||||
// `View` is a forward range.
|
||||
test_one<SplitViewDiff>(" ");
|
||||
test_one<SplitViewInput>(' ');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||
// UNSUPPORTED: libcpp-has-no-incomplete-ranges
|
||||
|
||||
// friend constexpr bool operator==(const outer-iterator& x, const outer-iterator& y)
|
||||
// requires forward_range<Base>;
|
||||
//
|
||||
// friend constexpr bool operator==(const outer-iterator& x, default_sentinel_t);
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include <concepts>
|
||||
#include <string_view>
|
||||
#include "../types.h"
|
||||
|
||||
template <class Iter>
|
||||
concept CanCallEquals = requires(const Iter& i) {
|
||||
i == i;
|
||||
i != i;
|
||||
};
|
||||
|
||||
constexpr bool test() {
|
||||
// Forward range supports both overloads of `operator==`.
|
||||
{
|
||||
// outer-iterator == outer-iterator
|
||||
{
|
||||
SplitViewForward v("abc def", " ");
|
||||
auto b = v.begin(), e = v.end();
|
||||
|
||||
assert(b == b);
|
||||
assert(!(b != b));
|
||||
|
||||
assert(e == e);
|
||||
assert(!(e != e));
|
||||
|
||||
assert(!(b == e));
|
||||
assert(b != e);
|
||||
}
|
||||
|
||||
// outer-iterator == default_sentinel
|
||||
{
|
||||
SplitViewForward v("abc def", " ");
|
||||
auto b = v.begin(), e = v.end();
|
||||
|
||||
assert(!(b == std::default_sentinel));
|
||||
assert(b != std::default_sentinel);
|
||||
assert(e == std::default_sentinel);
|
||||
assert(!(e != std::default_sentinel));
|
||||
}
|
||||
|
||||
// Default-constructed `outer-iterator`s compare equal.
|
||||
{
|
||||
OuterIterForward i1, i2;
|
||||
assert(i1 == i2);
|
||||
assert(!(i1 != i2));
|
||||
}
|
||||
}
|
||||
|
||||
// Input range only supports comparing an `outer-iterator` to the default sentinel.
|
||||
{
|
||||
using namespace std::string_view_literals;
|
||||
SplitViewInput v("abc def"sv, ' ');
|
||||
auto b = v.begin();
|
||||
std::same_as<std::default_sentinel_t> decltype(auto) e = v.end();
|
||||
|
||||
static_assert(!CanCallEquals<decltype(b)>);
|
||||
|
||||
assert(!(b == std::default_sentinel));
|
||||
assert(b != std::default_sentinel);
|
||||
assert(!(b == e));
|
||||
assert(b != e);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||
// UNSUPPORTED: libcpp-has-no-incomplete-ranges
|
||||
|
||||
// constexpr outer-iterator& outer-iterator::operator++();
|
||||
// constexpr decltype(auto) outer-iterator::operator++(int);
|
||||
|
||||
// Note that corner cases are tested in `range.lazy.split/general.pass.cpp`.
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include <algorithm>
|
||||
#include <string_view>
|
||||
#include "../small_string.h"
|
||||
#include "../types.h"
|
||||
|
||||
constexpr bool test() {
|
||||
// Can call `outer-iterator::operator++`; `View` is a forward range.
|
||||
{
|
||||
SplitViewForward v("abc def ghi", " ");
|
||||
|
||||
// ++i
|
||||
{
|
||||
auto i = v.begin();
|
||||
assert(*i == "abc"_str);
|
||||
|
||||
decltype(auto) i2 = ++i;
|
||||
static_assert(std::is_lvalue_reference_v<decltype(i2)>);
|
||||
assert(&i2 == &i);
|
||||
assert(*i2 == "def"_str);
|
||||
}
|
||||
|
||||
// i++
|
||||
{
|
||||
auto i = v.begin();
|
||||
assert(*i == "abc"_str);
|
||||
|
||||
decltype(auto) i2 = i++;
|
||||
static_assert(!std::is_reference_v<decltype(i2)>);
|
||||
assert(*i2 == "abc"_str);
|
||||
assert(*i == "def"_str);
|
||||
}
|
||||
}
|
||||
|
||||
// Can call `outer-iterator::operator++`; `View` is an input range.
|
||||
{
|
||||
SplitViewInput v("abc def ghi", ' ');
|
||||
|
||||
// ++i
|
||||
{
|
||||
auto i = v.begin();
|
||||
assert(*i == "abc"_str);
|
||||
|
||||
decltype(auto) i2 = ++i;
|
||||
static_assert(std::is_lvalue_reference_v<decltype(i2)>);
|
||||
assert(&i2 == &i);
|
||||
assert(*i2 == "def"_str);
|
||||
}
|
||||
|
||||
// i++
|
||||
{
|
||||
auto i = v.begin();
|
||||
assert(*i == "abc"_str);
|
||||
|
||||
static_assert(std::is_void_v<decltype(i++)>);
|
||||
i++;
|
||||
assert(*i == "def"_str);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||
// UNSUPPORTED: libcpp-has-no-incomplete-ranges
|
||||
|
||||
// using iterator_category = input_iterator_tag; // Only defined if `View` is a forward range.
|
||||
// using iterator_concept = conditional_t<forward_range<Base>, forward_iterator_tag, input_iterator_tag>;
|
||||
// using difference_type = range_difference_t<Base>;
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include <concepts>
|
||||
#include <iterator>
|
||||
#include "../types.h"
|
||||
|
||||
template <class Range, class Pattern>
|
||||
using OuterIter = decltype(std::declval<std::ranges::lazy_split_view<Range, Pattern>>().begin());
|
||||
|
||||
// iterator_category
|
||||
|
||||
static_assert(std::same_as<typename OuterIter<ForwardView, ForwardView>::iterator_category, std::input_iterator_tag>);
|
||||
|
||||
template <class Range, class Pattern>
|
||||
concept NoIteratorCategory = !requires { typename OuterIter<Range, Pattern>::iterator_category; };
|
||||
static_assert(NoIteratorCategory<InputView, ForwardTinyView>);
|
||||
|
||||
// iterator_concept
|
||||
|
||||
static_assert(std::same_as<typename OuterIter<ForwardView, ForwardView>::iterator_concept, std::forward_iterator_tag>);
|
||||
static_assert(std::same_as<typename OuterIter<InputView, ForwardTinyView>::iterator_concept, std::input_iterator_tag>);
|
||||
|
||||
// difference_type
|
||||
|
||||
static_assert(std::same_as<typename OuterIter<ForwardView, ForwardView>::difference_type,
|
||||
std::ranges::range_difference_t<ForwardView>>);
|
|
@ -0,0 +1,79 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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_LAZY_SPLIT_SMALL_STRING_H
|
||||
#define TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_LAZY_SPLIT_SMALL_STRING_H
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <ranges>
|
||||
#include <string_view>
|
||||
|
||||
// A constexpr-friendly lightweight string, primarily useful for comparisons.
|
||||
// Unlike `std::string`, all functions are `constexpr`. Unlike `std::string_view`, it copies the given string into an
|
||||
// internal buffer and can work with non-contiguous inputs.
|
||||
//
|
||||
// TODO(var-const): remove once https://reviews.llvm.org/D110598 lands and `std::string` can be used instead of this
|
||||
// class.
|
||||
template <class Char>
|
||||
class BasicSmallString {
|
||||
constexpr static int N = 32;
|
||||
Char buffer_[N] = {};
|
||||
size_t size_ = 0;
|
||||
|
||||
public:
|
||||
// Main constructors.
|
||||
|
||||
constexpr BasicSmallString() = default;
|
||||
|
||||
constexpr BasicSmallString(std::basic_string_view<Char> v) : size_(v.size()) {
|
||||
assert(size_ < N);
|
||||
if (size_ == 0) return;
|
||||
|
||||
std::copy(v.begin(), v.end(), buffer_);
|
||||
}
|
||||
|
||||
template <class I, class S>
|
||||
constexpr BasicSmallString(I b, const S& e) {
|
||||
for (; b != e; ++b) {
|
||||
buffer_[size_++] = *b;
|
||||
assert(size_ < N);
|
||||
}
|
||||
}
|
||||
|
||||
// Delegating constructors.
|
||||
|
||||
constexpr BasicSmallString(const Char* ptr, size_t size) : BasicSmallString(std::basic_string_view<Char>(ptr, size)) {
|
||||
}
|
||||
|
||||
template <std::ranges::range R>
|
||||
constexpr BasicSmallString(R&& from) : BasicSmallString(from.begin(), from.end()) {
|
||||
}
|
||||
|
||||
// Iterators.
|
||||
|
||||
constexpr Char* begin() { return buffer_; }
|
||||
constexpr Char* end() { return buffer_ + size_; }
|
||||
constexpr const Char* begin() const { return buffer_; }
|
||||
constexpr const Char* end() const { return buffer_ + size_; }
|
||||
|
||||
friend constexpr bool operator==(const BasicSmallString& lhs, const BasicSmallString& rhs) {
|
||||
return lhs.size_ == rhs.size_ && std::equal(lhs.buffer_, lhs.buffer_ + lhs.size_, rhs.buffer_);
|
||||
}
|
||||
friend constexpr bool operator==(const BasicSmallString& lhs, std::string_view rhs) {
|
||||
return lhs == BasicSmallString(rhs);
|
||||
}
|
||||
};
|
||||
|
||||
using SmallString = BasicSmallString<char>;
|
||||
|
||||
inline constexpr SmallString operator "" _str(const char* ptr, size_t size) {
|
||||
return SmallString(ptr, size);
|
||||
}
|
||||
|
||||
#endif // TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_LAZY_SPLIT_SMALL_STRING_H
|
|
@ -0,0 +1,202 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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_LAZY_SPLIT_TYPES_H
|
||||
#define TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_LAZY_SPLIT_TYPES_H
|
||||
|
||||
#include <concepts>
|
||||
#include <ranges>
|
||||
#include <string_view>
|
||||
#include <type_traits>
|
||||
#include "small_string.h"
|
||||
#include "test_macros.h"
|
||||
#include "test_iterators.h"
|
||||
|
||||
// CopyableView
|
||||
|
||||
struct CopyableView : std::ranges::view_base {
|
||||
std::string_view view_;
|
||||
constexpr explicit CopyableView() = default;
|
||||
constexpr CopyableView(const char* ptr) : view_(ptr) {}
|
||||
constexpr CopyableView(std::string_view v) : view_(v) {}
|
||||
constexpr forward_iterator<const char*> begin() const { return forward_iterator<const char*>(view_.begin()); }
|
||||
constexpr forward_iterator<const char*> end() const { return forward_iterator<const char*>(view_.end()); }
|
||||
constexpr bool operator==(const CopyableView& rhs) const { return view_ == rhs.view_; }
|
||||
};
|
||||
static_assert( std::ranges::forward_range<CopyableView>);
|
||||
static_assert( std::ranges::forward_range<const CopyableView>);
|
||||
static_assert( std::ranges::view<CopyableView>);
|
||||
static_assert( std::is_copy_constructible_v<CopyableView>);
|
||||
|
||||
// ForwardView
|
||||
|
||||
struct ForwardView : std::ranges::view_base {
|
||||
std::string_view view_;
|
||||
constexpr explicit ForwardView() = default;
|
||||
constexpr ForwardView(const char* ptr) : view_(ptr) {}
|
||||
constexpr ForwardView(std::string_view v) : view_(v) {}
|
||||
constexpr ForwardView(ForwardView&&) = default;
|
||||
constexpr ForwardView& operator=(ForwardView&&) = default;
|
||||
constexpr forward_iterator<const char*> begin() const { return forward_iterator<const char*>(view_.begin()); }
|
||||
constexpr forward_iterator<const char*> end() const { return forward_iterator<const char*>(view_.end()); }
|
||||
};
|
||||
static_assert( std::ranges::forward_range<ForwardView>);
|
||||
static_assert( std::ranges::forward_range<const ForwardView>);
|
||||
static_assert( std::ranges::view<ForwardView>);
|
||||
static_assert(!std::is_copy_constructible_v<ForwardView>);
|
||||
static_assert( std::is_move_constructible_v<ForwardView>);
|
||||
|
||||
// ForwardDiffView
|
||||
|
||||
// Iterator types differ based on constness of this class.
|
||||
struct ForwardDiffView : std::ranges::view_base {
|
||||
SmallString buffer_;
|
||||
constexpr explicit ForwardDiffView() = default;
|
||||
constexpr ForwardDiffView(const char* ptr) : ForwardDiffView(std::string_view(ptr)) {}
|
||||
constexpr ForwardDiffView(std::string_view v) : buffer_(v) {}
|
||||
constexpr ForwardDiffView(ForwardDiffView&&) = default;
|
||||
constexpr ForwardDiffView& operator=(ForwardDiffView&&) = default;
|
||||
constexpr ForwardDiffView(const ForwardDiffView&) = default;
|
||||
constexpr ForwardDiffView& operator=(const ForwardDiffView&) = default;
|
||||
constexpr forward_iterator<char*> begin() { return forward_iterator<char*>(buffer_.begin()); }
|
||||
constexpr forward_iterator<char*> end() { return forward_iterator<char*>(buffer_.end()); }
|
||||
constexpr forward_iterator<const char*> begin() const { return forward_iterator<const char*>(buffer_.begin()); }
|
||||
constexpr forward_iterator<const char*> end() const { return forward_iterator<const char*>(buffer_.end()); }
|
||||
};
|
||||
static_assert( std::ranges::forward_range<ForwardView>);
|
||||
static_assert( std::ranges::forward_range<const ForwardView>);
|
||||
static_assert( std::ranges::view<ForwardView>);
|
||||
static_assert(!std::same_as<std::ranges::iterator_t<ForwardDiffView>, std::ranges::iterator_t<const ForwardDiffView>>);
|
||||
|
||||
// ForwardOnlyIfNonConstView
|
||||
|
||||
template <class It>
|
||||
class almost_forward_iterator {
|
||||
It it_;
|
||||
|
||||
template <class U> friend class almost_forward_iterator;
|
||||
|
||||
public:
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
using value_type = typename std::iterator_traits<It>::value_type;
|
||||
using difference_type = typename std::iterator_traits<It>::difference_type;
|
||||
using pointer = It;
|
||||
using reference = typename std::iterator_traits<It>::reference;
|
||||
|
||||
constexpr almost_forward_iterator() : it_() {}
|
||||
constexpr explicit almost_forward_iterator(It it) : it_(it) {}
|
||||
template <class U>
|
||||
constexpr almost_forward_iterator(const almost_forward_iterator<U>& u) : it_(u.it_) {}
|
||||
|
||||
constexpr reference operator*() const { return *it_; }
|
||||
constexpr pointer operator->() const { return it_; }
|
||||
|
||||
constexpr almost_forward_iterator& operator++() { ++it_; return *this; }
|
||||
// Notice the slightly different return type.
|
||||
constexpr const almost_forward_iterator operator++(int) { return almost_forward_iterator(it_); }
|
||||
|
||||
friend constexpr bool operator==(const almost_forward_iterator& x, const almost_forward_iterator& y) {
|
||||
return x.it_ == y.it_;
|
||||
}
|
||||
friend constexpr bool operator!=(const almost_forward_iterator& x, const almost_forward_iterator& y) {
|
||||
return x.it_ != y.it_;
|
||||
}
|
||||
};
|
||||
static_assert(!std::forward_iterator<almost_forward_iterator<int*>>);
|
||||
static_assert( std::input_iterator<almost_forward_iterator<int*>>);
|
||||
|
||||
struct ForwardOnlyIfNonConstView : std::ranges::view_base {
|
||||
std::string_view view_;
|
||||
|
||||
constexpr explicit ForwardOnlyIfNonConstView() = default;
|
||||
constexpr ForwardOnlyIfNonConstView(const char* ptr) : view_(ptr) {}
|
||||
constexpr ForwardOnlyIfNonConstView(std::string_view v) : view_(v) {}
|
||||
constexpr ForwardOnlyIfNonConstView(ForwardOnlyIfNonConstView&&) = default;
|
||||
constexpr ForwardOnlyIfNonConstView& operator=(ForwardOnlyIfNonConstView&&) = default;
|
||||
|
||||
constexpr forward_iterator<const char*> begin() { return forward_iterator<const char*>(view_.begin()); }
|
||||
constexpr forward_iterator<const char*> end() { return forward_iterator<const char*>(view_.end()); }
|
||||
constexpr almost_forward_iterator<const char*> begin() const {
|
||||
return almost_forward_iterator<const char*>(view_.begin());
|
||||
}
|
||||
constexpr almost_forward_iterator<const char*> end() const {
|
||||
return almost_forward_iterator<const char*>(view_.end());
|
||||
}
|
||||
};
|
||||
static_assert( std::ranges::forward_range<ForwardOnlyIfNonConstView>);
|
||||
static_assert(!std::ranges::forward_range<const ForwardOnlyIfNonConstView>);
|
||||
static_assert( std::ranges::view<ForwardOnlyIfNonConstView>);
|
||||
|
||||
// InputView
|
||||
|
||||
struct InputView : std::ranges::view_base {
|
||||
SmallString buffer_;
|
||||
|
||||
constexpr InputView() = default;
|
||||
constexpr InputView(const char* s) : InputView(std::string_view(s)) {}
|
||||
constexpr InputView(std::string_view v) : buffer_(v) {}
|
||||
|
||||
constexpr cpp20_input_iterator<char*> begin() { return cpp20_input_iterator<char*>(buffer_.begin()); }
|
||||
constexpr sentinel_wrapper<cpp20_input_iterator<char*>> end() {
|
||||
return sentinel_wrapper(cpp20_input_iterator<char*>(buffer_.end()));
|
||||
}
|
||||
constexpr cpp20_input_iterator<const char*> begin() const {
|
||||
return cpp20_input_iterator<const char*>(buffer_.begin());
|
||||
}
|
||||
constexpr sentinel_wrapper<cpp20_input_iterator<const char*>> end() const {
|
||||
return sentinel_wrapper(cpp20_input_iterator<const char*>(buffer_.end()));
|
||||
}
|
||||
};
|
||||
|
||||
static_assert(std::ranges::input_range<InputView>);
|
||||
static_assert(std::ranges::input_range<const InputView>);
|
||||
static_assert(std::ranges::view<InputView>);
|
||||
|
||||
// ForwardTinyView
|
||||
|
||||
struct ForwardTinyView : std::ranges::view_base {
|
||||
char c_[1] = {};
|
||||
constexpr ForwardTinyView() = default;
|
||||
constexpr ForwardTinyView(char c) { *c_ = c; }
|
||||
constexpr forward_iterator<const char*> begin() const { return forward_iterator<const char*>(c_); }
|
||||
constexpr forward_iterator<const char*> end() const { return forward_iterator<const char*>(c_ + 1); }
|
||||
constexpr static size_t size() { return 1; }
|
||||
};
|
||||
static_assert(std::ranges::forward_range<ForwardTinyView>);
|
||||
static_assert(std::ranges::view<ForwardTinyView>);
|
||||
LIBCPP_STATIC_ASSERT(std::ranges::__tiny_range<ForwardTinyView>);
|
||||
|
||||
// Aliases
|
||||
|
||||
using SplitViewCopyable = std::ranges::lazy_split_view<CopyableView, CopyableView>;
|
||||
using OuterIterCopyable = std::ranges::iterator_t<SplitViewCopyable>;
|
||||
using ValueTypeCopyable = OuterIterCopyable::value_type;
|
||||
using InnerIterCopyable = std::ranges::iterator_t<ValueTypeCopyable>;
|
||||
using BaseIterCopyable = std::ranges::iterator_t<CopyableView>;
|
||||
|
||||
using SplitViewForward = std::ranges::lazy_split_view<ForwardView, ForwardView>;
|
||||
using OuterIterForward = std::ranges::iterator_t<SplitViewForward>;
|
||||
using ValueTypeForward = OuterIterForward::value_type;
|
||||
using InnerIterForward = std::ranges::iterator_t<ValueTypeForward>;
|
||||
using BaseIterForward = std::ranges::iterator_t<ForwardView>;
|
||||
|
||||
using SplitViewInput = std::ranges::lazy_split_view<InputView, ForwardTinyView>;
|
||||
using OuterIterInput = std::ranges::iterator_t<SplitViewInput>;
|
||||
using ValueTypeInput = OuterIterInput::value_type;
|
||||
using InnerIterInput = std::ranges::iterator_t<ValueTypeInput>;
|
||||
using BaseIterInput = std::ranges::iterator_t<InputView>;
|
||||
|
||||
using SplitViewDiff = std::ranges::lazy_split_view<ForwardDiffView, ForwardDiffView>;
|
||||
using OuterIterConst = decltype(std::declval<const SplitViewDiff>().begin());
|
||||
using OuterIterNonConst = decltype(std::declval<SplitViewDiff>().begin());
|
||||
static_assert(!std::same_as<OuterIterConst, OuterIterNonConst>);
|
||||
using InnerIterConst = decltype((*std::declval<OuterIterConst>()).begin());
|
||||
using InnerIterNonConst = decltype((*std::declval<OuterIterNonConst>()).begin());
|
||||
static_assert(!std::same_as<InnerIterConst, InnerIterNonConst>);
|
||||
|
||||
#endif // TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_LAZY_SPLIT_TYPES_H
|
|
@ -0,0 +1,73 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||
// UNSUPPORTED: libcpp-has-no-incomplete-ranges
|
||||
|
||||
// class std::ranges::lazy_split_view;
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include <cassert>
|
||||
#include <concepts>
|
||||
#include <string_view>
|
||||
#include <type_traits>
|
||||
#include "types.h"
|
||||
|
||||
using V = SplitViewForward;
|
||||
|
||||
static_assert(std::is_base_of_v<std::ranges::view_interface<SplitViewForward>, SplitViewForward>);
|
||||
|
||||
constexpr bool test() {
|
||||
using namespace std::string_view_literals;
|
||||
|
||||
// empty()
|
||||
{
|
||||
{
|
||||
std::ranges::lazy_split_view v("abc def", " ");
|
||||
assert(!v.empty());
|
||||
}
|
||||
|
||||
{
|
||||
// Note: an empty string literal would still produce a non-empty output because the terminating zero is treated as
|
||||
// a separate character; hence the use of `string_view`.
|
||||
std::ranges::lazy_split_view v(""sv, "");
|
||||
assert(v.empty());
|
||||
}
|
||||
}
|
||||
|
||||
// operator bool()
|
||||
{
|
||||
{
|
||||
std::ranges::lazy_split_view v("abc", "");
|
||||
assert(v);
|
||||
}
|
||||
|
||||
{
|
||||
// Note: an empty string literal would still produce a non-empty output because the terminating zero is treated as
|
||||
// a separate character; hence the use of `string_view`.
|
||||
std::ranges::lazy_split_view v(""sv, "");
|
||||
assert(!v);
|
||||
}
|
||||
}
|
||||
|
||||
// front()
|
||||
{
|
||||
SplitViewForward v("abc", "");
|
||||
assert(*(v.front()).begin() == 'a');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -506,6 +506,7 @@ public:
|
|||
template <class T>
|
||||
void operator,(T const &) = delete;
|
||||
};
|
||||
static_assert(std::input_iterator<cpp20_input_iterator<int*>>);
|
||||
|
||||
template<std::input_or_output_iterator>
|
||||
struct iter_value_or_void { using type = void; };
|
||||
|
|
Loading…
Reference in New Issue