11// / @file trailing_view.hpp
2- #include < iterator> // std::iterator_traits
2+ #include < concepts> // std::semiregular
3+ #include < iterator> // std::iterator_traits, std::unreachable_sentinel_t
34#include < ranges>
45#include < type_traits>
56#include < utility>
67
78namespace strtpl {
8- template <std::ranges::input_range View>
9+ template <class T , class U >
10+ concept different_from = !std::same_as<std::remove_cvref_t <T>, std::remove_cvref_t <U>>;
11+
12+ // clang-format off
13+ template <std::ranges::input_range View, std::semiregular Bound = std::unreachable_sentinel_t >
914 requires std::ranges::view<View>
10- struct trailing_view : std::ranges::view_interface<trailing_view<View>> {
15+ and (std::convertible_to<Bound, std::ranges::range_difference_t <View>> or std::same_as<Bound, std::unreachable_sentinel_t >)
16+ struct trailing_view : std::ranges::view_interface<trailing_view<View, Bound>> {
17+ // clang-format on
1118 private:
1219 [[no_unique_address]] View base_ = View();
13- std::ranges:: range_difference_t <View> count_ = 0 ;
20+ Bound bound_ = Bound() ;
1421
1522 template <bool Const>
1623 class iterator ;
1724
1825 public:
1926 trailing_view () requires std::default_initializable<View>
2027 = default ;
21- constexpr trailing_view (View base, std::ranges::range_difference_t <View> count)
22- : base_(std::move(base)), count_(std::move(count)) {
23- assert (count_ >= 0 );
28+ constexpr trailing_view (View base) : base_(std::move(base)) {}
29+ constexpr trailing_view (View base, Bound bound)
30+ : base_(std::move(base)), bound_(std::move(bound)) {
31+ assert (bound_ >= 0 );
2432 }
2533
2634 constexpr View
@@ -31,9 +39,9 @@ namespace strtpl {
3139 base () && {
3240 return std::move (base_);
3341 }
34- constexpr std::ranges:: range_difference_t <View>
42+ constexpr Bound
3543 count () const noexcept {
36- return count_ ;
44+ return bound_ ;
3745 }
3846
3947 constexpr iterator<false >
@@ -50,37 +58,43 @@ namespace strtpl {
5058 return std::default_sentinel;
5159 }
5260 constexpr iterator<false >
53- end () requires std::ranges::common_range<View> {
54- return {*this , std::ranges::end (base_), count_};
61+ end () requires
62+ std::ranges::common_range<View> and different_from<Bound, std::unreachable_sentinel_t > {
63+ return {*this , std::ranges::end (base_), bound_};
5564 }
5665 constexpr auto
5766 end () const requires std::ranges::input_range<const View> {
5867 return std::default_sentinel;
5968 }
6069 constexpr iterator<true >
61- end () const requires
62- std::ranges::input_range< const View> and std::ranges::common_range< const View > {
63- return {*this , std::ranges::end (base_), count_ };
70+ end () const requires std::ranges::input_range< const View> and std::ranges::common_range<
71+ const View> and different_from<Bound, std::unreachable_sentinel_t > {
72+ return {*this , std::ranges::end (base_), bound_ };
6473 }
6574
6675 constexpr auto
67- size () requires std::ranges::sized_range<View> {
68- return std::ranges::empty (base_)
69- ? 0
70- : std::ranges::size (base_) + static_cast <std::ranges::range_size_t <View>>(count_)
71- - 1 ;
76+ size () requires
77+ std::ranges::sized_range<View> and different_from<Bound, std::unreachable_sentinel_t > {
78+ using Size = std::ranges::range_size_t <View>;
79+ if (std::ranges::empty (base_))
80+ return static_cast <Size>(0 );
81+ return std::ranges::size (base_) + static_cast <Size>(bound_) - 1 ;
7282 }
7383 constexpr auto
74- size () const requires std::ranges::sized_range<const View> {
75- return std::ranges::empty (base_)
76- ? 0
77- : std::ranges::size (base_)
78- + static_cast <std::ranges::range_size_t <const View>>(count_) - 1 ;
84+ size () const requires
85+ std::ranges::sized_range<const View> and different_from<Bound, std::unreachable_sentinel_t > {
86+ using Size = std::ranges::range_size_t <const View>;
87+ if (std::ranges::empty (base_))
88+ return static_cast <Size>(0 );
89+ return std::ranges::size (base_) + static_cast <Size>(bound_) - 1 ;
7990 }
8091 };
8192
82- template <class Range , class DifferenceType >
83- trailing_view (Range&&, DifferenceType) -> trailing_view<std::views::all_t <Range>>;
93+ template <class Range >
94+ trailing_view (Range&&) -> trailing_view<std::views::all_t <Range>>;
95+
96+ template <class Range , class Bound >
97+ trailing_view (Range&&, Bound) -> trailing_view<std::views::all_t <Range>, Bound>;
8498
8599 template <class View >
86100 struct trailing_iterator_category {};
@@ -96,11 +110,14 @@ namespace strtpl {
96110 // clang-format on
97111 };
98112
99- template <std::ranges::input_range View>
113+ // clang-format off
114+ template <std::ranges::input_range View, std::semiregular Bound>
100115 requires std::ranges::view<View>
116+ and (std::convertible_to<Bound, std::ranges::range_difference_t <View>> or std::same_as<Bound, std::unreachable_sentinel_t >)
101117 template <bool Const>
102- struct trailing_view <View>::iterator
118+ struct trailing_view <View, Bound >::iterator
103119 : trailing_iterator_category<std::conditional_t <Const, const View, View>> {
120+ // clang-format on
104121 private:
105122 using Parent = std::conditional_t <Const, const trailing_view, trailing_view>;
106123 using Base = std::conditional_t <Const, const View, View>;
@@ -112,8 +129,9 @@ namespace strtpl {
112129
113130 constexpr bool
114131 accessible () const noexcept {
115- return next_ != std::ranges::end (parent_->base ())
116- or (not std::ranges::empty (parent_->base ()) and ncount_ < parent_->count ());
132+ if (std::ranges::empty (parent_->base ()))
133+ return false ;
134+ return next_ != std::ranges::end (parent_->base ()) or ncount_ != parent_->count ();
117135 }
118136
119137 public:
@@ -203,14 +221,16 @@ namespace strtpl {
203221 friend constexpr bool
204222 operator ==(const iterator& x,
205223 const iterator& y) requires std::equality_comparable<std::ranges::iterator_t <Base>> {
206- return x.next_ == y.next_
207- and (std::ranges::empty (x.parent_ ->base ()) or x.ncount_ == y.ncount_ );
224+ if (std::ranges::empty (x.parent_ ->base ()) and std::ranges::empty (y.parent_ ->base ()))
225+ return true ;
226+ return x.next_ == y.next_ and x.ncount_ == y.ncount_ ;
208227 }
209228 friend constexpr bool
210229 operator ==(const iterator& x, std::default_sentinel_t ) requires
211230 std::equality_comparable<std::ranges::iterator_t <Base>> {
212- return x.next_ == std::ranges::end (x.parent_ ->base ())
213- and (std::ranges::empty (x.parent_ ->base ()) or x.ncount_ == x.parent_ ->count ());
231+ if (std::ranges::empty (x.parent_ ->base ()))
232+ return true ;
233+ return x.next_ == std::ranges::end (x.parent_ ->base ()) and x.ncount_ == x.parent_ ->count ();
214234 }
215235
216236 friend constexpr std::pair<std::ranges::range_rvalue_reference_t <Base>,
0 commit comments