Skip to content

Commit

Permalink
Merge pull request #9 from beman-project/neatudarius/P3168R1
Browse files Browse the repository at this point in the history
Implement P3168R1: Give std::optional Range Support
  • Loading branch information
neatudarius authored Jun 19, 2024
2 parents ce7d23c + 77fb8da commit 6666e03
Show file tree
Hide file tree
Showing 10 changed files with 409 additions and 129 deletions.
14 changes: 5 additions & 9 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,6 @@ jobs:
cmake_args: "-G \"Ninja Multi-Config\" -DCMAKE_CONFIGURATION_TYPES=\"RelWithDebInfo;Asan\" "
}

- {
name: "Ubuntu Clang 19",
os: ubuntu-24.04,
toolchain: "clang-19-toolchain.cmake",
clang_version: 19,
installed_clang_version: 14,
cmake_args: "-G \"Ninja Multi-Config\" -DCMAKE_CONFIGURATION_TYPES=\"RelWithDebInfo;Asan\" "
}

- {
name: "Ubuntu GCC 13",
os: ubuntu-24.04,
Expand All @@ -68,9 +59,13 @@ jobs:

- uses: seanmiddleditch/gha-setup-ninja@master

- name: Activate verbose shell
run: set -x

- name: Install LLVM+Clang
if: startsWith(matrix.config.os, 'ubuntu-')
run: |
set -x
cat /etc/lsb-release
sudo apt-get remove clang-${{matrix.config.installed_clang_version}} \
lldb-${{matrix.config.installed_clang_version}} \
Expand Down Expand Up @@ -105,6 +100,7 @@ jobs:
- name: Configure
run: |
rm -rf .build
mkdir -p .build
cd .build
echo ${{ matrix.config.cmake_args }}
Expand Down
122 changes: 46 additions & 76 deletions include/Beman/Optional26/optional.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// beman/optional/optional.h -*-C++-*-
#ifndef BEMAN_OPTIONAL26_OPTIONAL
#define BEMAN_OPTIONAL26_OPTIONAL
// include/Beman/Optional26/optional.hpp -*-C++-*-
#ifndef BEMAN_OPTIONAL26_OPTIONAL_HPP
#define BEMAN_OPTIONAL26_OPTIONAL_HPP

/*
22.5.2 Header <optional> synopsis[optional.syn]
Expand Down Expand Up @@ -165,10 +165,13 @@ namespace std {
*/

#include <compare>
#include <utility>
#if defined(__cpp_lib_format_ranges)
#include <format>
#endif
#include <functional>
#include <type_traits>
#include <ranges>
#include <type_traits>
#include <utility>

namespace beman::optional {

Expand Down Expand Up @@ -202,22 +205,22 @@ template <class T>
class optional;

} // namespace beman::optional

namespace std {
// Since P3168R1: Give std::optional Range Support.
template <typename T>
inline constexpr bool ranges::enable_view<beman::optional::optional<T>> = true;

template <typename T>
inline constexpr bool ranges::enable_view<beman::optional::optional<T&>> = true;

template <typename T>
inline constexpr bool ranges::enable_borrowed_range<beman::optional::optional<T*>> = true;

template <typename T>
inline constexpr bool ranges::enable_borrowed_range<beman::optional::optional<std::reference_wrapper<T>>> = true;

// TODO: document why this is needed.
template <typename T>
inline constexpr bool ranges::enable_borrowed_range<beman::optional::optional<T&>> = true;

// Since P3168R1: Give std::optional Range Support.
#if defined(__cpp_lib_format_ranges)
template <class T>
inline constexpr auto format_kind<beman::optional::optional<T>> = range_format::disabled;
#endif

} // namespace std

namespace beman::optional {
Expand Down Expand Up @@ -309,6 +312,11 @@ class optional {
}

public:
using value_type = T;
// Since P3168R1: Give std::optional Range Support.
using iterator = T*; // see [optional.iterators]
using const_iterator = const T*; // see [optional.iterators]

constexpr optional() noexcept
requires std::is_default_constructible_v<T>
= default;
Expand Down Expand Up @@ -675,6 +683,13 @@ class optional {
swap(engaged, rhs.engaged);
}

// Since P3168R1: Give std::optional Range Support.
// [optional.iterators], iterator support
constexpr iterator begin() noexcept { return has_value() ? std::addressof(value_) : nullptr; };
constexpr const_iterator begin() const noexcept { return has_value() ? std::addressof(value_) : nullptr; };
constexpr iterator end() noexcept { return begin() + has_value(); }
constexpr const_iterator end() const noexcept { return begin() + has_value(); }

/// Returns a pointer to the stored value
constexpr const T* operator->() const { return std::addressof(value_); }

Expand All @@ -699,36 +714,6 @@ class optional {
}
engaged = false;
}
using iterator = T*;
using const_iterator = const T*;

// [optional.iterators], iterator support
constexpr T* begin() noexcept {
if (has_value()) {
return std::addressof(value_);
} else {
return nullptr;
}
}
constexpr const T* begin() const noexcept {
if (has_value()) {
return std::addressof(value_);
} else {
return nullptr;
}
}
constexpr T* end() noexcept { return begin() + has_value(); }
constexpr const T* end() const noexcept { return begin() + has_value(); }

constexpr std::reverse_iterator<T*> rbegin() noexcept { return reverse_iterator(end()); }
constexpr std::reverse_iterator<const T*> rbegin() const noexcept { return reverse_iterator(end()); }
constexpr std::reverse_iterator<T*> rend() noexcept { return reverse_iterator(begin()); }
constexpr std::reverse_iterator<const T*> rend() const noexcept { return reverse_iterator(begin()); }

constexpr const T* cbegin() const noexcept { return begin(); }
constexpr const T* cend() const noexcept { return end(); }
constexpr std::reverse_iterator<const T*> crbegin() const noexcept { return rbegin(); }
constexpr std::reverse_iterator<const T*> crend() const noexcept { return rend(); }
};

