Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions libcxx/include/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -509,6 +509,7 @@ set(files
__iterator/sortable.h
__iterator/static_bounded_iter.h
__iterator/unreachable_sentinel.h
__iterator/upper_bounded_iterator.h
__iterator/wrap_iter.h
__locale
__locale_dir/check_grouping.h
Expand Down
164 changes: 164 additions & 0 deletions libcxx/include/__iterator/upper_bounded_iterator.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
// -*- 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
//
//===----------------------------------------------------------------------===//

/*
* __upper_bounded_iterator is an iterator that wraps an underlying iterator.
* It stores the underlying container type to prevent mixing iterators, and allow algorithms
* to optimize based on the underlying container type.
* It also stores the absolute maximum amount of elements the container can have, known at compile-time.
* As of writing, the only standard library containers which have this property are inplace_vector and optional.
*/

#ifndef _LIBCPP___ITERATOR_UPPER_BOUNDED_ITERATOR_H
#define _LIBCPP___ITERATOR_UPPER_BOUNDED_ITERATOR_H

#include <__compare/three_way_comparable.h>
#include <__config>
#include <__cstddef/size_t.h>
#include <__iterator/incrementable_traits.h>
#include <__iterator/iterator_traits.h>
#include <__memory/pointer_traits.h>
#include <__type_traits/is_constructible.h>
#include <__utility/move.h>

#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
#endif

_LIBCPP_PUSH_MACROS
#include <__undef_macros>

#if _LIBCPP_STD_VER >= 26

_LIBCPP_BEGIN_NAMESPACE_STD

template <class _Iter, class _Container, size_t _Max_Elements>
class __upper_bounded_iterator {
private:
_Iter __iter_;

friend _Container;

public:
using iterator_category = iterator_traits<_Iter>::iterator_category;
using iterator_concept = _Iter::iterator_concept;
using value_type = iter_value_t<_Iter>;
using difference_type = iter_difference_t<_Iter>;
using reference = iter_reference_t<_Iter>;

_LIBCPP_HIDE_FROM_ABI constexpr __upper_bounded_iterator()
requires is_default_constructible_v<_Iter>
= default;

_LIBCPP_HIDE_FROM_ABI constexpr __upper_bounded_iterator(_Iter __iter) : __iter_(std::move(__iter)) {}

_LIBCPP_HIDE_FROM_ABI _Iter __base() const { return __iter_; }
_LIBCPP_HIDE_FROM_ABI constexpr size_t __max_elements() const { return _Max_Elements; }

_LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) operator*() const { return *__iter_; }
_LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) operator->() const { return __iter_.operator->(); }

_LIBCPP_HIDE_FROM_ABI constexpr __upper_bounded_iterator& operator++() {
++__iter_;
return *this;
}

_LIBCPP_HIDE_FROM_ABI constexpr __upper_bounded_iterator operator++(int) {
__upper_bounded_iterator __tmp(*this);
++*this;
return __tmp;
}

_LIBCPP_HIDE_FROM_ABI constexpr __upper_bounded_iterator& operator--() {
--__iter_;
return *this;
}

_LIBCPP_HIDE_FROM_ABI constexpr __upper_bounded_iterator operator--(int) {
__upper_bounded_iterator __tmp(*this);
--*this;
return __tmp;
}

_LIBCPP_HIDE_FROM_ABI constexpr __upper_bounded_iterator& operator+=(difference_type __x) {
__iter_ += __x;
return *this;
}

_LIBCPP_HIDE_FROM_ABI constexpr __upper_bounded_iterator& operator-=(difference_type __x) {
__iter_ -= __x;
return *this;
}

_LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) operator[](difference_type __n) const { return *(*this + __n); }

_LIBCPP_HIDE_FROM_ABI friend constexpr bool
operator==(const __upper_bounded_iterator& __x, const __upper_bounded_iterator& __y) {
return __x.__iter_ == __y.__iter_;
}

_LIBCPP_HIDE_FROM_ABI friend constexpr bool
operator<(const __upper_bounded_iterator& __x, const __upper_bounded_iterator& __y) {
return __x.__iter_ < __y.__iter_;
}

