Skip to content
Closed
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
4b9c76b
[libcxx] add ranges::enable_view<optional<_T>> = true and format_kind…
dywoq Jun 30, 2025
ebda4e4
[libcxx] add forward declaration of __optional_iterator in <optional>
dywoq Jun 30, 2025
6e97c34
[libcxx] add __optional_iterator
dywoq Jun 30, 2025
ef52562
[libcxxx] add begin() and end() to std::optional class
dywoq Jul 1, 2025
820d96c
[libcxx] update includes in <optional> header
dywoq Jul 1, 2025
5fc696b
[libcxx] add comment
dywoq Jul 1, 2025
162170c
[libcxx] remove unimplemented: True parameter in generate_feature_tes…
dywoq Jul 1, 2025
f968252
[libcxx] update <version> header
dywoq Jul 1, 2025
06109ed
[libcxx] write optional.range tests
dywoq Jul 1, 2025
fc75fe0
[libcxx] add optional.range.runtime_error.fail test
dywoq Jul 1, 2025
f939528
[libcxx] remove unused include
dywoq Jul 1, 2025
fdc917b
[libcxx] change path to assert_macros.h
dywoq Jul 1, 2025
e704aba
[libcxx] remove .clangd
dywoq Jul 1, 2025
f294f98
[libcxx] rename test
dywoq Jul 1, 2025
a720391
[libcxx] change iterator_category to random_access_iterator_tag <opti…
dywoq Jul 1, 2025
4bfc9bb
[libcxx] remove operator!= for __optional_iterator in <optional>
dywoq Jul 1, 2025
26974eb
[libcxx] add constexpr to __optional_iterator, optional<T>::begin and…
dywoq Jul 1, 2025
b61f90b
[libcxx] use assert in optional.range.iteration.pass test
dywoq Jul 1, 2025
6993061
[libcxx] use static_assert in optional.range.satisfies_range_concept.…
dywoq Jul 1, 2025
a3ef155
[libcxx] add additional operators to __optional_iterator
dywoq Jul 1, 2025
6d4be21
[libcxx] remove .clangd
dywoq Jul 1, 2025
47ba868
[libcxx] add iterator_types.verify test to optional.ranges
dywoq Jul 1, 2025
3f69eda
[libcxx] add missing new character line at EOF
dywoq Jul 1, 2025
ef8af0a
[libcxx] change optional.range.iteration.pass test to constant eveluated
dywoq Jul 1, 2025
04b5511
[libcxx] use __wrap_iter in __optional_iterator
dywoq Jul 1, 2025
3f6f457
[libcxx] add missing comment
dywoq Jul 1, 2025
132bc39
[libcxx] add tests enable_ranges_view.pass and format_kind.pass in op…
dywoq Jul 1, 2025
8c4d4df
[libcxx] remove .clangd
dywoq Jul 1, 2025
ef032f1
[libcxx] add friend declarations for __wrap_iter in __optional_iterator
dywoq Jul 1, 2025
149ff9e
[libcxx] update const_iterator type to use const reference in optional
dywoq Jul 1, 2025
0510945
[libcxx] simplify __optional_iterator operations and add to_address u…
dywoq Jul 1, 2025
5be2e9d
[libcxx] rename enable_ranges_view.pass.cpp to enable_ranges_view.com…
dywoq Jul 2, 2025
e34c3bc
[libcxx] rename optional.range tests
dywoq Jul 2, 2025
fc0219e
[libcxx] remove main function blocks in optional.range.*.compile.pass…
dywoq Jul 2, 2025
b0393d6
[libcxx] update satisfies_range_concept test to include sized_range, …
dywoq Jul 2, 2025
d66ea58
[libcxx] remove __optional_iterator class
dywoq Jul 2, 2025
42de74b
[libcxx] refactor iterator type assertions in optional.range
dywoq Jul 2, 2025
99fb189
[libcxx] use test() along with static_assert(test()) in optional.rang…
dywoq Jul 2, 2025
02cd53f
[libcxx] correct iterator type to use pointer types in optional
dywoq Jul 3, 2025
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
2 changes: 1 addition & 1 deletion libcxx/docs/FeatureTestMacroTable.rst
Original file line number Diff line number Diff line change
Expand Up @@ -476,7 +476,7 @@ Status
---------------------------------------------------------- -----------------
``__cpp_lib_not_fn`` ``202306L``
---------------------------------------------------------- -----------------
``__cpp_lib_optional_range_support`` *unimplemented*
``__cpp_lib_optional_range_support`` ``202406L``
---------------------------------------------------------- -----------------
``__cpp_lib_out_ptr`` ``202311L``
---------------------------------------------------------- -----------------
Expand Down
113 changes: 113 additions & 0 deletions libcxx/include/optional
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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

