Skip to content
Closed
Show file tree
Hide file tree
Changes from 31 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
167 changes: 167 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,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>
Expand Down Expand Up @@ -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;
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?

using _Base = __wrap_iter<_Tp*>;
Copy link
Contributor

Choose a reason for hiding this comment

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

Missing _LIBCPP_NODEBUG.

Copy link
Contributor

Choose a reason for hiding this comment

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

I meant that we don't need to invent a new iterator at all. We can just use __wrap_iter instead.

Copy link
Author

Choose a reason for hiding this comment

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

oh, I misunderstood you. I'll use __wrap-iter then

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

Choose a reason for hiding this comment

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

Can you explain why adding this function? P3168 doesn't add this this function.

Copy link
Author

Choose a reason for hiding this comment

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

Here

Note that std::contiguous_iterator requires std::to_address(iter2) == std::to_address(iter1) + std::iter_difference_t(iter2 - iter1) even if iter1 is dereferenceable and iter2 is NON-dereferenceable.

I thought I would need to add std::to_address for __optional_iterator

Copy link
Author

Choose a reason for hiding this comment

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

Sorry


# endif // _LIBCPP_STD_VER >= 26

template <class _Tp>
class _LIBCPP_DECLSPEC_EMPTY_BASES optional
: private __optional_move_assign_base<_Tp>,
Expand All @@ -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&>;
Copy link
Contributor

Choose a reason for hiding this comment

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

Did you mean __optional_iterator<const _Tp>?

This needs tests as well.


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

Choose a reason for hiding this comment

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

Seems wrong after updating implementation of operator++.


# endif // _LIBCPP_STD_VER >= 26

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,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>>);
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
//
//===----------------------------------------------------------------------===//

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 <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());
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;

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