template <typename T, typename U>
Expand Down Expand Up @@ -947,6 +932,12 @@ template <class T>
class optional<T&> {
public:
using value_type = T&;
// Since ${PAPER_NUMBER}: ${PAPER_TITLE}.
// Note: P3168 and P2988 may have different flows inside LEWG/LWG.
// Implementation of the range support for optional<T&> reflects P3168R1 for now.
// [optional.iterators], iterator support
using iterator = T*; // see [optional.iterators]
using const_iterator = const T*; // see [optional.iterators]

// [optional.ctor], constructors
// constexpr optional() noexcept;
Expand Down Expand Up @@ -1076,6 +1067,15 @@ class optional<T&> {

constexpr void swap(optional& rhs) noexcept { std::swap(value_, rhs.value_); }

// Since ${PAPER_NUMBER}: ${PAPER_TITLE}.
// Note: P3168 and P2988 may have different flows inside LEWG/LWG.
// Implementation of the range support for optional<T&> reflects P3168R1 for now.
// [optional.iterators], iterator support
constexpr iterator begin() noexcept { return has_value() ? value_ : nullptr; };
constexpr const_iterator begin() const noexcept { return has_value() ? value_ : nullptr; };
constexpr iterator end() noexcept { return begin() + has_value(); }
constexpr const_iterator end() const noexcept { return begin() + has_value(); }

// \rSec3[optional.observe]{Observers}
constexpr T* operator->() const noexcept { return value_; }

Expand Down Expand Up @@ -1120,37 +1120,7 @@ class optional<T&> {
}

constexpr void reset() noexcept { value_ = nullptr; }
using iterator = T*;
using const_iterator = const T*;

// [optional.iterators], iterator support
constexpr T* begin() noexcept {
if (has_value()) {
return value_;
} else {
return nullptr;
}
}
constexpr const T* begin() const noexcept {
if (has_value()) {
return value_;
} else {
return nullptr;
}
}
constexpr T* end() noexcept { return begin() + has_value(); }

constexpr const T* end() const noexcept { return begin() + has_value(); }

constexpr std::reverse_iterator<T*> rbegin() noexcept { return reverse_iterator(end()); }
constexpr std::reverse_iterator<const T*> rbegin() const noexcept { return reverse_iterator(end()); }
constexpr std::reverse_iterator<T*> rend() noexcept { return reverse_iterator(begin()); }
constexpr std::reverse_iterator<const T*> rend() const noexcept { return reverse_iterator(begin()); }

constexpr const T* cbegin() const noexcept { return begin(); }
constexpr const T* cend() const noexcept { return end(); }
constexpr std::reverse_iterator<const T*> crbegin() const noexcept { return rbegin(); }
constexpr std::reverse_iterator<const T*> crend() const noexcept { return rend(); }
};
} // namespace beman::optional
#endif