_LIBCPP_HIDE_FROM_ABI friend constexpr bool
operator>(const __upper_bounded_iterator& __x, const __upper_bounded_iterator& __y) {
return __y < __x;
}

_LIBCPP_HIDE_FROM_ABI friend constexpr bool
operator<=(const __upper_bounded_iterator& __x, const __upper_bounded_iterator& __y) {
return !(__y < __x);
}

_LIBCPP_HIDE_FROM_ABI friend constexpr bool
operator>=(const __upper_bounded_iterator& __x, const __upper_bounded_iterator& __y) {
return !(__x < __y);
}

_LIBCPP_HIDE_FROM_ABI friend constexpr auto
operator<=>(const __upper_bounded_iterator& __x, const __upper_bounded_iterator& __y)
requires three_way_comparable<_Iter>
{
return __x.__iter_ <=> __y.__iter_;
}

_LIBCPP_HIDE_FROM_ABI friend constexpr __upper_bounded_iterator
operator+(const __upper_bounded_iterator& __i, difference_type __n) {
auto __tmp = __i;
__tmp += __n;
return __tmp;
}

_LIBCPP_HIDE_FROM_ABI friend constexpr __upper_bounded_iterator
operator+(difference_type __n, const __upper_bounded_iterator& __i) {
return __i + __n;
}

_LIBCPP_HIDE_FROM_ABI friend constexpr __upper_bounded_iterator
operator-(const __upper_bounded_iterator& __i, difference_type __n) {
auto __tmp = __i;
__tmp -= __n;
return __tmp;
}

_LIBCPP_HIDE_FROM_ABI friend constexpr difference_type
operator-(const __upper_bounded_iterator& __x, const __upper_bounded_iterator& __y) {
return __x.__iter_ - __y.__iter_;
}
};

_LIBCPP_END_NAMESPACE_STD

#endif // _LIBCPP_STD_VER >= 26

_LIBCPP_POP_MACROS

