xref: /freebsd/contrib/llvm-project/libcxx/include/__ranges/view_interface.h (revision 5956d97f4b3204318ceb6aa9c77bd0bc6ea87a41)
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 #ifndef _LIBCPP___RANGES_VIEW_INTERFACE_H
10 #define _LIBCPP___RANGES_VIEW_INTERFACE_H
11 
12 #include <__config>
13 #include <__debug>
14 #include <__iterator/concepts.h>
15 #include <__iterator/iterator_traits.h>
16 #include <__iterator/prev.h>
17 #include <__memory/pointer_traits.h>
18 #include <__ranges/access.h>
19 #include <__ranges/concepts.h>
20 #include <__ranges/empty.h>
21 #include <concepts>
22 #include <type_traits>
23 
24 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
25 #pragma GCC system_header
26 #endif
27 
28 _LIBCPP_BEGIN_NAMESPACE_STD
29 
30 #if !defined(_LIBCPP_HAS_NO_CONCEPTS) && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES)
31 
32 namespace ranges {
33 
34 template<class _Tp>
35 concept __can_empty = requires(_Tp __t) { ranges::empty(__t); };
36 
37 template<class _Tp>
38 void __implicitly_convert_to(type_identity_t<_Tp>) noexcept;
39 
40 template<class _Derived>
41   requires is_class_v<_Derived> && same_as<_Derived, remove_cv_t<_Derived>>
42 class view_interface {
43   _LIBCPP_HIDE_FROM_ABI
44   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
50   constexpr _Derived const& __derived() const noexcept {
51     static_assert(sizeof(_Derived) && derived_from<_Derived, view_interface> && view<_Derived>);
52     return static_cast<_Derived const&>(*this);
53   }
54 
55 public:
56   template<class _D2 = _Derived>
57   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool empty()
58     noexcept(noexcept(__implicitly_convert_to<bool>(ranges::begin(__derived()) == ranges::end(__derived()))))
59     requires forward_range<_D2>
60   {
61     return ranges::begin(__derived()) == ranges::end(__derived());
62   }
63 
64   template<class _D2 = _Derived>
65   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool empty() const
66     noexcept(noexcept(__implicitly_convert_to<bool>(ranges::begin(__derived()) == ranges::end(__derived()))))
67     requires forward_range<const _D2>
68   {
69     return ranges::begin(__derived()) == ranges::end(__derived());
70   }
71 
72   template<class _D2 = _Derived>
73   _LIBCPP_HIDE_FROM_ABI
74   constexpr explicit operator bool()
75     noexcept(noexcept(ranges::empty(declval<_D2>())))
76     requires __can_empty<_D2>
77   {
78     return !ranges::empty(__derived());
79   }
80 
81   template<class _D2 = _Derived>
82   _LIBCPP_HIDE_FROM_ABI
83   constexpr explicit operator bool() const
84     noexcept(noexcept(ranges::empty(declval<const _D2>())))
85     requires __can_empty<const _D2>
86   {
87     return !ranges::empty(__derived());
88   }
89 
90   template<class _D2 = _Derived>
91   _LIBCPP_HIDE_FROM_ABI
92   constexpr auto data()
93     noexcept(noexcept(_VSTD::to_address(ranges::begin(__derived()))))
94     requires contiguous_iterator<iterator_t<_D2>>
95   {
96     return _VSTD::to_address(ranges::begin(__derived()));
97   }
98 
99   template<class _D2 = _Derived>
100   _LIBCPP_HIDE_FROM_ABI
101   constexpr auto data() const
102     noexcept(noexcept(_VSTD::to_address(ranges::begin(__derived()))))
103     requires range<const _D2> && contiguous_iterator<iterator_t<const _D2>>
104   {
105     return _VSTD::to_address(ranges::begin(__derived()));
106   }
107 
108   template<class _D2 = _Derived>
109   _LIBCPP_HIDE_FROM_ABI
110   constexpr auto size()
111     noexcept(noexcept(ranges::end(__derived()) - ranges::begin(__derived())))
112     requires forward_range<_D2>
113       && sized_sentinel_for<sentinel_t<_D2>, iterator_t<_D2>>
114   {
115     return ranges::end(__derived()) - ranges::begin(__derived());
116   }
117 
118   template<class _D2 = _Derived>
119   _LIBCPP_HIDE_FROM_ABI
120   constexpr auto size() const
121     noexcept(noexcept(ranges::end(__derived()) - ranges::begin(__derived())))
122     requires forward_range<const _D2>
123       && sized_sentinel_for<sentinel_t<const _D2>, iterator_t<const _D2>>
124   {
125     return ranges::end(__derived()) - ranges::begin(__derived());
126   }
127 
128   template<class _D2 = _Derived>
129   _LIBCPP_HIDE_FROM_ABI
130   constexpr decltype(auto) front()
131     noexcept(noexcept(*ranges::begin(__derived())))
132     requires forward_range<_D2>
133   {
134     _LIBCPP_ASSERT(!empty(),
135         "Precondition `!empty()` not satisfied. `.front()` called on an empty view.");
136     return *ranges::begin(__derived());
137   }
138 
139   template<class _D2 = _Derived>
140   _LIBCPP_HIDE_FROM_ABI
141   constexpr decltype(auto) front() const
142     noexcept(noexcept(*ranges::begin(__derived())))
143     requires forward_range<const _D2>
144   {
145     _LIBCPP_ASSERT(!empty(),
146         "Precondition `!empty()` not satisfied. `.front()` called on an empty view.");
147     return *ranges::begin(__derived());
148   }
149 
150   template<class _D2 = _Derived>
151   _LIBCPP_HIDE_FROM_ABI
152   constexpr decltype(auto) back()
153     noexcept(noexcept(*ranges::prev(ranges::end(__derived()))))
154     requires bidirectional_range<_D2> && common_range<_D2>
155   {
156     _LIBCPP_ASSERT(!empty(),
157         "Precondition `!empty()` not satisfied. `.back()` called on an empty view.");
158     return *ranges::prev(ranges::end(__derived()));
159   }
160 
161   template<class _D2 = _Derived>
162   _LIBCPP_HIDE_FROM_ABI
163   constexpr decltype(auto) back() const
164     noexcept(noexcept(*ranges::prev(ranges::end(__derived()))))
165     requires bidirectional_range<const _D2> && common_range<const _D2>
166   {
167     _LIBCPP_ASSERT(!empty(),
168         "Precondition `!empty()` not satisfied. `.back()` called on an empty view.");
169     return *ranges::prev(ranges::end(__derived()));
170   }
171 
172   template<random_access_range _RARange = _Derived>
173   _LIBCPP_HIDE_FROM_ABI
174   constexpr decltype(auto) operator[](range_difference_t<_RARange> __index)
175     noexcept(noexcept(ranges::begin(__derived())[__index]))
176   {
177     return ranges::begin(__derived())[__index];
178   }
179 
180   template<random_access_range _RARange = const _Derived>
181   _LIBCPP_HIDE_FROM_ABI
182   constexpr decltype(auto) operator[](range_difference_t<_RARange> __index) const
183     noexcept(noexcept(ranges::begin(__derived())[__index]))
184   {
185     return ranges::begin(__derived())[__index];
186   }
187 };
188 
189 } // namespace ranges
190 
191 #endif // !defined(_LIBCPP_HAS_NO_CONCEPTS) && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES)
192 
193 _LIBCPP_END_NAMESPACE_STD
194 
195 #endif // _LIBCPP___RANGES_VIEW_INTERFACE_H
196