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

Fix rvalref #23

Merged
merged 3 commits into from
Jan 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
2 changes: 0 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ project(stl-concepts VERSION 0.0.0 LANGUAGES CXX)

enable_testing()

set(CMAKE_CXX_STANDARD 20)

set(TARGETS_EXPORT_NAME ${CMAKE_PROJECT_NAME}Targets)

add_subdirectory(extern)
Expand Down
7 changes: 4 additions & 3 deletions etc/clang-17-toolchain.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@ include_guard(GLOBAL)
set(CMAKE_C_COMPILER clang-17)
set(CMAKE_CXX_COMPILER clang++-17)

set(CMAKE_CXX_STANDARD 20)

set(CMAKE_CXX_FLAGS
"-std=gnu++23 \
-Wall -Wextra \
"-Wall -Wextra \
-stdlib=libstdc++ "
CACHE STRING "CXX_FLAGS" FORCE)

set(CMAKE_CXX_FLAGS_DEBUG "-O0 -fno-inline -g3" CACHE STRING "C++ DEBUG Flags" FORCE)
set(CMAKE_CXX_FLAGS_RELEASE "-Ofast -g0 -DNDEBUG" CACHE STRING "C++ Release Flags" FORCE)
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O3 -g -DNDEBUG" CACHE STRING "C++ RelWithDebInfo Flags" FORCE)
set(CMAKE_CXX_FLAGS_TSAN "-O3 -g -DNDEBUG -fsanitize=thread" CACHE STRING "C++ TSAN Flags" FORCE)
set(CMAKE_CXX_FLAGS_ASAN "-O3 -g -DNDEBUG -fsanitize=address -fsanitize=undefined -fsanitize=leak" CACHE STRING "C++ ASAN Flags" FORCE)
set(CMAKE_CXX_FLAGS_ASAN "-O3 -g -DNDEBUG -fsanitize=address,undefined,leak" CACHE STRING "C++ ASAN Flags" FORCE)
16 changes: 16 additions & 0 deletions etc/gcc-14-toolchain.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
include_guard(GLOBAL)

set(CMAKE_C_COMPILER gcc-14)
set(CMAKE_CXX_COMPILER g++-14)

set(CMAKE_CXX_STANDARD 23)

set(CMAKE_CXX_FLAGS
"-Wall -Wextra "
CACHE STRING "CXX_FLAGS" FORCE)

