-
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 14 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,71 @@ 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 = std::forward_iterator_tag; | ||
dywoq marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| private: | ||
| pointer __ptr_; | ||
| _LIBCPP_HIDE_FROM_ABI 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 __optional_iterator() : __ptr_(nullptr) {} | ||
|
|
||
| _LIBCPP_HIDE_FROM_ABI __optional_iterator(const __optional_iterator&) = default; | ||
| _LIBCPP_HIDE_FROM_ABI __optional_iterator& operator=(const __optional_iterator&) = default; | ||
|
|
||
| _LIBCPP_HIDE_FROM_ABI reference operator*() const { | ||
| if (__ptr_ == nullptr) | ||
| std::__throw_runtime_error("deferencering end iterator"); | ||
| return *__ptr_; | ||
| } | ||
|
|
||
| _LIBCPP_HIDE_FROM_ABI pointer operator->() const { | ||
| if (__ptr_ == nullptr) | ||
| std::__throw_runtime_error("deferencering end iterator"); | ||
| return *__ptr_; | ||
| } | ||
|
|
||
| _LIBCPP_HIDE_FROM_ABI __optional_iterator& operator++() { | ||
| __ptr_ = nullptr; | ||
|
||
| return *this; | ||
| } | ||
|
|
||
| _LIBCPP_HIDE_FROM_ABI __optional_iterator operator++(int) { | ||
| __optional_iterator __tmp = *this; | ||
| __ptr_ = nullptr; | ||
| return __tmp; | ||
| } | ||
|
|
||
| _LIBCPP_HIDE_FROM_ABI bool operator==(const __optional_iterator& __other) const { return __ptr_ == __other.__ptr_; } | ||
| _LIBCPP_HIDE_FROM_ABI bool operator!=(const __optional_iterator& __other) const { return __ptr_ != __other.__ptr_; } | ||
dywoq marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| template <typename _Ut = _Tp> | ||
| _LIBCPP_HIDE_FROM_ABI 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 +675,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 +1070,25 @@ public: | |
| } | ||
| # endif // _LIBCPP_STD_VER >= 23 | ||
|
|
||
| // P3168R2 | ||
| # if _LIBCPP_STD_VER >= 26 | ||
|
|
||
| _LIBCPP_HIDE_FROM_ABI iterator begin() { | ||
| if (!this->has_value()) | ||
| return this->end(); | ||
| return iterator(reinterpret_cast<_Tp*>(this->__get())); | ||
| } | ||
|
||
| _LIBCPP_HIDE_FROM_ABI const_iterator begin() const { | ||
| if (!this->has_value()) | ||
| return this->end(); | ||
| return const_iterator(reinterpret_cast<_Tp*>(this->value())); | ||
| } | ||
|
|
||
| _LIBCPP_HIDE_FROM_ABI iterator end() { return iterator(nullptr); } | ||
| _LIBCPP_HIDE_FROM_ABI 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,20 @@ | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // 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 <iostream> | ||
| #include <optional> | ||
|
|
||
| int main() { | ||
|
||
| std::optional<int> val = 2; | ||
| for (const auto& elem : val) { | ||
| std::cout << elem << std::endl; | ||
|
||
| } | ||
| return 0; | ||
| } | ||
zwuis marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
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,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 <iostream> | ||
| #include <optional> | ||
| #include <ranges> | ||
|
|
||
| int main() { | ||
| bool status = std::ranges::range<std::optional<int>>; | ||
zwuis marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| std::cout << "std::ranges::range<std::optional<int>> is " << status << std::endl; | ||
| 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?