mirror of
https://github.com/Naios/continuable.git
synced 2025-12-07 01:06:44 +08:00
Some more work on the optional variant type
This commit is contained in:
parent
ca03c52d40
commit
224e8c835f
@ -46,6 +46,22 @@ namespace traits {
|
|||||||
template <std::size_t I, typename... Args>
|
template <std::size_t I, typename... Args>
|
||||||
using at_t = decltype(std::get<I>(std::declval<std::tuple<Args...>>()));
|
using at_t = decltype(std::get<I>(std::declval<std::tuple<Args...>>()));
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
template <typename T, typename... Args>
|
||||||
|
struct index_of_impl;
|
||||||
|
template <typename T, typename... Args>
|
||||||
|
struct index_of_impl<T, T, Args...> : std::integral_constant<std::size_t, 0U> {
|
||||||
|
};
|
||||||
|
template <typename T, typename U, typename... Args>
|
||||||
|
struct index_of_impl<T, U, Args...>
|
||||||
|
: std::integral_constant<std::size_t,
|
||||||
|
1 + index_of_impl<T, Args...>::value> {};
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
/// Evaluates to the index of T in the given pack
|
||||||
|
template <typename T, typename... Args>
|
||||||
|
using index_of_t = detail::index_of_impl<T, Args...>;
|
||||||
|
|
||||||
/// A tagging type for wrapping other types
|
/// A tagging type for wrapping other types
|
||||||
template <typename... T>
|
template <typename... T>
|
||||||
struct identity {};
|
struct identity {};
|
||||||
|
|||||||
@ -9,11 +9,11 @@
|
|||||||
|
|
||||||
Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is_slot hereby granted, free of charge, to any person obtaining a
|
||||||
of this software and associated documentation files(the "Software"), to deal
|
copy of this software and associated documentation files(the "Software"), to
|
||||||
in the Software without restriction, including without limitation the rights
|
deal in the Software without restriction, including without limitation the
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
|
rights to use, copy, modify, merge, publish, distribute, sublicense, and / or
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
sell copies of the Software, and to permit persons to whom the Software is_slot
|
||||||
furnished to do so, subject to the following conditions :
|
furnished to do so, subject to the following conditions :
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in
|
The above copyright notice and this permission notice shall be included in
|
||||||
@ -33,6 +33,7 @@
|
|||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <limits>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
@ -54,16 +55,24 @@ constexpr std::size_t max_size(std::initializer_list<std::size_t> list) {
|
|||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Declares the aligned storage union for the given types
|
||||||
template <typename... T>
|
template <typename... T>
|
||||||
using storage_of_t =
|
using storage_of_t =
|
||||||
std::aligned_storage_t<max_size({sizeof(T)...}), max_size({alignof(T)...})>;
|
std::aligned_storage_t<max_size({sizeof(T)...}), max_size({alignof(T)...})>;
|
||||||
|
|
||||||
|
/// The value fpr the empty slot
|
||||||
|
using slot_t = std::uint8_t;
|
||||||
|
|
||||||
|
/// The value which is used to mark the empty slot
|
||||||
|
using empty_slot =
|
||||||
|
std::integral_constant<slot_t, std::numeric_limits<slot_t>::max()>;
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct optional_variant_base {
|
struct optional_variant_base {
|
||||||
storage_of_t<T> storage_;
|
storage_of_t<T> storage_;
|
||||||
std::uint8_t slot_;
|
slot_t slot_;
|
||||||
|
|
||||||
constexpr optional_variant_base() : slot_(0U) {
|
constexpr optional_variant_base() : slot_(empty_slot::value) {
|
||||||
}
|
}
|
||||||
|
|
||||||
optional_variant_base(optional_variant_base const&) noexcept {
|
optional_variant_base(optional_variant_base const&) noexcept {
|
||||||
@ -89,14 +98,14 @@ struct optional_variant_move_base {
|
|||||||
assert(!other.is_empty());
|
assert(!other.is_empty());
|
||||||
|
|
||||||
#ifndef _NDEBUG
|
#ifndef _NDEBUG
|
||||||
me.set(slot_t::empty);
|
me.set_slot(empty_slot::value);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
other.visit([&](auto&& value) {
|
other.visit([&](auto&& value) {
|
||||||
// ...
|
// ...
|
||||||
me.init(std::move(value));
|
me.init(std::move(value));
|
||||||
});
|
});
|
||||||
me.set(other.get());
|
me.set_slot(other.get());
|
||||||
other.destroy();
|
other.destroy();
|
||||||
}
|
}
|
||||||
optional_variant_move_base&
|
optional_variant_move_base&
|
||||||
@ -112,7 +121,7 @@ struct optional_variant_move_base {
|
|||||||
// ...
|
// ...
|
||||||
me.init(std::move(value));
|
me.init(std::move(value));
|
||||||
});
|
});
|
||||||
me.set(other.get());
|
me.set_slot(other.get());
|
||||||
other.destroy();
|
other.destroy();
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
@ -131,14 +140,14 @@ struct optional_variant_copy_base : optional_variant_copy_base<Base> {
|
|||||||
assert(!other.is_empty());
|
assert(!other.is_empty());
|
||||||
|
|
||||||
#ifndef _NDEBUG
|
#ifndef _NDEBUG
|
||||||
me.set(slot_t::empty);
|
me.set_slot(empty_slot::value);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
other.visit([&](auto&& value) {
|
other.visit([&](auto&& value) {
|
||||||
// ...
|
// ...
|
||||||
me.init(std::move(value));
|
me.init(std::move(value));
|
||||||
});
|
});
|
||||||
me.set(other.get());
|
me.set_slot(other.get());
|
||||||
}
|
}
|
||||||
optional_variant_copy_base& operator=(optional_variant_copy_base&&) = default;
|
optional_variant_copy_base& operator=(optional_variant_copy_base&&) = default;
|
||||||
optional_variant_copy_base& operator=(optional_variant_copy_base const& right)
|
optional_variant_copy_base& operator=(optional_variant_copy_base const& right)
|
||||||
@ -154,7 +163,7 @@ struct optional_variant_copy_base : optional_variant_copy_base<Base> {
|
|||||||
// ...
|
// ...
|
||||||
me.init(std::move(value));
|
me.init(std::move(value));
|
||||||
});
|
});
|
||||||
me.set(other.get());
|
me.set_slot(other.get());
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -168,21 +177,22 @@ struct optional_variant_copy_base<Base, false>
|
|||||||
default;
|
default;
|
||||||
optional_variant_copy_base&
|
optional_variant_copy_base&
|
||||||
operator=(optional_variant_copy_base const&) = delete;
|
operator=(optional_variant_copy_base const&) = delete;
|
||||||
optional_variant_copy_base&
|
optional_variant_copy_base& operator=(optional_variant_copy_base&&) = default;
|
||||||
operator=(optional_variant_copy_base&& right) = default;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Deduces to a true_type if all parameters T satisfy the predicate.
|
||||||
|
template <template <typename> class Predicate, typename... T>
|
||||||
|
using every = traits::conjunction<Predicate<T>...>;
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
/// A class similar to the one in the expected proposal,
|
/// A class similar to the one in the optional_variant proposal,
|
||||||
/// however it is capable of carrying an exception_ptr if
|
/// however it is_slot capable of carrying an exception_ptr if
|
||||||
/// exceptions are used.
|
/// exceptions are used.
|
||||||
template <typename... T>
|
template <typename... T>
|
||||||
class optional_variant
|
class optional_variant : detail::optional_variant_copy_base<
|
||||||
: detail::optional_variant_copy_base<
|
optional_variant<T...>,
|
||||||
optional_variant<T...>,
|
detail::every<std::is_copy_constructible, T...>>,
|
||||||
std::is_copy_constructible<types::error_type>::value &&
|
detail::optional_variant_base<T...> {
|
||||||
std::is_copy_constructible<T>::value>,
|
|
||||||
detail::optional_variant_base<T...> {
|
|
||||||
|
|
||||||
template <typename>
|
template <typename>
|
||||||
friend class optional_variant;
|
friend class optional_variant;
|
||||||
@ -195,84 +205,48 @@ class optional_variant
|
|||||||
optional_variant(V&& value, detail::slot_t const slot) {
|
optional_variant(V&& value, detail::slot_t const slot) {
|
||||||
using type = std::decay_t<decltype(value)>;
|
using type = std::decay_t<decltype(value)>;
|
||||||
new (&this->storage_) type(std::forward<V>(value));
|
new (&this->storage_) type(std::forward<V>(value));
|
||||||
set(slot);
|
set_slot(slot);
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
constexpr expected() = default;
|
constexpr optional_variant() = default;
|
||||||
expected(expected const&) = default;
|
optional_variant(optional_variant const&) = default;
|
||||||
expected(expected&&) = default;
|
optional_variant(optional_variant&&) = default;
|
||||||
expected& operator=(expected const&) = default;
|
optional_variant& operator=(optional_variant const&) = default;
|
||||||
expected& operator=(expected&&) = default;
|
optional_variant& operator=(optional_variant&&) = default;
|
||||||
|
|
||||||
~expected() noexcept(
|
~optional_variant() noexcept(
|
||||||
std::is_nothrow_destructible<T>::value&&
|
detail::every<std::is_nothrow_destructible, T...>::value) {
|
||||||
std::is_nothrow_destructible<types::error_type>::value) {
|
|
||||||
weak_destroy();
|
weak_destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
explicit expected(T value) //
|
template <typename V, std::size_t Index =
|
||||||
: expected(std::move(value), detail::slot_t::value) {
|
traits::index_of_t<std::decay_t<V>, T...>::value>
|
||||||
}
|
explicit optional_variant(V&& value) //
|
||||||
explicit expected(types::error_type error) //
|
: optional_variant(std::forward<V>(value), Index) {
|
||||||
: expected(std::move(error), detail::slot_t::error) {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
expected& operator=(T value) {
|
optional_variant& operator=(T value) {
|
||||||
set_value(std::move(value));
|
set_value(std::move(value));
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
expected& operator=(types::error_type error) {
|
optional_variant& operator=(types::error_type error) {
|
||||||
set_exception(std::move(error));
|
set_exception(std::move(error));
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_value() const noexcept {
|
template <typename V, std::size_t Index =
|
||||||
assert(!is_empty());
|
traits::index_of_t<std::decay_t<V>, T...>::value>
|
||||||
return is(detail::slot_t::value);
|
bool is() const noexcept {
|
||||||
|
return is_slot(Index);
|
||||||
}
|
}
|
||||||
bool is_exception() const noexcept {
|
|
||||||
assert(!is_empty());
|
bool is_empty() const noexcept {
|
||||||
return is(detail::slot_t::error);
|
return is_slot(detail::empty_slot::value);
|
||||||
}
|
}
|
||||||
|
|
||||||
explicit constexpr operator bool() const noexcept {
|
explicit constexpr operator bool() const noexcept {
|
||||||
return is_value();
|
return !is_empty();
|
||||||
}
|
|
||||||
|
|
||||||
void set_value(T value) {
|
|
||||||
weak_destroy();
|
|
||||||
init(std::move(value));
|
|
||||||
set(detail::slot_t::value);
|
|
||||||
}
|
|
||||||
void set_exception(types::error_type error) {
|
|
||||||
weak_destroy();
|
|
||||||
init(std::move(error));
|
|
||||||
set(detail::slot_t::error);
|
|
||||||
}
|
|
||||||
|
|
||||||
T& get_value() noexcept {
|
|
||||||
assert(is_value());
|
|
||||||
return cast<T>();
|
|
||||||
}
|
|
||||||
T const& get_value() const noexcept {
|
|
||||||
assert(is_value());
|
|
||||||
return cast<T>();
|
|
||||||
}
|
|
||||||
types::error_type& get_exception() noexcept {
|
|
||||||
assert(is_exception());
|
|
||||||
return cast<types::error_type>();
|
|
||||||
}
|
|
||||||
types::error_type const& get_exception() const noexcept {
|
|
||||||
assert(is_exception());
|
|
||||||
return cast<types::error_type>();
|
|
||||||
}
|
|
||||||
|
|
||||||
T& operator*() noexcept {
|
|
||||||
return get_value();
|
|
||||||
}
|
|
||||||
T const& operator*() const noexcept {
|
|
||||||
return get_value();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -284,7 +258,7 @@ private:
|
|||||||
case detail::slot_t::error:
|
case detail::slot_t::error:
|
||||||
return std::forward<V>(visitor)(cast<types::error_type>());
|
return std::forward<V>(visitor)(cast<types::error_type>());
|
||||||
default:
|
default:
|
||||||
// We don't visit when there is no value
|
// We don't visit when there is_slot no value
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -296,15 +270,11 @@ private:
|
|||||||
case detail::slot_t::error:
|
case detail::slot_t::error:
|
||||||
return std::forward<V>(visitor)(cast<types::error_type>());
|
return std::forward<V>(visitor)(cast<types::error_type>());
|
||||||
default:
|
default:
|
||||||
// We don't visit when there is no value
|
// We don't visit when there is_slot no value
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_empty() const noexcept {
|
|
||||||
return is(detail::slot_t::empty);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename V>
|
template <typename V>
|
||||||
V& cast() noexcept {
|
V& cast() noexcept {
|
||||||
assert(!is_empty());
|
assert(!is_empty());
|
||||||
@ -326,7 +296,7 @@ private:
|
|||||||
weak_destroy();
|
weak_destroy();
|
||||||
|
|
||||||
#ifdef NDEBUG
|
#ifdef NDEBUG
|
||||||
set(detail::slot_t::empty);
|
set_slot(detail::empty_slot::value);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
void weak_destroy() {
|
void weak_destroy() {
|
||||||
@ -336,67 +306,19 @@ private:
|
|||||||
});
|
});
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
set(detail::slot_t::empty);
|
set_slot(detail::empty_slot::value);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
detail::slot_t get() const noexcept {
|
detail::slot_t get() const noexcept {
|
||||||
return this->slot_;
|
return this->slot_;
|
||||||
}
|
}
|
||||||
bool is(detail::slot_t const slot) const noexcept {
|
bool is_slot(detail::slot_t const slot) const noexcept {
|
||||||
return get() == slot;
|
return get() == slot;
|
||||||
}
|
}
|
||||||
void set(detail::slot_t const slot) {
|
void set_slot(detail::slot_t const slot) {
|
||||||
this->slot_ = slot;
|
this->slot_ = slot;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace detail {
|
|
||||||
struct void_guard_tag {};
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
struct expected_result_trait;
|
|
||||||
template <>
|
|
||||||
struct expected_result_trait<traits::identity<>> {
|
|
||||||
using expected_type = expected<void_guard_tag>;
|
|
||||||
|
|
||||||
static constexpr void_guard_tag wrap() noexcept {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
static void unwrap(expected_type&& e) {
|
|
||||||
assert(e.is_value());
|
|
||||||
(void)e;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
template <typename T>
|
|
||||||
struct expected_result_trait<traits::identity<T>> {
|
|
||||||
using expected_type = expected<T>;
|
|
||||||
|
|
||||||
static auto wrap(T arg) {
|
|
||||||
return std::move(arg);
|
|
||||||
}
|
|
||||||
static auto unwrap(expected_type&& e) {
|
|
||||||
assert(e.is_value());
|
|
||||||
return std::move(e.get_value());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
template <typename First, typename Second, typename... Rest>
|
|
||||||
struct expected_result_trait<traits::identity<First, Second, Rest...>> {
|
|
||||||
using expected_type = expected<std::tuple<First, Second, Rest...>>;
|
|
||||||
|
|
||||||
static auto wrap(First first, Second second, Rest... rest) {
|
|
||||||
return std::make_tuple(std::move(first), std::move(second),
|
|
||||||
std::move(rest)...);
|
|
||||||
}
|
|
||||||
static auto unwrap(expected_type&& e) {
|
|
||||||
assert(e.is_value());
|
|
||||||
return std::move(e.get_value());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} // namespace detail
|
|
||||||
|
|
||||||
template <typename Continuable>
|
|
||||||
using expected_result_trait_t = detail::expected_result_trait<decltype(
|
|
||||||
hints::hint_of(traits::identify<Continuable>{}))>;
|
|
||||||
} // namespace util
|
} // namespace util
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
} // namespace cti
|
} // namespace cti
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user