#endif // _LIBCPP___ITERATOR_UPPER_BOUNDED_ITERATOR_H
1 change: 1 addition & 0 deletions libcxx/include/module.modulemap.in
Original file line number Diff line number Diff line change
Expand Up @@ -1545,6 +1545,7 @@ module std [system] {
module sortable { header "__iterator/sortable.h" }
module static_bounded_iter { header "__iterator/static_bounded_iter.h" }
module unreachable_sentinel { header "__iterator/unreachable_sentinel.h" }
module upper_bounded_iterator { header "__iterator/upper_bounded_iterator.h" }
module wrap_iter { header "__iterator/wrap_iter.h" }

header "iterator"
Expand Down
16 changes: 7 additions & 9 deletions libcxx/include/optional
Original file line number Diff line number Diff line change
Expand Up @@ -199,14 +199,14 @@ namespace std {
# include <__compare/three_way_comparable.h>
# include <__concepts/invocable.h>
# include <__config>
# include <__cstddef/ptrdiff_t.h>
# include <__exception/exception.h>
# include <__format/range_format.h>
# include <__functional/hash.h>
# include <__functional/invoke.h>
# include <__functional/unary_function.h>
# include <__fwd/functional.h>
# include <__iterator/bounded_iter.h>
# include <__iterator/upper_bounded_iterator.h>
# include <__iterator/wrap_iter.h>
# include <__memory/addressof.h>
# include <__memory/construct_at.h>
Expand All @@ -225,7 +225,6 @@ namespace std {
# include <__type_traits/is_convertible.h>
# include <__type_traits/is_core_convertible.h>
# include <__type_traits/is_destructible.h>
# include <__type_traits/is_function.h>
# include <__type_traits/is_nothrow_assignable.h>
# include <__type_traits/is_nothrow_constructible.h>
# include <__type_traits/is_object.h>
Expand All @@ -238,7 +237,6 @@ namespace std {
# include <__type_traits/is_trivially_constructible.h>
# include <__type_traits/is_trivially_destructible.h>
# include <__type_traits/is_trivially_relocatable.h>
# include <__type_traits/is_unbounded_array.h>
# include <__type_traits/negation.h>
# include <__type_traits/remove_const.h>
# include <__type_traits/remove_cv.h>
Expand Down Expand Up @@ -622,11 +620,11 @@ public:

# if _LIBCPP_STD_VER >= 26
# ifdef _LIBCPP_ABI_BOUNDED_ITERATORS_IN_OPTIONAL
using iterator = __bounded_iter<__wrap_iter<__pointer>>;
using const_iterator = __bounded_iter<__wrap_iter<__const_pointer>>;
using iterator = __upper_bounded_iterator<__bounded_iter<__wrap_iter<__pointer>>, optional, 1>;
using const_iterator = __upper_bounded_iterator<__bounded_iter<__wrap_iter<__const_pointer>>, optional, 1>;
# else
using iterator = __wrap_iter<__pointer>;
using const_iterator = __wrap_iter<__const_pointer>;
using iterator = __upper_bounded_iterator<__wrap_iter<__pointer>, optional, 1>;
using const_iterator = __upper_bounded_iterator<__wrap_iter<__const_pointer>, optional, 1>;
# endif
# endif
using __trivially_relocatable _LIBCPP_NODEBUG =
Expand Down Expand Up @@ -841,7 +839,7 @@ public:
std::__wrap_iter<__pointer>(std::addressof(this->__get())),
std::__wrap_iter<__pointer>(std::addressof(this->__get()) + (this->has_value() ? 1 : 0)));
# else
return iterator(std::addressof(this->__get()));
return iterator(__wrap_iter<__pointer>(std::addressof(this->__get())));
# endif
}

Expand All @@ -852,7 +850,7 @@ public:
std::__wrap_iter<__const_pointer>(std::addressof(this->__get())),
std::__wrap_iter<__const_pointer>(std::addressof(this->__get()) + (this->has_value() ? 1 : 0)));
# else
return const_iterator(std::addressof(this->__get()));
return const_iterator(__wrap_iter<__const_pointer>(std::addressof(this->__get())));
# endif
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
// template <class T> class optional::const_iterator;

#include <optional>
#include <type_traits>

template <typename T>
concept has_iterator_aliases = requires {
Expand All @@ -24,6 +25,31 @@ concept has_iterator_aliases = requires {
static_assert(has_iterator_aliases<std::optional<int>>);
static_assert(has_iterator_aliases<std::optional<const int>>);

using Iter1 = std::optional<int>::iterator;
using Iter2 = std::optional<double>::iterator;
using Iter3 = std::optional<int>::const_iterator;
using Iter4 = std::optional<double>::const_iterator;

static_assert(std::is_convertible_v<Iter1, Iter1>);
static_assert(!std::is_convertible_v<Iter1, Iter2>);
static_assert(!std::is_convertible_v<Iter1, Iter3>);
static_assert(!std::is_convertible_v<Iter1, Iter4>);

static_assert(std::is_convertible_v<Iter2, Iter2>);
static_assert(!std::is_convertible_v<Iter2, Iter1>);
static_assert(!std::is_convertible_v<Iter2, Iter3>);
static_assert(!std::is_convertible_v<Iter2, Iter4>);

static_assert(std::is_convertible_v<Iter3, Iter3>);
static_assert(!std::is_convertible_v<Iter3, Iter1>);
static_assert(!std::is_convertible_v<Iter3, Iter2>);
static_assert(!std::is_convertible_v<Iter3, Iter4>);

static_assert(std::is_convertible_v<Iter4, Iter4>);
static_assert(!std::is_convertible_v<Iter4, Iter1>);
static_assert(!std::is_convertible_v<Iter4, Iter2>);
static_assert(!std::is_convertible_v<Iter4, Iter3>);

// TODO: Uncomment these once P2988R12 is implemented, as they would be testing optional<T&>

// static_assert(!has_iterator_aliases<std::optional<int (&)[]>>);
Expand Down
Loading