-
Notifications
You must be signed in to change notification settings - Fork 15.1k
[libc++] P3168R2 Give std::optional Range Support #146491
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 31 commits
4b9c76b
ebda4e4
6e97c34
ef52562
820d96c
5fc696b
162170c
f968252
06109ed
fc75fe0
f939528
fdc917b
e704aba
f294f98
a720391
4bfc9bb
26974eb
b61f90b
6993061
a3ef155
6d4be21
47ba868
3f69eda
ef8af0a
04b5511
3f6f457
132bc39
8c4d4df
ef032f1
149ff9e
0510945
5be2e9d
e34c3bc
fc0219e
b0393d6
d66ea58
42de74b
99fb189
02cd53f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -102,6 +102,8 @@ namespace std { | |
| class optional { | ||
| public: | ||
| using value_type = T; | ||
| using iterator = implementation-defined; // see [optional.iterators] // since C++26 | ||
| using const_iterator = implementation-defined; // see [optional.iterators] // since C++26 | ||
|
|
||
| // [optional.ctor], constructors | ||
| constexpr optional() noexcept; | ||
|
|
@@ -135,6 +137,12 @@ namespace std { | |
| // [optional.swap], swap | ||
| void swap(optional &) noexcept(see below ); // constexpr in C++20 | ||
|
|
||
| // [optional.iterators], iterator support | ||
| constexpr iterator begin() noexcept; // since C++26 | ||
| constexpr const_iterator begin() const noexcept; // since C++26 | ||
| constexpr iterator end() noexcept; // since C++26 | ||
| constexpr const_iterator end() const noexcept; // since C++26 | ||
|
|
||
| // [optional.observe], observers | ||
| constexpr T const *operator->() const noexcept; | ||
| constexpr T *operator->() noexcept; | ||
|
|
@@ -173,6 +181,11 @@ namespace std { | |
| template<class T> | ||
| optional(T) -> optional<T>; | ||
|
|
||
| template<class T> | ||
| constexpr bool ranges::enable_view<optional<T>> = true; // since C++26 | ||
| template<class T> | ||
| constexpr auto format_kind<optional<T>> = range_format::disabled; // since C++26 | ||
|
|
||
| } // namespace std | ||
|
|
||
| */ | ||
|
|
@@ -187,10 +200,12 @@ namespace std { | |
| # include <__concepts/invocable.h> | ||
| # include <__config> | ||
| # include <__exception/exception.h> | ||
| # include <__format/range_default_formatter.h> | ||
| # include <__functional/hash.h> | ||
| # include <__functional/invoke.h> | ||
| # include <__functional/unary_function.h> | ||
| # include <__fwd/functional.h> | ||
| # include <__iterator/wrap_iter.h> | ||
| # include <__memory/addressof.h> | ||
| # include <__memory/construct_at.h> | ||
| # include <__tuple/sfinae_helpers.h> | ||
|
|
@@ -578,6 +593,128 @@ struct __is_std_optional : false_type {}; | |
| template <class _Tp> | ||
| struct __is_std_optional<optional<_Tp>> : true_type {}; | ||
|
|
||
| # if _LIBCPP_STD_VER >= 26 | ||
|
|
||
| template <class _T> | ||
| constexpr bool ranges::enable_view<optional<_T>> = true; | ||
|
|
||
| template <class _T> | ||
| constexpr auto format_kind<optional<_T>> = range_format::disabled; | ||
|
|
||
| template <typename _Tp> | ||
|
||
| class __optional_iterator { | ||
|
||
| using _Base = __wrap_iter<_Tp*>; | ||
|
||
| _Base __it_; | ||
|
|
||
| public: | ||
| using value_type = _Tp; | ||
| using difference_type = typename _Base::difference_type; | ||
| using pointer = typename _Base::pointer; | ||
| using reference = typename _Base::reference; | ||
| using iterator_category = random_access_iterator_tag; | ||
| using iterator_concept = contiguous_iterator_tag; | ||
|
|
||
| private: | ||
| _LIBCPP_HIDE_FROM_ABI constexpr explicit __optional_iterator(_Base __it) noexcept : __it_(__it) {} | ||
|
|
||
| _LIBCPP_HIDE_FROM_ABI friend class __wrap_iter<_Tp*>; | ||
| _LIBCPP_HIDE_FROM_ABI friend class __wrap_iter<const _Tp*>; | ||
|
|
||
| _LIBCPP_HIDE_FROM_ABI friend class optional<std::remove_const_t<_Tp>>; | ||
| _LIBCPP_HIDE_FROM_ABI friend class optional<const _Tp>; | ||
|
|
||
| public: | ||
| _LIBCPP_HIDE_FROM_ABI constexpr __optional_iterator() : __it_(_Base()) {} | ||
|
|
||
| _LIBCPP_HIDE_FROM_ABI constexpr __optional_iterator(const __optional_iterator&) = default; | ||
| _LIBCPP_HIDE_FROM_ABI constexpr __optional_iterator& operator=(const __optional_iterator&) = default; | ||
|
|
||
| _LIBCPP_HIDE_FROM_ABI constexpr reference operator*() const { return *__it_; } | ||
| _LIBCPP_HIDE_FROM_ABI constexpr pointer operator->() const { return __it_.operator->(); } | ||
|
|
||
| _LIBCPP_HIDE_FROM_ABI constexpr __optional_iterator& operator++() noexcept { | ||
| ++__it_; | ||
| return *this; | ||
| } | ||
| _LIBCPP_HIDE_FROM_ABI constexpr __optional_iterator operator++(int) noexcept { | ||
| auto __tmp = *this; | ||
| ++__it_; | ||
| return __tmp; | ||
| } | ||
|
|
||
| _LIBCPP_HIDE_FROM_ABI constexpr __optional_iterator& operator--() noexcept { | ||
| --__it_; | ||
| return *this; | ||
| } | ||
| _LIBCPP_HIDE_FROM_ABI constexpr __optional_iterator operator--(int) noexcept { | ||
| auto __tmp = *this; | ||
| --__it_; | ||
| return __tmp; | ||
| } | ||
|
|
||
| _LIBCPP_HIDE_FROM_ABI constexpr __optional_iterator& operator+=(difference_type __n) noexcept { | ||
| __it_ += __n; | ||
| return *this; | ||
| } | ||
| _LIBCPP_HIDE_FROM_ABI constexpr __optional_iterator& operator-=(difference_type __n) noexcept { | ||
| __it_ -= __n; | ||
| return *this; | ||
| } | ||
|
|
||
| _LIBCPP_HIDE_FROM_ABI friend constexpr __optional_iterator | ||
| operator+(__optional_iterator __i, difference_type __n) noexcept { | ||
| return __optional_iterator(__i.__it_ + __n); | ||
| } | ||
| _LIBCPP_HIDE_FROM_ABI friend constexpr __optional_iterator | ||
| operator+(difference_type __n, __optional_iterator __i) noexcept { | ||
| return __i + __n; | ||
| } | ||
| _LIBCPP_HIDE_FROM_ABI friend constexpr __optional_iterator | ||
| operator-(__optional_iterator __i, difference_type __n) noexcept { | ||
| return __optional_iterator(__i.__it_ - __n); | ||
| } | ||
| _LIBCPP_HIDE_FROM_ABI friend constexpr difference_type | ||
| operator-(__optional_iterator __a, __optional_iterator __b) noexcept { | ||
| return __a.__it_ - __b.__it_; | ||
| } | ||
|
|
||
| _LIBCPP_HIDE_FROM_ABI constexpr reference operator[](difference_type __n) const noexcept { return *(__it_ + __n); } | ||
|
|
||
| _LIBCPP_HIDE_FROM_ABI constexpr bool operator==(const __optional_iterator& __other) const { | ||
| return __it_ == __other.__it_; | ||
| } | ||
|
|
||
| _LIBCPP_HIDE_FROM_ABI friend constexpr bool | ||
| operator<(const __optional_iterator& __a, const __optional_iterator& __b) noexcept { | ||
| return __a.__it_ < __b.__it_; | ||
| } | ||
| _LIBCPP_HIDE_FROM_ABI friend constexpr bool | ||
| operator>(const __optional_iterator& __a, const __optional_iterator& __b) noexcept { | ||
| return __a.__it_ > __b.__it_; | ||
| } | ||
| _LIBCPP_HIDE_FROM_ABI friend constexpr bool | ||
| operator<=(const __optional_iterator& __a, const __optional_iterator& __b) noexcept { | ||
| return __a.__it_ <= __b.__it_; | ||
| } | ||
| _LIBCPP_HIDE_FROM_ABI friend constexpr bool | ||
| operator>=(const __optional_iterator& __a, const __optional_iterator& __b) noexcept { | ||
| return __a.__it_ >= __b.__it_; | ||
| } | ||
|
|
||
| template <typename _Ut = _Tp> | ||
| _LIBCPP_HIDE_FROM_ABI constexpr operator __optional_iterator<const _Tp>() const | ||
| requires(!std::is_const_v<_Ut>) | ||
| { | ||
| return __optional_iterator<const _Tp>(__wrap_iter<const _Tp*>{__it_.base()}); | ||
| } | ||
| }; | ||
| template <typename _Tp> | ||
| _LIBCPP_HIDE_FROM_ABI constexpr _Tp* to_address(const __optional_iterator<_Tp>& __it) noexcept { | ||
| return std::to_address(__it.__it_); | ||
| } | ||
|
||
|
|
||
| # endif // _LIBCPP_STD_VER >= 26 | ||
|
|
||
| template <class _Tp> | ||
| class _LIBCPP_DECLSPEC_EMPTY_BASES optional | ||
| : private __optional_move_assign_base<_Tp>, | ||
|
|
@@ -588,6 +725,13 @@ class _LIBCPP_DECLSPEC_EMPTY_BASES optional | |
| public: | ||
| using value_type = _Tp; | ||
|
|
||
| # if _LIBCPP_STD_VER >= 26 | ||
|
|
||
| using iterator = __optional_iterator<_Tp>; | ||
| using const_iterator = __optional_iterator<const _Tp&>; | ||
|
||
|
|
||
| # endif // _LIBCPP_STD_VER >= 26 | ||
|
|
||
| using __trivially_relocatable _LIBCPP_NODEBUG = | ||
| conditional_t<__libcpp_is_trivially_relocatable<_Tp>::value, optional, void>; | ||
| using __replaceable _LIBCPP_NODEBUG = conditional_t<__is_replaceable_v<_Tp>, optional, void>; | ||
|
|
@@ -976,6 +1120,29 @@ public: | |
| } | ||
| # endif // _LIBCPP_STD_VER >= 23 | ||
|
|
||
| // P3168R2 | ||
| # if _LIBCPP_STD_VER >= 26 | ||
|
|
||
| _LIBCPP_HIDE_FROM_ABI constexpr iterator begin() { | ||
| if (!this->has_value()) | ||
| return end(); | ||
| return iterator(__wrap_iter(static_cast<_Tp*>(this->__get()))); | ||
| } | ||
|
|
||
| _LIBCPP_HIDE_FROM_ABI constexpr const_iterator begin() const { | ||
| if (!this->has_value()) | ||
| return end(); | ||
| return const_iterator(__wrap_iter(static_cast<const _Tp*>(this->__get()))); | ||
| } | ||
|
|
||
| _LIBCPP_HIDE_FROM_ABI constexpr iterator end() { return iterator(__wrap_iter(static_cast<_Tp*>(nullptr))); } | ||
|
|
||
| _LIBCPP_HIDE_FROM_ABI constexpr const_iterator end() const { | ||
| return const_iterator(__wrap_iter(static_cast<const _Tp*>(nullptr))); | ||
| } | ||
|
||
|
|
||
| # endif // _LIBCPP_STD_VER >= 26 | ||
|
|
||
| using __base::reset; | ||
| }; | ||
|
|
||
|
|
||
zwuis marked this conversation as resolved.
Show resolved
Hide resolved
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // 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 | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| // UNSUPPORTED: std-at-least-c++26 | ||
|
|
||
| #include <optional> | ||
| #include <ranges> | ||
|
|
||
| int main() { | ||
| static_assert(std::ranges::enable_view<std::optional<int>>); | ||
| return 0; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // 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 | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| // UNSUPPORTED: std-at-least-c++26 | ||
|
|
||
| #include <format> | ||
| #include <optional> | ||
|
|
||
| int main() { | ||
| static_assert(std::format_kind<std::optional<int>>); | ||
dywoq marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| return 0; | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // 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 | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please add comments in all tests what they are supported to do. |
||
| // UNSUPPORTED: std-at-least-c++26 | ||
|
|
||
| #include <cassert> | ||
| #include <optional> | ||
|
|
||
| constexpr bool test() { | ||
| constexpr std::optional<int> val = 2; | ||
| for (const auto& elem : val) | ||
| if (elem != 2) | ||
| return false; | ||
| return true; | ||
| } | ||
|
|
||
| int main() { | ||
| static_assert(test()); | ||
dywoq marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| return 0; | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // 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 | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| // UNSUPPORTED: std-at-least-c++26 | ||
|
|
||
| #include <iterator> | ||
| #include <optional> | ||
|
|
||
| int main() { | ||
| using Iter = std::optional<int>::iterator; | ||
dywoq marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| std::iterator_traits<int> s; | ||
| static_assert(std::random_access_iterator<Iter>); | ||
| static_assert(std::contiguous_iterator<Iter>); | ||
|
|
||
| static_assert(std::is_same_v<typename std::iterator_traits<Iter>::value_type, int>); | ||
| static_assert(std::is_same_v<typename std::iterator_traits<Iter>::difference_type, std::ptrdiff_t>); | ||
| static_assert(std::is_same_v<typename std::iterator_traits<Iter>::pointer, int*>); | ||
| static_assert(std::is_same_v<typename std::iterator_traits<Iter>::reference, int&>); | ||
| static_assert( | ||
| std::is_same_v<typename std::iterator_traits<Iter>::iterator_category, std::random_access_iterator_tag>); | ||
| return 0; | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // 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 | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| // UNSUPPORTED: std-at-least-c++26 | ||
|
|
||
| #include "assert_macros.h" | ||
| #include <optional> | ||
|
|
||
| int main() { | ||
| std::optional<int> val = 2; | ||
| auto end = val.end(); | ||
| TEST_DOES_NOT_THROW(*end); | ||
| return 0; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These don't have tests AFAICT.