Skip to content
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

Add ranges support to optional #62

Merged
merged 2 commits into from
Oct 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
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
88 changes: 88 additions & 0 deletions include/preview/__iterator/pointer_iterator.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
//
// Created by yonggyulee on 2024. 10. 20.
//

#ifndef PREVIEW_ITERATOR_POINTER_ITERATOR_H_
#define PREVIEW_ITERATOR_POINTER_ITERATOR_H_

#include <cstddef>
#include <type_traits>

#include "preview/__iterator/detail/contiguous_iterator_tag.h"
#include "preview/__iterator/iterator_tag.h"

namespace preview {
namespace detail {

template<typename T, typename Tag = void>
class pointer_iterator {
public:
using difference_type = std::ptrdiff_t;
using value_type = std::remove_cv_t<T>;
using pointer = T*;
using reference = T&;
using iterator_category = std::random_access_iterator_tag;
using iterator_concept = contiguous_iterator_tag;

pointer_iterator() = default;

constexpr pointer_iterator(pointer p)
: ptr_(p) {}

constexpr reference operator*() const noexcept { return *ptr_; }
constexpr pointer operator->() const noexcept { return ptr_; }

constexpr reference operator[](difference_type n) const noexcept {
return ptr_[n];
}

constexpr pointer_iterator& operator++() noexcept {
++ptr_;
return *this;
}
constexpr pointer_iterator operator++(int) noexcept {
pointer_iterator temp{*this};
++*this;
return temp;
}

constexpr pointer_iterator& operator--() noexcept {
--ptr_;
return *this;
}
constexpr pointer_iterator operator--(int) noexcept {
pointer_iterator temp{*this};
--*this;
return temp;
}

constexpr pointer_iterator& operator+=(difference_type n) const noexcept {
ptr_ += n;
return *this;
}

constexpr pointer_iterator& operator-=(difference_type n) const noexcept {
ptr_ -= n;
return *this;
}

friend constexpr bool operator==(pointer_iterator x, pointer_iterator y) noexcept { return x.ptr_ == y.ptr_; }
friend constexpr bool operator!=(pointer_iterator x, pointer_iterator y) noexcept { return x.ptr_ != y.ptr_; }
friend constexpr bool operator< (pointer_iterator x, pointer_iterator y) noexcept { return x.ptr_ < y.ptr_; }
friend constexpr bool operator<=(pointer_iterator x, pointer_iterator y) noexcept { return x.ptr_ <= y.ptr_; }
friend constexpr bool operator> (pointer_iterator x, pointer_iterator y) noexcept { return x.ptr_ > y.ptr_; }
friend constexpr bool operator>=(pointer_iterator x, pointer_iterator y) noexcept { return x.ptr_ >= y.ptr_; }

friend constexpr pointer_iterator operator+(pointer_iterator i, difference_type n) noexcept { return pointer_iterator{i.ptr_ + n}; }
friend constexpr pointer_iterator operator+(difference_type n, pointer_iterator i) noexcept { return pointer_iterator{i.ptr_ + n}; }
friend constexpr pointer_iterator operator-(pointer_iterator i, difference_type n) noexcept { return pointer_iterator{i.ptr_ - n}; }
friend constexpr difference_type operator-(pointer_iterator x, pointer_iterator y) noexcept { return x.ptr_ - y.ptr_; }

private:
pointer ptr_ = nullptr;
};

} // namespace detail
} // namespace preview

#endif // PREVIEW_ITERATOR_POINTER_ITERATOR_H_
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);
}
Loading