Skip to content

Commit

Permalink
Add ranges support to optional
Browse files Browse the repository at this point in the history
  • Loading branch information
lackhole committed Oct 19, 2024
1 parent 8c3e332 commit aa54d4c
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 10 deletions.
20 changes: 11 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -901,19 +901,21 @@ Description

#### `<optional>`

| | Introduced | Revision |
|-----------------------|-------------|-----------------------|
| `optional` | ![][c17ok] | ![][c23ok] ![][c26no] |
| `bad_optional_access` | ![][c17ok] | |
| `std::hash<optional>` | ![][c17ok] | |
| `nullopt` | ![][c17ok]* | |
| `nullopt_t` | ![][c17ok]* | |
| `swap(optional)` | ![][c17ok] | |
| `make_optional` | ![][c17ok] | |
| | Introduced | Revision |
|-----------------------|-------------|------------------------|
| `optional` | ![][c17ok] | ![][c23ok] ![][c26ok]* |
| `bad_optional_access` | ![][c17ok] | |
| `std::hash<optional>` | ![][c17ok] | |
| `nullopt` | ![][c17ok]* | |
| `nullopt_t` | ![][c17ok]* | |
| `swap(optional)` | ![][c17ok] | |
| `make_optional` | ![][c17ok] | |

* Notes
* `nullopt`, `nullopt_t`
* `std::nullopt` is used if available, `preview::nullopt` otherwise.
* C++26
* [P3168 (R2)](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3168r2.html)

#### `<random>`

Expand Down
31 changes: 30 additions & 1 deletion include/preview/__optional/optional.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,15 @@
# include "preview/__concepts/invocable.h"
# include "preview/__concepts/move_constructible.h"
# include "preview/__functional/invoke.h"
# include "preview/__iterator/basic_const_iterator.h"
# include "preview/__iterator/pointer_iterator.h"
# include "preview/__memory/addressof.h"
# include "preview/__memory/construct_at.h"
# include "preview/__memory/destroy_at.h"
# include "preview/__optional/bad_optional_access.h"
# include "preview/__optional/nullopt_t.h"
# include "preview/__optional/swap.h"
# include "preview/__ranges/enable_view.h"
# include "preview/__type_traits/detail/control_special.h"
# include "preview/__type_traits/is_swappable.h"
# include "preview/__type_traits/is_invocable.h"
Expand Down Expand Up @@ -249,7 +252,9 @@ class optional : private detail::optional_control_smf<T> {
using base::base;

public:
using value_type = T;
using value_type = T;
using iterator = detail::pointer_iterator<T, class optional_iterator_tag>;
using const_iterator = detail::pointer_iterator<const T, class optional_iterator_tag>;

static_assert(!std::is_reference<T>::value,
"preview::optional : T must not be a reference type");
Expand Down Expand Up @@ -600,6 +605,20 @@ class optional : private detail::optional_control_smf<T> {
this->construct_with(ilist, std::forward<Args>(args)...);
return **this;
}

constexpr iterator begin() noexcept {
return iterator{has_value() ? preview::addressof(**this) : nullptr};
}
constexpr const_iterator begin() const noexcept {
return const_iterator{has_value() ? preview::addressof(**this) : nullptr};
}

constexpr iterator end() noexcept {
return begin() + has_value();
}
constexpr const_iterator end() const noexcept {
return begin() + has_value();
}
};

# if PREVIEW_CXX_VERSION >= 17
Expand Down Expand Up @@ -808,6 +827,16 @@ constexpr inline bool operator>=(const T& value, const optional<U>& opt) {
return bool(opt) ? value >= *opt : true;
}


// ranges support
namespace ranges {

template<typename T>
struct enable_view<optional<T>> : std::true_type {};

// TODO: Specialize format_kind

} // namespace ranges
} // namespace preview

# endif // PREVIEW_OPTIONAL_OPTIONAL_H_
21 changes: 21 additions & 0 deletions test/optional/optional_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -371,3 +371,24 @@ TEST(VERSIONED(optional), copy_over_move) {
std::swap(op1, op2); // copy is selected for non-movable object
EXPECT_EQ(NoMove::copied, 2);
}

TEST(VERSIONED(optional), ranges) {
preview::optional<int> o;
using I = decltype(o)::iterator;
using CI = decltype(o)::const_iterator;

EXPECT_TRUE_TYPE(preview::contiguous_iterator<I>);
EXPECT_TRUE_TYPE(preview::ranges::view<decltype(o)>);
EXPECT_EQ(o.begin(), o.begin());
EXPECT_EQ(o.begin(), o.end());
EXPECT_EQ(o.end(), o.end());
EXPECT_EQ(preview::ranges::size(o), 0);

o = 100;
EXPECT_EQ(o.begin(), o.begin());
EXPECT_NE(o.begin(), o.end());
EXPECT_EQ(o.end(), o.end());
EXPECT_EQ(o.begin() + 1, o.end());
EXPECT_EQ(o.begin(), o.end() - 1);
EXPECT_EQ(preview::ranges::size(o), 1);
}

0 comments on commit aa54d4c

Please sign in to comment.