1// -*- C++ -*-
2//===----------------------------------------------------------------------===//
3//
4// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5// See https://llvm.org/LICENSE.txt for license information.
6// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7//
8//===----------------------------------------------------------------------===//
9
10#ifndef _LIBCPP___RANGES_VIEW_INTERFACE_H
11#define _LIBCPP___RANGES_VIEW_INTERFACE_H
12
13#include <__assert>
14#include <__concepts/derived_from.h>
15#include <__concepts/same_as.h>
16#include <__config>
17#include <__iterator/concepts.h>
18#include <__iterator/distance.h>
19#include <__iterator/iterator_traits.h>
20#include <__iterator/prev.h>
21#include <__memory/pointer_traits.h>
22#include <__ranges/access.h>
23#include <__ranges/concepts.h>
24#include <__ranges/empty.h>
25#include <__ranges/size.h>
26#include <__type_traits/is_class.h>
27#include <__type_traits/make_unsigned.h>
28#include <__type_traits/remove_cv.h>
29#include <stdexcept>
30
31#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
32# pragma GCC system_header
33#endif
34
35#if _LIBCPP_STD_VER >= 20
36
37_LIBCPP_BEGIN_NAMESPACE_STD
38
39namespace ranges {
40
41template <class _Derived>
42 requires is_class_v<_Derived> && same_as<_Derived, remove_cv_t<_Derived>>
43class view_interface {
44 _LIBCPP_HIDE_FROM_ABI constexpr _Derived& __derived() noexcept {
45 static_assert(sizeof(_Derived) && derived_from<_Derived, view_interface> && view<_Derived>);
46 return static_cast<_Derived&>(*this);
47 }
48
49 _LIBCPP_HIDE_FROM_ABI constexpr _Derived const& __derived() const noexcept {
50 static_assert(sizeof(_Derived) && derived_from<_Derived, view_interface> && view<_Derived>);
51 return static_cast<_Derived const&>(*this);
52 }
53
54public:
55 template <class _D2 = _Derived>
56 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool empty()
57 requires sized_range<_D2> || forward_range<_D2>
58 {
59 if constexpr (sized_range<_D2>) {
60 return ranges::size(__derived()) == 0;
61 } else {
62 return ranges::begin(__derived()) == ranges::end(__derived());
63 }
64 }
65
66 template <class _D2 = _Derived>
67 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool empty() const
68 requires sized_range<const _D2> || forward_range<const _D2>
69 {
70 if constexpr (sized_range<const _D2>) {
71 return ranges::size(__derived()) == 0;
72 } else {
73 return ranges::begin(__derived()) == ranges::end(__derived());
74 }
75 }
76
77 template <class _D2 = _Derived>
78 _LIBCPP_HIDE_FROM_ABI constexpr explicit operator bool()
79 requires requires(_D2& __t) { ranges::empty(__t); }
80 {
81 return !ranges::empty(__derived());
82 }
83
84 template <class _D2 = _Derived>
85 _LIBCPP_HIDE_FROM_ABI constexpr explicit operator bool() const
86 requires requires(const _D2& __t) { ranges::empty(__t); }
87 {
88 return !ranges::empty(__derived());
89 }
90
91 template <class _D2 = _Derived>
92 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto data()
93 requires contiguous_iterator<iterator_t<_D2>>
94 {
95 return std::to_address(ranges::begin(__derived()));
96 }
97
98 template <class _D2 = _Derived>
99 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto data() const
100 requires range<const _D2> && contiguous_iterator<iterator_t<const _D2>>
101 {
102 return std::to_address(ranges::begin(__derived()));
103 }
104
105 template <class _D2 = _Derived>
106 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto size()
107 requires forward_range<_D2> && sized_sentinel_for<sentinel_t<_D2>, iterator_t<_D2>>
108 {
109 return std::__to_unsigned_like(ranges::end(__derived()) - ranges::begin(__derived()));
110 }
111
112 template <class _D2 = _Derived>
113 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto size() const
114 requires forward_range<const _D2> && sized_sentinel_for<sentinel_t<const _D2>, iterator_t<const _D2>>
115 {
116 return std::__to_unsigned_like(ranges::end(__derived()) - ranges::begin(__derived()));
117 }
118
119 template <class _D2 = _Derived>
120 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) front()
121 requires forward_range<_D2>
122 {
123 _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
124 !empty(), "Precondition `!empty()` not satisfied. `.front()` called on an empty view.");
125 return *ranges::begin(__derived());
126 }
127
128 template <class _D2 = _Derived>
129 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) front() const
130 requires forward_range<const _D2>
131 {
132 _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
133 !empty(), "Precondition `!empty()` not satisfied. `.front()` called on an empty view.");
134 return *ranges::begin(__derived());
135 }
136
137 template <class _D2 = _Derived>
138 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) back()
139 requires bidirectional_range<_D2> && common_range<_D2>
140 {
141 _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
142 !empty(), "Precondition `!empty()` not satisfied. `.back()` called on an empty view.");
143 return *ranges::prev(ranges::end(__derived()));
144 }
145
146 template <class _D2 = _Derived>
147 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) back() const
148 requires bidirectional_range<const _D2> && common_range<const _D2>
149 {
150 _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
151 !empty(), "Precondition `!empty()` not satisfied. `.back()` called on an empty view.");
152 return *ranges::prev(ranges::end(__derived()));
153 }
154
155 template <random_access_range _RARange = _Derived>
156 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) operator[](range_difference_t<_RARange> __index) {
157 return ranges::begin(__derived())[__index];
158 }
159
160 template <random_access_range _RARange = const _Derived>
161 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) operator[](range_difference_t<_RARange> __index) const {
162 return ranges::begin(__derived())[__index];
163 }
164
165# if _LIBCPP_STD_VER >= 29
166
167 template <random_access_range _RARange = _Derived>
168 requires sized_range<_RARange>
169 [[nodiscard]] constexpr decltype(auto) at(range_difference_t<_RARange> __index) {
170 if (__index < 0 || __index >= ranges::distance(__derived())) {
171 std::__throw_out_of_range("The index passed to `view_interface::at()` is out of bounds.");
172 }
173 return (*this)[__index];
174 }
175
176 template <random_access_range _RARange = const _Derived>
177 requires sized_range<_RARange>
178 [[nodiscard]] constexpr decltype(auto) at(range_difference_t<_RARange> __index) const {
179 if (__index < 0 || __index >= ranges::distance(__derived())) {
180 std::__throw_out_of_range("The index passed to `view_interface::at()` is out of bounds.");
181 }
182 return (*this)[__index];
183 }
184
185# endif // _LIBCPP_STD_VER >= 29
186};
187
188} // namespace ranges
189
190_LIBCPP_END_NAMESPACE_STD
191
192#endif // _LIBCPP_STD_VER >= 20
193
194#endif // _LIBCPP___RANGES_VIEW_INTERFACE_H
195