-
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 21 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,6 +200,8 @@ namespace std { | |
| # include <__concepts/invocable.h> | ||
| # include <__config> | ||
| # include <__exception/exception.h> | ||
| # include <__format/format_context.h> | ||
| # include <__format/range_default_formatter.h> | ||
| # include <__functional/hash.h> | ||
| # include <__functional/invoke.h> | ||
| # include <__functional/unary_function.h> | ||
|
|
@@ -566,6 +581,13 @@ using __optional_sfinae_assign_base_t _LIBCPP_NODEBUG = | |
| template <class _Tp> | ||
| class optional; | ||
|
|
||
| # if _LIBCPP_STD_VER >= 26 | ||
|
|
||
| template <typename _Tp> | ||
| class __optional_iterator; | ||
|
|
||
| # endif // _LIBCPP_STD_VER >= 26 | ||
|
||
|
|
||
| # if _LIBCPP_STD_VER >= 20 | ||
|
|
||
| template <class _Tp> | ||
|
|
@@ -578,6 +600,120 @@ 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; | ||
|
Comment on lines
+598
to
+602
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. These don't have tests AFAICT. |
||
|
|
||
| template <typename _Tp> | ||
|
||
| class __optional_iterator { | ||
|
||
| public: | ||
| using value_type = _Tp; | ||
| using difference_type = std::ptrdiff_t; | ||
| using pointer = _Tp*; | ||
| using reference = _Tp&; | ||
| using iterator_category = random_access_iterator_tag; | ||
| using iterator_concept = contiguous_iterator_tag; | ||
|
|
||
| private: | ||
| pointer __ptr_; | ||
| _LIBCPP_HIDE_FROM_ABI constexpr explicit __optional_iterator(pointer __ptr) : __ptr_(__ptr) {} | ||
| _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() : __ptr_(nullptr) {} | ||
|
|
||
| _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 *__ptr_; } | ||
| _LIBCPP_HIDE_FROM_ABI constexpr pointer operator->() const { return *__ptr_; } | ||
|
|
||
| _LIBCPP_HIDE_FROM_ABI constexpr __optional_iterator& operator++() noexcept { | ||
| __ptr_ = nullptr; | ||
|
||
| return *this; | ||
| } | ||
| _LIBCPP_HIDE_FROM_ABI constexpr __optional_iterator operator++(int) noexcept { | ||
| auto __t = *this; | ||
| __ptr_ = nullptr; | ||
| return __t; | ||
| } | ||
|
|
||
| _LIBCPP_HIDE_FROM_ABI constexpr __optional_iterator& operator--() noexcept { | ||
| __ptr_ = nullptr; | ||
| return *this; | ||
| } | ||
| _LIBCPP_HIDE_FROM_ABI constexpr __optional_iterator operator--(int) noexcept { | ||
| auto __t = *this; | ||
| __ptr_ = nullptr; | ||
| return __t; | ||
| } | ||
|
|
||
| _LIBCPP_HIDE_FROM_ABI constexpr __optional_iterator& operator+=(difference_type __n) noexcept { | ||
| if (__n != 0) | ||
| __ptr_ = nullptr; | ||
| return *this; | ||
| } | ||
| _LIBCPP_HIDE_FROM_ABI constexpr __optional_iterator& operator-=(difference_type __n) noexcept { | ||
| if (__n != 0) | ||
| __ptr_ = nullptr; | ||
| return *this; | ||
| } | ||
|
|
||
| _LIBCPP_HIDE_FROM_ABI friend constexpr __optional_iterator | ||
| operator+(__optional_iterator __i, difference_type __n) noexcept { | ||
| return (__n == 0 ? __i : __optional_iterator{}); | ||
| } | ||
| _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 (__n == 0 ? __i : __optional_iterator{}); | ||
| } | ||
| _LIBCPP_HIDE_FROM_ABI friend constexpr difference_type | ||
| operator-(__optional_iterator __a, __optional_iterator __b) noexcept { | ||
| return (__a.__ptr_ == __b.__ptr_ ? 0 : (__a.__ptr_ ? 1 : -1)); | ||
| } | ||
|
|
||
| _LIBCPP_HIDE_FROM_ABI constexpr reference operator[](difference_type __n) const noexcept { return *(*this + __n); } | ||
|
|
||
| _LIBCPP_HIDE_FROM_ABI constexpr bool operator==(const __optional_iterator& __other) const { | ||
| return __ptr_ == __other.__ptr_; | ||
| } | ||
|
|
||
| _LIBCPP_HIDE_FROM_ABI friend constexpr bool | ||
| operator<(const __optional_iterator& __a, const __optional_iterator& __b) noexcept { | ||
| return __a.__ptr_ < __b.__ptr_; | ||
| } | ||
| _LIBCPP_HIDE_FROM_ABI friend constexpr bool | ||
| operator>(const __optional_iterator& __a, const __optional_iterator& __b) noexcept { | ||
| return __a.__ptr_ > __b.__ptr_; | ||
| } | ||
| _LIBCPP_HIDE_FROM_ABI friend constexpr bool | ||
| operator<=(const __optional_iterator& __a, const __optional_iterator& __b) noexcept { | ||
| return __a.__ptr_ <= __b.__ptr_; | ||
| } | ||
| _LIBCPP_HIDE_FROM_ABI friend constexpr bool | ||
| operator>=(const __optional_iterator& __a, const __optional_iterator& __b) noexcept { | ||
| return __a.__ptr_ >= __b.__ptr_; | ||
| } | ||
|
|
||
| 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>(static_cast<const _Tp*>(__ptr_)); | ||
| } | ||
| }; | ||
|
|
||
| # endif // _LIBCPP_STD_VER >= 26 | ||
|
|
||
| template <class _Tp> | ||
| class _LIBCPP_DECLSPEC_EMPTY_BASES optional | ||
| : private __optional_move_assign_base<_Tp>, | ||
|
|
@@ -588,6 +724,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<_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 +1119,25 @@ public: | |
| } | ||
| # endif // _LIBCPP_STD_VER >= 23 | ||
|
|
||
| // P3168R2 | ||
| # if _LIBCPP_STD_VER >= 26 | ||
|
|
||
| _LIBCPP_HIDE_FROM_ABI constexpr iterator begin() { | ||
| if (!this->has_value()) | ||
| return this->end(); | ||
| return iterator(static_cast<_Tp*>(this->__get())); | ||
| } | ||
| _LIBCPP_HIDE_FROM_ABI constexpr const_iterator begin() const { | ||
| if (!this->has_value()) | ||
| return this->end(); | ||
| return const_iterator(static_cast<_Tp*>(this->value())); | ||
| } | ||
|
|
||
| _LIBCPP_HIDE_FROM_ABI constexpr iterator end() { return iterator(nullptr); } | ||
| _LIBCPP_HIDE_FROM_ABI constexpr const_iterator end() const { return const_iterator(nullptr); } | ||
|
|
||
| # endif | ||
|
|
||
| using __base::reset; | ||
| }; | ||
|
|
||
|
|
||
| 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 | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
|
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> | ||
|
|
||
| int main() { | ||
|
||
| std::optional<int> val = 2; | ||
| for (const auto& elem : val) | ||
| assert(elem == 2); | ||
| return 0; | ||
| } | ||
|
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 don't use |
| 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; | ||
| } | ||
|
||
| 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::range<std::optional<int>>, "std::ranges::range<std::optional<int>> is false"); | ||
|
||
| 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.
Why is this include needed?