*/
Expand All @@ -187,6 +200,8 @@ namespace std {
# include <__concepts/invocable.h>
# include <__config>
# include <__exception/exception.h>
# include <__format/format_context.h>
Copy link
Contributor

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?

# include <__format/range_default_formatter.h>
# include <__functional/hash.h>
# include <__functional/invoke.h>
# include <__functional/unary_function.h>
Expand Down Expand Up @@ -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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this needed?


# if _LIBCPP_STD_VER >= 20

template <class _Tp>
Expand All @@ -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
Copy link
Contributor

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.


template <typename _Tp>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add tests to make sure that the iterator fulfills all the iterator requirements.

class __optional_iterator {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Couldn't we just use __wrap_iter?

public:
using value_type = _Tp;
using difference_type = std::ptrdiff_t;
using pointer = _Tp*;
using reference = _Tp&;
using iterator_category = std::forward_iterator_tag;

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;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't meet the Cpp17RandomAccessIterator requirements.

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_; }

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>,
Expand All @@ -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>;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reference type for const_iterator is 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>;
Expand Down Expand Up @@ -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()));
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

constexpr is missing, and reinterpret_cast is incompatible with constant evaluation. Ditto below.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will use static_cast then

_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;
};

Expand Down
2 changes: 1 addition & 1 deletion libcxx/include/version
Original file line number Diff line number Diff line change
Expand Up @@ -581,7 +581,7 @@ __cpp_lib_void_t 201411L <type_traits>
# define __cpp_lib_mdspan 202406L
# undef __cpp_lib_not_fn
# define __cpp_lib_not_fn 202306L
// # define __cpp_lib_optional_range_support 202406L
# define __cpp_lib_optional_range_support 202406L
# undef __cpp_lib_out_ptr
# define __cpp_lib_out_ptr 202311L
// # define __cpp_lib_philox_engine 202406L
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,17 +152,11 @@
# error "__cpp_lib_optional should have the value 202110L in c++26"
# endif

# if !defined(_LIBCPP_VERSION)
# ifndef __cpp_lib_optional_range_support
# error "__cpp_lib_optional_range_support should be defined in c++26"
# endif
# if __cpp_lib_optional_range_support != 202406L
# error "__cpp_lib_optional_range_support should have the value 202406L in c++26"
# endif
# else
# ifdef __cpp_lib_optional_range_support
# error "__cpp_lib_optional_range_support should not be defined because it is unimplemented in libc++!"
# endif
# ifndef __cpp_lib_optional_range_support
# error "__cpp_lib_optional_range_support should be defined in c++26"
# endif
# if __cpp_lib_optional_range_support != 202406L
# error "__cpp_lib_optional_range_support should have the value 202406L in c++26"
# endif

#endif // TEST_STD_VER > 23
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7377,17 +7377,11 @@
# error "__cpp_lib_optional should have the value 202110L in c++26"
# endif

# if !defined(_LIBCPP_VERSION)
# ifndef __cpp_lib_optional_range_support
# error "__cpp_lib_optional_range_support should be defined in c++26"
# endif
# if __cpp_lib_optional_range_support != 202406L
# error "__cpp_lib_optional_range_support should have the value 202406L in c++26"
# endif
# else
# ifdef __cpp_lib_optional_range_support
# error "__cpp_lib_optional_range_support should not be defined because it is unimplemented in libc++!"
# endif
# ifndef __cpp_lib_optional_range_support
# error "__cpp_lib_optional_range_support should be defined in c++26"
# endif
# if __cpp_lib_optional_range_support != 202406L
# error "__cpp_lib_optional_range_support should have the value 202406L in c++26"
# endif

# ifndef __cpp_lib_out_ptr
Expand Down
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
//
//===----------------------------------------------------------------------===//

Copy link
Contributor

Choose a reason for hiding this comment

The 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() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All tests should also be constant evaluated.

std::optional<int> val = 2;
for (const auto& elem : val) {
std::cout << elem << std::endl;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should assert here.

Also, there should be a file testing the properties of the iterator types.

}
return 0;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please don't use .fail.cpp.

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;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing newline.

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>>;
std::cout << "std::ranges::range<std::optional<int>> is " << status << std::endl;
return 0;
}
1 change: 0 additions & 1 deletion libcxx/utils/generate_feature_test_macro_components.py
Original file line number Diff line number Diff line change
Expand Up @@ -1004,7 +1004,6 @@ def add_version_header(tc):
"name": "__cpp_lib_optional_range_support",
"values": {"c++26": 202406}, # P3168R2 Give std::optional Range Support
"headers": ["optional"],
"unimplemented": True,
},
{
"name": "__cpp_lib_out_ptr",
Expand Down