#endif // BEMAN_OPTIONAL26_OPTIONAL_HPP
2 changes: 1 addition & 1 deletion src/Beman/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
add_subdirectory(optional)
add_subdirectory(Optional26)
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,11 @@ add_executable(optional_test "")
target_sources(
optional_test
PRIVATE
optional.t.cpp
optional_ref.t.cpp
optional_monadic.t.cpp
optional_ref_monadic.t.cpp
tests/optional.t.cpp
tests/optional_ref.t.cpp
tests/optional_monadic.t.cpp
tests/optional_range_support.t.cpp
tests/optional_ref_monadic.t.cpp
)

target_link_libraries(optional_test "${TARGET_LIBRARY}")
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -638,42 +638,6 @@ TEST(ViewMaybeTest, Constructors) {
beman::optional::optional<std::optional<int>> n3{std::optional<int>{}};
}

TEST(ViewMaybeTest, ConceptCheck) {
static_assert(std::ranges::range<beman::optional::optional<int>>);
static_assert(std::ranges::view<beman::optional::optional<int>>);
static_assert(std::ranges::input_range<beman::optional::optional<int>>);
static_assert(std::ranges::forward_range<beman::optional::optional<int>>);
static_assert(std::ranges::bidirectional_range<beman::optional::optional<int>>);
static_assert(std::ranges::contiguous_range<beman::optional::optional<int>>);
static_assert(std::ranges::common_range<beman::optional::optional<int>>);
static_assert(std::ranges::viewable_range<beman::optional::optional<int>>);
static_assert(!std::ranges::borrowed_range<beman::optional::optional<int>>);
static_assert(std::ranges::random_access_range<beman::optional::optional<int>>);
static_assert(std::ranges::sized_range<beman::optional::optional<int>>);

static_assert(std::ranges::range<beman::optional::optional<int*>>);
static_assert(std::ranges::view<beman::optional::optional<int*>>);
static_assert(std::ranges::input_range<beman::optional::optional<int*>>);
static_assert(std::ranges::forward_range<beman::optional::optional<int*>>);
static_assert(std::ranges::bidirectional_range<beman::optional::optional<int*>>);
static_assert(std::ranges::contiguous_range<beman::optional::optional<int*>>);
static_assert(std::ranges::common_range<beman::optional::optional<int*>>);
static_assert(std::ranges::viewable_range<beman::optional::optional<int*>>);
static_assert(std::ranges::borrowed_range<beman::optional::optional<int*>>);
static_assert(std::ranges::random_access_range<beman::optional::optional<int*>>);

using ref = std::reference_wrapper<int>;
static_assert(std::ranges::range<beman::optional::optional<ref>>);
static_assert(std::ranges::view<beman::optional::optional<ref>>);
static_assert(std::ranges::input_range<beman::optional::optional<ref>>);
static_assert(std::ranges::forward_range<beman::optional::optional<ref>>);
static_assert(std::ranges::bidirectional_range<beman::optional::optional<ref>>);
static_assert(std::ranges::contiguous_range<beman::optional::optional<ref>>);
static_assert(std::ranges::common_range<beman::optional::optional<ref>>);
static_assert(std::ranges::viewable_range<beman::optional::optional<ref>>);
static_assert(std::ranges::borrowed_range<beman::optional::optional<ref>>);
static_assert(std::ranges::random_access_range<beman::optional::optional<ref>>);
}

TEST(ViewMaybeTest, ConceptCheckRef) {
static_assert(std::ranges::range<beman::optional::optional<int&>>);
Expand Down Expand Up @@ -823,8 +787,8 @@ TEST(ViewMaybe, CompTestRef) {
// (This uses one syntax for constrained lambdas
// in C++20.)
inline constexpr auto and_then = [](auto&& r, auto fun) {
return decltype(r)(r) | std::ranges::views::transform(std::move(fun)) |
std::ranges::views::join;
return decltype(r)(r) | std::views::transform(std::move(fun)) |
std::views::join;
};

// "yield_if" takes a bool and a value and
Expand All @@ -837,7 +801,7 @@ inline constexpr auto yield_if = []<class T>(bool b, T x) {


TEST(ViewMaybeTest, PythTripleTest) {
using std::ranges::views::iota;
using std::views::iota;
auto triples = and_then(iota(1), [](int z) {
return and_then(iota(1, z + 1), [=](int x) {
return and_then(iota(x, z + 1), [=](int y) {
Expand Down
File renamed without changes.
Loading

0 comments on commit 6666e03

Please sign in to comment.