2 //===----------------------------------------------------------------------===//
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
8 //===----------------------------------------------------------------------===//
10 #ifndef _LIBCPP___ITERATOR_BOUNDED_ITER_H
11 #define _LIBCPP___ITERATOR_BOUNDED_ITER_H
15 #include <__iterator/iterator_traits.h>
16 #include <__memory/pointer_traits.h>
17 #include <__type_traits/enable_if.h>
18 #include <__type_traits/integral_constant.h>
19 #include <__type_traits/is_convertible.h>
20 #include <__utility/move.h>
22 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
23 # pragma GCC system_header
27 #include <__undef_macros>
29 _LIBCPP_BEGIN_NAMESPACE_STD
31 // Iterator wrapper that carries the valid range it is allowed to access.
33 // This is a simple iterator wrapper for contiguous iterators that points
34 // within a [begin, end) range and carries these bounds with it. The iterator
35 // ensures that it is pointing within that [begin, end) range when it is
38 // Arithmetic operations are allowed and the bounds of the resulting iterator
39 // are not checked. Hence, it is possible to create an iterator pointing outside
40 // its range, but it is not possible to dereference it.
41 template <class _Iterator
, class = __enable_if_t
< __libcpp_is_contiguous_iterator
<_Iterator
>::value
> >
42 struct __bounded_iter
{
43 using value_type
= typename iterator_traits
<_Iterator
>::value_type
;
44 using difference_type
= typename iterator_traits
<_Iterator
>::difference_type
;
45 using pointer
= typename iterator_traits
<_Iterator
>::pointer
;
46 using reference
= typename iterator_traits
<_Iterator
>::reference
;
47 using iterator_category
= typename iterator_traits
<_Iterator
>::iterator_category
;
48 #if _LIBCPP_STD_VER >= 20
49 using iterator_concept
= contiguous_iterator_tag
;
52 // Create a singular iterator.
54 // Such an iterator does not point to any object and is conceptually out of bounds, so it is
55 // not dereferenceable. Observing operations like comparison and assignment are valid.
56 _LIBCPP_HIDE_FROM_ABI
__bounded_iter() = default;
58 _LIBCPP_HIDE_FROM_ABI
__bounded_iter(__bounded_iter
const&) = default;
59 _LIBCPP_HIDE_FROM_ABI
__bounded_iter(__bounded_iter
&&) = default;
61 template <class _OtherIterator
, class = __enable_if_t
< is_convertible
<_OtherIterator
, _Iterator
>::value
> >
62 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR
__bounded_iter(__bounded_iter
<_OtherIterator
> const& __other
) _NOEXCEPT
63 : __current_(__other
.__current_
),
64 __begin_(__other
.__begin_
),
65 __end_(__other
.__end_
) {}
67 // Assign a bounded iterator to another one, rebinding the bounds of the iterator as well.
68 _LIBCPP_HIDE_FROM_ABI __bounded_iter
& operator=(__bounded_iter
const&) = default;
69 _LIBCPP_HIDE_FROM_ABI __bounded_iter
& operator=(__bounded_iter
&&) = default;
72 // Create an iterator wrapping the given iterator, and whose bounds are described
73 // by the provided [begin, end) range.
75 // This constructor does not check whether the resulting iterator is within its bounds.
76 // However, it does check that the provided [begin, end) range is a valid range (that
79 // Since it is non-standard for iterators to have this constructor, __bounded_iter must
80 // be created via `std::__make_bounded_iter`.
81 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14
explicit __bounded_iter(
82 _Iterator __current
, _Iterator __begin
, _Iterator __end
)
83 : __current_(__current
), __begin_(__begin
), __end_(__end
) {
84 _LIBCPP_ASSERT_INTERNAL(__begin
<= __end
, "__bounded_iter(current, begin, end): [begin, end) is not a valid range");
88 friend _LIBCPP_CONSTEXPR __bounded_iter
<_It
> __make_bounded_iter(_It
, _It
, _It
);
91 // Dereference and indexing operations.
93 // These operations check that the iterator is dereferenceable, that is within [begin, end).
94 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 reference
operator*() const _NOEXCEPT
{
95 _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
96 __in_bounds(__current_
), "__bounded_iter::operator*: Attempt to dereference an out-of-range iterator");
100 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pointer
operator->() const _NOEXCEPT
{
101 _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
102 __in_bounds(__current_
), "__bounded_iter::operator->: Attempt to dereference an out-of-range iterator");
103 return std::__to_address(__current_
);
106 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 reference
operator[](difference_type __n
) const _NOEXCEPT
{
107 _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
108 __in_bounds(__current_
+ __n
), "__bounded_iter::operator[]: Attempt to index an iterator out-of-range");
109 return __current_
[__n
];
112 // Arithmetic operations.
114 // These operations do not check that the resulting iterator is within the bounds, since that
115 // would make it impossible to create a past-the-end iterator.
116 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 __bounded_iter
& operator++() _NOEXCEPT
{
120 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 __bounded_iter
operator++(int) _NOEXCEPT
{
121 __bounded_iter
__tmp(*this);
126 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 __bounded_iter
& operator--() _NOEXCEPT
{
130 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 __bounded_iter
operator--(int) _NOEXCEPT
{
131 __bounded_iter
__tmp(*this);
136 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 __bounded_iter
& operator+=(difference_type __n
) _NOEXCEPT
{
140 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14
friend __bounded_iter
141 operator+(__bounded_iter
const& __self
, difference_type __n
) _NOEXCEPT
{
142 __bounded_iter
__tmp(__self
);
146 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14
friend __bounded_iter
147 operator+(difference_type __n
, __bounded_iter
const& __self
) _NOEXCEPT
{
148 __bounded_iter
__tmp(__self
);
153 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 __bounded_iter
& operator-=(difference_type __n
) _NOEXCEPT
{
157 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14
friend __bounded_iter
158 operator-(__bounded_iter
const& __self
, difference_type __n
) _NOEXCEPT
{
159 __bounded_iter
__tmp(__self
);
163 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14
friend difference_type
164 operator-(__bounded_iter
const& __x
, __bounded_iter
const& __y
) _NOEXCEPT
{
165 return __x
.__current_
- __y
.__current_
;
168 // Comparison operations.
170 // These operations do not check whether the iterators are within their bounds.
171 // The valid range for each iterator is also not considered as part of the comparison,
172 // i.e. two iterators pointing to the same location will be considered equal even
173 // if they have different validity ranges.
174 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR
friend bool
175 operator==(__bounded_iter
const& __x
, __bounded_iter
const& __y
) _NOEXCEPT
{
176 return __x
.__current_
== __y
.__current_
;
178 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR
friend bool
179 operator!=(__bounded_iter
const& __x
, __bounded_iter
const& __y
) _NOEXCEPT
{
180 return __x
.__current_
!= __y
.__current_
;
182 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR
friend bool
183 operator<(__bounded_iter
const& __x
, __bounded_iter
const& __y
) _NOEXCEPT
{
184 return __x
.__current_
< __y
.__current_
;
186 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR
friend bool
187 operator>(__bounded_iter
const& __x
, __bounded_iter
const& __y
) _NOEXCEPT
{
188 return __x
.__current_
> __y
.__current_
;
190 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR
friend bool
191 operator<=(__bounded_iter
const& __x
, __bounded_iter
const& __y
) _NOEXCEPT
{
192 return __x
.__current_
<= __y
.__current_
;
194 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR
friend bool
195 operator>=(__bounded_iter
const& __x
, __bounded_iter
const& __y
) _NOEXCEPT
{
196 return __x
.__current_
>= __y
.__current_
;
200 // Return whether the given iterator is in the bounds of this __bounded_iter.
201 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR
bool __in_bounds(_Iterator
const& __iter
) const {
202 return __iter
>= __begin_
&& __iter
< __end_
;
206 friend struct pointer_traits
;
207 _Iterator __current_
; // current iterator
208 _Iterator __begin_
, __end_
; // valid range represented as [begin, end)
212 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR __bounded_iter
<_It
> __make_bounded_iter(_It __it
, _It __begin
, _It __end
) {
213 return __bounded_iter
<_It
>(std::move(__it
), std::move(__begin
), std::move(__end
));
216 #if _LIBCPP_STD_VER <= 17
217 template <class _Iterator
>
218 struct __libcpp_is_contiguous_iterator
<__bounded_iter
<_Iterator
> > : true_type
{};
221 template <class _Iterator
>
222 struct pointer_traits
<__bounded_iter
<_Iterator
> > {
223 using pointer
= __bounded_iter
<_Iterator
>;
224 using element_type
= typename pointer_traits
<_Iterator
>::element_type
;
225 using difference_type
= typename pointer_traits
<_Iterator
>::difference_type
;
227 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR
static element_type
* to_address(pointer __it
) _NOEXCEPT
{
228 return std::__to_address(__it
.__current_
);
232 _LIBCPP_END_NAMESPACE_STD
236 #endif // _LIBCPP___ITERATOR_BOUNDED_ITER_H