set(CMAKE_CXX_FLAGS_DEBUG "-O0 -fno-inline -g3" CACHE STRING "C++ DEBUG Flags" FORCE)
set(CMAKE_CXX_FLAGS_RELEASE "-Ofast -g0 -DNDEBUG" CACHE STRING "C++ Release Flags" FORCE)
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O3 -g -DNDEBUG" CACHE STRING "C++ RelWithDebInfo Flags" FORCE)
set(CMAKE_CXX_FLAGS_TSAN "-O3 -g -DNDEBUG -fsanitize=thread" CACHE STRING "C++ TSAN Flags" FORCE)
set(CMAKE_CXX_FLAGS_ASAN "-O3 -g -DNDEBUG -fsanitize=undefined" CACHE STRING "C++ ASAN Flags" FORCE)
2 changes: 1 addition & 1 deletion etc/gcc-toolchain.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@ set(CMAKE_CXX_FLAGS_DEBUG "-O0 -fno-inline -g3" CACHE STRING "C++ DEBUG Flags" F
set(CMAKE_CXX_FLAGS_RELEASE "-Ofast -g0 -DNDEBUG" CACHE STRING "C++ Release Flags" FORCE)
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O3 -g -DNDEBUG" CACHE STRING "C++ RelWithDebInfo Flags" FORCE)
set(CMAKE_CXX_FLAGS_TSAN "-O3 -g -DNDEBUG -fsanitize=thread" CACHE STRING "C++ TSAN Flags" FORCE)
set(CMAKE_CXX_FLAGS_ASAN "-O3 -g -DNDEBUG -fsanitize=address -fsanitize=undefined -fsanitize=leak" CACHE STRING "C++ ASAN Flags" FORCE)
set(CMAKE_CXX_FLAGS_ASAN "-O3 -g -DNDEBUG -fsanitize=address,undefined,leak" CACHE STRING "C++ ASAN Flags" FORCE)
2 changes: 2 additions & 0 deletions src/smd/optional/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ target_sources(
PRIVATE
optional.t.cpp
optional_ref.t.cpp
optional_monadic.t.cpp
optional_ref_monadic.t.cpp
)

target_link_libraries(optional_test optional)
Expand Down
181 changes: 63 additions & 118 deletions src/smd/optional/optional.h
Original file line number Diff line number Diff line change
Expand Up @@ -472,75 +472,89 @@ class optional {
}

template <class F>
constexpr auto and_then(F&& f) &
requires detail::is_optional<std::remove_cvref_t<std::invoke_result_t<F, T&>>>::value
{
using result = std::invoke_result_t<F, T&>;
return has_value() ? std::invoke(std::forward<F>(f), value()) : result(nullopt);
constexpr auto and_then(F&& f) & {
using U = std::invoke_result_t<F, T&>;
static_assert(detail::is_optional<std::remove_cvref_t<U>>::value);
if (has_value()) {
return std::invoke(std::forward<F>(f), value_);
} else {
return std::remove_cvref_t<U>();
}
}

template <class F>
constexpr auto and_then(F&& f) &&
requires detail::is_optional<std::remove_cvref_t<std::invoke_result_t<F, T&&>>>::value
{
using result = std::invoke_result_t<F, T&&>;
return has_value() ? std::invoke(std::forward<F>(f), value()) : result(nullopt);
constexpr auto and_then(F&& f) && {
using U = std::invoke_result_t<F, T&&>;
static_assert(detail::is_optional<std::remove_cvref_t<U>>::value);
if (has_value()) {
return std::invoke(std::forward<F>(f), std::move(value_));
} else {
return std::remove_cvref_t<U>();
}
}

template <class F>
constexpr auto and_then(F&& f) const&
requires detail::is_optional<std::remove_cvref_t<std::invoke_result_t<F, T&>>>::value
{
using result = std::invoke_result_t<F, const T&>;
return has_value() ? std::invoke(std::forward<F>(f), value()) : result(nullopt);
constexpr auto and_then(F&& f) const& {
using U = std::invoke_result_t<F, const T&>;
static_assert(detail::is_optional<std::remove_cvref_t<U>>::value);
if (has_value()) {
return std::invoke(std::forward<F>(f), value_);
} else {
return std::remove_cvref_t<U>();
}
}

template <class F>
constexpr auto and_then(F&& f) const&&
requires detail::is_optional<std::remove_cvref_t<std::invoke_result_t<F, T&>>>::value
{
using result = std::invoke_result_t<F, const T&>;
return has_value() ? std::invoke(std::forward<F>(f), value()) : result(nullopt);
constexpr auto and_then(F&& f) const&& {
using U = std::invoke_result_t<F, const T&&>;
static_assert(detail::is_optional<std::remove_cvref_t<U>>::value);
if (has_value()) {
return std::invoke(std::forward<F>(f), std::move(value_));
} else {
return std::remove_cvref_t<U>();
}
}

/// Carries out some operation on the stored object if there is one.
template <class F>
constexpr auto transform(F&& f) & {
return optional_map_impl(*this, std::forward<F>(f));
using U = std::invoke_result_t<F, T&>;
return (has_value()) ? optional<U>{std::invoke(std::forward<F>(f), value_)} : optional<U>{};
}

template <class F>
constexpr auto transform(F&& f) && {
return optional_map_impl(std::move(*this), std::forward<F>(f));
using U = std::invoke_result_t<F, T&&>;
return (has_value()) ? optional<U>{std::invoke(std::forward<F>(f), std::move(value_))} : optional<U>{};
}

template <class F>
constexpr auto transform(F&& f) const& {
return optional_map_impl(*this, std::forward<F>(f));
using U = std::invoke_result_t<F, const T&>;
return (has_value()) ? optional<U>{std::invoke(std::forward<F>(f), value_)} : optional<U>{};
}

template <class F>
constexpr auto transform(F&& f) const&& {
return optional_map_impl(std::move(*this), std::forward<F>(f));
using U = std::invoke_result_t<F, const T&>;
return (has_value()) ? optional<U>{std::invoke(std::forward<F>(f), value_)} : optional<U>{};
}

/// Calls `f` if the optional is empty
template <class F>
constexpr optional<T> or_else(F&& f) & {
if (has_value())
return *this;
return value_;

std::forward<F>(f)();
return nullopt;
return std::forward<F>(f)();
}

template <class F>
optional<T> or_else(F&& f) && {
if (has_value())
return std::move(*this);
return std::move(value_);

std::forward<F>(f)();
return nullopt;
return std::forward<F>(f)();
}

/// Assigns the stored value from `u`, destroying the old value if there
Expand Down Expand Up @@ -959,7 +973,7 @@ class optional<T&> {
T* value_; // exposition only

public:
// \rSec3[optional.ctor]{Constructors}
// \rSec3[optional.ctor]{Constructors}

constexpr optional() noexcept : value_(nullptr) {}

Expand All @@ -978,19 +992,19 @@ class optional<T&> {
template <class U>
constexpr explicit optional(const optional<U>& rhs) noexcept : optional(*rhs) {}

// \rSec3[optional.dtor]{Destructor}
// \rSec3[optional.dtor]{Destructor}

~optional() = default;

// \rSec3[optional.assign]{Assignment}
// \rSec3[optional.assign]{Assignment}

optional& operator=(nullopt_t) noexcept {
value_ = nullptr;
return *this;
}

optional& operator=(const optional& rhs) noexcept = default;
optional& operator=(optional&& rhs) noexcept = default;
optional& operator=(optional&& rhs) noexcept = default;

template <class U = T>
requires(!detail::is_optional<std::decay_t<U>>::value)
Expand Down Expand Up @@ -1021,31 +1035,12 @@ class optional<T&> {
// \rSec3[optional.observe]{Observers}
constexpr T* operator->() const noexcept { return value_; }

constexpr T& operator*() const& noexcept { return *value_; }
constexpr T&& operator*() const&& noexcept { return *value_; }
constexpr T& operator*() const noexcept { return *value_; }

constexpr explicit operator bool() const noexcept { return value_ != nullptr; }
constexpr bool has_value() const noexcept { return value_ != nullptr; }

constexpr T& value() const& {
if (has_value())
return *value_;
throw bad_optional_access();
}

constexpr T& value() & {
if (has_value())
return *value_;
throw bad_optional_access();
}

constexpr T&& value() && {
if (has_value())
return *value_;
throw bad_optional_access();
}

constexpr const T&& value() const&& {
constexpr T& value() const {
if (has_value())
return *value_;
throw bad_optional_access();
Expand All @@ -1055,86 +1050,36 @@ class optional<T&> {
constexpr T value_or(U&& u) const& {
static_assert(std::is_copy_constructible_v<T> && std::is_convertible_v<U&&, T>,
"T must be copy constructible and convertible from U");
return has_value() ? value() : static_cast<T>(std::forward<U>(u));
return has_value() ? *value_ : static_cast<T>(std::forward<U>(u));
}

template <class U>
constexpr T value_or(U&& u) && {
static_assert(std::is_move_constructible_v<T> && std::is_convertible_v<U&&, T>,
"T must be move constructible and convertible from U");
return has_value() ? value() : static_cast<T>(std::forward<U>(u));
return has_value() ? *value_ : static_cast<T>(std::forward<U>(u));
}

// \rSec3[optional.monadic]{Monadic operations}

template <class F>
constexpr auto and_then(F&& f) & {
using result = std::invoke_result_t<F, T&>;
static_assert(detail::is_optional<result>::value, "F must return an optional");

return has_value() ? std::invoke(std::forward<F>(f), value()) : result(nullopt);
}

template <class F>
constexpr auto and_then(F&& f) && {
using result = std::invoke_result_t<F, T&>;
static_assert(detail::is_optional<result>::value, "F must return an optional");

return has_value() ? std::invoke(std::forward<F>(f), value()) : result(nullopt);
}

template <class F>
constexpr auto and_then(F&& f) const& {
using result = std::invoke_result_t<F, const T&>;
static_assert(detail::is_optional<result>::value, "F must return an optional");

return has_value() ? std::invoke(std::forward<F>(f), value()) : result(nullopt);
}

template <class F>
constexpr auto and_then(F&& f) const&& {
using result = std::invoke_result_t<F, const T&>;
static_assert(detail::is_optional<result>::value, "F must return an optional");

return has_value() ? std::invoke(std::forward<F>(f), value()) : result(nullopt);
constexpr auto and_then(F&& f) const {
using U = std::invoke_result_t<F, T&>;
static_assert(detail::is_optional<U>::value, "F must return an optional");
return (has_value()) ? std::invoke(std::forward<F>(f), *value_) : std::remove_cvref_t<U>();
}

template <class F>
constexpr auto transform(F&& f) & {
return detail::optional_map_impl(*this, std::forward<F>(f));
constexpr auto transform(F&& f) const -> optional<std::invoke_result_t<F, T&>> {
using U = std::invoke_result_t<F, T&>;
return (has_value()) ? optional<U>{std::invoke(std::forward<F>(f), *value_)} : optional<U>{};
}

template <class F>
constexpr auto transform(F&& f) && {
return detail::optional_map_impl(std::move(*this), std::forward<F>(f));
}

template <class F>
constexpr auto transform(F&& f) const& {
return detail::optional_map_impl(*this, std::forward<F>(f));
}

template <class F>
constexpr auto transform(F&& f) const&& {
return detail::optional_map_impl(std::move(*this), std::forward<F>(f));
}

template <class F>
constexpr optional or_else(F&& f) && {
if (*this) {
return std::move(*this);
} else {
return std::forward<F>(f)();
}
}

template <class F>
constexpr optional or_else(F&& f) const& {
if (*this) {
return *this;
} else {
return std::forward<F>(f)();
}
constexpr optional or_else(F&& f) const {
using U = std::invoke_result_t<F>;
static_assert(std::is_same_v<std::remove_cvref_t<U>, optional>);
return has_value() ? *value_ : std::forward<F>(f)();
}

void reset() noexcept { value_ = nullptr; }
Expand Down
Loading