mirror of
https://github.com/Naios/continuable.git
synced 2025-12-07 01:06:44 +08:00
Replace the result<...> implementation by a lighter one
* result<...> only moveable now, the conditional copy capabilities were removed * If you require the optional copy capability use a std::variant implementation of your choice * Closes #13
This commit is contained in:
parent
5f8b2aa317
commit
1e39bd85dd
@ -34,8 +34,8 @@
|
|||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <continuable/continuable-primitives.hpp>
|
#include <continuable/continuable-primitives.hpp>
|
||||||
#include <continuable/detail/utility/flat-variant.hpp>
|
|
||||||
#include <continuable/detail/utility/result-trait.hpp>
|
#include <continuable/detail/utility/result-trait.hpp>
|
||||||
|
#include <continuable/detail/utility/result-variant.hpp>
|
||||||
#include <continuable/detail/utility/traits.hpp>
|
#include <continuable/detail/utility/traits.hpp>
|
||||||
#include <continuable/detail/utility/util.hpp>
|
#include <continuable/detail/utility/util.hpp>
|
||||||
|
|
||||||
@ -49,6 +49,11 @@ namespace cti {
|
|||||||
/// or was cancelled.
|
/// or was cancelled.
|
||||||
/// \{
|
/// \{
|
||||||
|
|
||||||
|
/// A tag which represents present void values in result.
|
||||||
|
///
|
||||||
|
/// \since 4.0.0
|
||||||
|
using void_arg_t = detail::void_arg_t;
|
||||||
|
|
||||||
/// A class which is convertible to any \ref result and that definitely holds no
|
/// A class which is convertible to any \ref result and that definitely holds no
|
||||||
/// value so the real result gets invalidated when this object is passed to it.
|
/// value so the real result gets invalidated when this object is passed to it.
|
||||||
///
|
///
|
||||||
@ -137,43 +142,53 @@ public:
|
|||||||
template <typename... T>
|
template <typename... T>
|
||||||
class result {
|
class result {
|
||||||
using trait_t = detail::result_trait<T...>;
|
using trait_t = detail::result_trait<T...>;
|
||||||
using surrogate_t = typename trait_t::surrogate_t;
|
|
||||||
|
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
explicit result(detail::init_arg_t, Args&&... values)
|
explicit result(detail::init_result_arg_t arg, Args&&... values)
|
||||||
: variant_(trait_t::wrap(std::forward<Args>(values)...)) {}
|
: variant_(arg, trait_t::wrap(std::forward<Args>(values)...)) {}
|
||||||
explicit result(detail::init_arg_t, exception_t exception)
|
explicit result(detail::init_exception_arg_t arg, exception_t exception)
|
||||||
: variant_(std::move(exception)) {}
|
: variant_(arg, std::move(exception)) {}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using value_t = typename trait_t::value_t;
|
using value_t = typename trait_t::value_t;
|
||||||
|
using value_placeholder_t = typename trait_t::surrogate_t;
|
||||||
|
|
||||||
template <typename FirstArg, typename... Args>
|
template <typename FirstArg, typename... Args>
|
||||||
explicit result(FirstArg&& first, Args&&... values)
|
explicit result(FirstArg&& first, Args&&... values)
|
||||||
: variant_(trait_t::wrap(std::forward<FirstArg>(first),
|
: variant_(detail::init_result_arg_t{},
|
||||||
|
trait_t::wrap(std::forward<FirstArg>(first),
|
||||||
std::forward<Args>(values)...)) {}
|
std::forward<Args>(values)...)) {}
|
||||||
|
|
||||||
result() = default;
|
result() = default;
|
||||||
result(result const&) = default;
|
result(result const&) = delete;
|
||||||
result(result&&) = default;
|
result(result&&) = default;
|
||||||
result& operator=(result const&) = default;
|
result& operator=(result const&) = delete;
|
||||||
result& operator=(result&&) = default;
|
result& operator=(result&&) = default;
|
||||||
~result() = default;
|
~result() = default;
|
||||||
|
|
||||||
explicit result(exception_t exception)
|
explicit result(exception_t exception)
|
||||||
: variant_(std::move(exception)) {}
|
: variant_(detail::init_exception_arg_t{}, std::move(exception)) {}
|
||||||
/* implicit */ result(empty_result) {}
|
/* implicit */ result(empty_result) {}
|
||||||
/* implicit */ result(exceptional_result exceptional_result)
|
/* implicit */ result(exceptional_result exceptional_result)
|
||||||
: variant_(std::move(exceptional_result.get_exception())) {}
|
: variant_(detail::init_exception_arg_t{},
|
||||||
|
std::move(exceptional_result.get_exception())) {}
|
||||||
/* implicit */ result(cancellation_result)
|
/* implicit */ result(cancellation_result)
|
||||||
: variant_(exception_t{}) {}
|
: variant_(detail::init_exception_arg_t{}, exception_t{}) {}
|
||||||
|
|
||||||
result& operator=(empty_result) {
|
result& operator=(empty_result) {
|
||||||
set_empty();
|
variant_.set_empty();
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
result& operator=(exceptional_result exceptional_result) {
|
result& operator=(value_placeholder_t value) {
|
||||||
set_exception(std::move(exceptional_result.get_exception()));
|
variant_.set_value(std::move(value));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
result& operator=(exceptional_result exception) {
|
||||||
|
variant_.set_exception(std::move(exception.get_exception()));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
result& operator=(cancellation_result) {
|
||||||
|
variant_.set_exception({});
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -183,15 +198,15 @@ public:
|
|||||||
}
|
}
|
||||||
/// Set the result to a the state which holds the corresponding value
|
/// Set the result to a the state which holds the corresponding value
|
||||||
void set_value(T... values) {
|
void set_value(T... values) {
|
||||||
variant_ = trait_t::wrap(std::move(values)...);
|
variant_.set_value(trait_t::wrap(std::move(values)...));
|
||||||
}
|
}
|
||||||
/// Set the result into a state which holds the corresponding exception
|
/// Set the result into a state which holds the corresponding exception
|
||||||
void set_exception(exception_t exception) {
|
void set_exception(exception_t exception) {
|
||||||
variant_ = std::move(exception);
|
variant_.set_exception(std::move(exception));
|
||||||
}
|
}
|
||||||
/// Set the result into a state which holds the cancellation token
|
/// Set the result into a state which holds the cancellation token
|
||||||
void set_canceled() {
|
void set_canceled() {
|
||||||
variant_ = exception_t{};
|
variant_.set_exception(exception_t{});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if the state of the result is empty
|
/// Returns true if the state of the result is empty
|
||||||
@ -200,11 +215,11 @@ public:
|
|||||||
}
|
}
|
||||||
/// Returns true if the state of the result holds the result
|
/// Returns true if the state of the result holds the result
|
||||||
bool is_value() const noexcept {
|
bool is_value() const noexcept {
|
||||||
return variant_.template is<surrogate_t>();
|
return variant_.is_value();
|
||||||
}
|
}
|
||||||
/// Returns true if the state of the result holds a present exception
|
/// Returns true if the state of the result holds a present exception
|
||||||
bool is_exception() const noexcept {
|
bool is_exception() const noexcept {
|
||||||
return variant_.template is<exception_t>();
|
return variant_.is_exception();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \copydoc is_value
|
/// \copydoc is_value
|
||||||
@ -215,15 +230,15 @@ public:
|
|||||||
/// Returns the values of the result, if the result doesn't hold the value
|
/// Returns the values of the result, if the result doesn't hold the value
|
||||||
/// the behaviour is undefined but will assert in debug mode.
|
/// the behaviour is undefined but will assert in debug mode.
|
||||||
decltype(auto) get_value() & noexcept {
|
decltype(auto) get_value() & noexcept {
|
||||||
return trait_t::unwrap(variant_.template cast<surrogate_t>());
|
return trait_t::unwrap(variant_.get_value());
|
||||||
}
|
}
|
||||||
///\copydoc get_value
|
///\copydoc get_value
|
||||||
decltype(auto) get_value() const& noexcept {
|
decltype(auto) get_value() const& noexcept {
|
||||||
return trait_t::unwrap(variant_.template cast<surrogate_t>());
|
return trait_t::unwrap(variant_.get_value());
|
||||||
}
|
}
|
||||||
///\copydoc get_value
|
///\copydoc get_value
|
||||||
decltype(auto) get_value() && noexcept {
|
decltype(auto) get_value() && noexcept {
|
||||||
return trait_t::unwrap(std::move(variant_).template cast<surrogate_t>());
|
return trait_t::unwrap(std::move(variant_.get_value()));
|
||||||
}
|
}
|
||||||
|
|
||||||
///\copydoc get_value
|
///\copydoc get_value
|
||||||
@ -236,30 +251,30 @@ public:
|
|||||||
}
|
}
|
||||||
///\copydoc get_value
|
///\copydoc get_value
|
||||||
decltype(auto) operator*() && noexcept {
|
decltype(auto) operator*() && noexcept {
|
||||||
return std::move(*this).get_value();
|
return std::move(variant_.get_value());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the exception of the result, if the result doesn't hold an
|
/// Returns the exception of the result, if the result doesn't hold an
|
||||||
/// exception the behaviour is undefined but will assert in debug mode.
|
/// exception the behaviour is undefined but will assert in debug mode.
|
||||||
exception_t& get_exception() & noexcept {
|
exception_t& get_exception() & noexcept {
|
||||||
return variant_.template cast<exception_t>();
|
return variant_.get_exception();
|
||||||
}
|
}
|
||||||
/// \copydoc get_exception
|
/// \copydoc get_exception
|
||||||
exception_t const& get_exception() const& noexcept {
|
exception_t const& get_exception() const& noexcept {
|
||||||
return variant_.template cast<exception_t>();
|
return variant_.get_exception();
|
||||||
}
|
}
|
||||||
/// \copydoc get_exception
|
/// \copydoc get_exception
|
||||||
exception_t&& get_exception() && noexcept {
|
exception_t&& get_exception() && noexcept {
|
||||||
return std::move(variant_).template cast<exception_t>();
|
return std::move(variant_.get_exception());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a present result from the given values
|
/// Creates a present result from the given values
|
||||||
static result from(T... values) {
|
static result from(T... values) {
|
||||||
return result{detail::init_arg_t{}, std::move(values)...};
|
return result{detail::init_result_arg_t{}, std::move(values)...};
|
||||||
}
|
}
|
||||||
/// Creates a present result from the given exception
|
/// Creates a present result from the given exception
|
||||||
static result from(exception_arg_t, exception_t exception) {
|
static result from(exception_arg_t, exception_t exception) {
|
||||||
return result{detail::init_arg_t{}, std::move(exception)};
|
return result{detail::init_exception_arg_t{}, std::move(exception)};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates an empty result
|
/// Creates an empty result
|
||||||
@ -268,7 +283,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
detail::container::flat_variant<surrogate_t, exception_t> variant_;
|
detail::result_variant<value_placeholder_t> variant_;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Returns the value at position I of the given result
|
/// Returns the value at position I of the given result
|
||||||
|
|||||||
@ -38,7 +38,6 @@
|
|||||||
#include <continuable/continuable-result.hpp>
|
#include <continuable/continuable-result.hpp>
|
||||||
#include <continuable/continuable-traverse.hpp>
|
#include <continuable/continuable-traverse.hpp>
|
||||||
#include <continuable/detail/core/base.hpp>
|
#include <continuable/detail/core/base.hpp>
|
||||||
#include <continuable/detail/utility/flat-variant.hpp>
|
|
||||||
#include <continuable/detail/utility/traits.hpp>
|
#include <continuable/detail/utility/traits.hpp>
|
||||||
|
|
||||||
namespace cti {
|
namespace cti {
|
||||||
@ -55,22 +54,25 @@ namespace connection {
|
|||||||
/// - single async value -> single value
|
/// - single async value -> single value
|
||||||
/// - multiple async value -> tuple of async values.
|
/// - multiple async value -> tuple of async values.
|
||||||
namespace aggregated {
|
namespace aggregated {
|
||||||
|
|
||||||
/// Guards a type to be default constructible,
|
/// Guards a type to be default constructible,
|
||||||
/// and wraps it into an optional type if it isn't default constructible.
|
/// and wraps it into an optional type if it isn't default constructible.
|
||||||
template <typename T>
|
template <typename T>
|
||||||
using lazy_value_t = std::conditional_t<std::is_default_constructible<T>::value,
|
using lazy_value_t = std::conditional_t<std::is_default_constructible<T>::value,
|
||||||
T, container::flat_variant<T>>;
|
T, result<T>>;
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
decltype(auto) unpack_lazy(T&& value) {
|
decltype(auto) unpack_lazy(std::true_type /*is_default_constructible*/,
|
||||||
|
T&& value) {
|
||||||
return std::forward<T>(value);
|
return std::forward<T>(value);
|
||||||
}
|
}
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T&& unpack_lazy(container::flat_variant<T>&& value) {
|
T&& unpack_lazy(std::false_type /*is_default_constructible*/,
|
||||||
assert(value.template is<T>() &&
|
result<T>&& value) {
|
||||||
|
assert(value.is_value() &&
|
||||||
"The connection was finalized before all values were present!");
|
"The connection was finalized before all values were present!");
|
||||||
|
|
||||||
return std::move(value.template cast<T>());
|
return std::move(value).get_value();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Continuable>
|
template <typename Continuable>
|
||||||
@ -82,8 +84,7 @@ class continuable_box<continuable_base<Data, identity<>>> {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
explicit continuable_box(continuable_base<Data, identity<>>&& continuable)
|
explicit continuable_box(continuable_base<Data, identity<>>&& continuable)
|
||||||
: continuable_(std::move(continuable)) {
|
: continuable_(std::move(continuable)) {}
|
||||||
}
|
|
||||||
|
|
||||||
auto const& peek() const {
|
auto const& peek() const {
|
||||||
return continuable_;
|
return continuable_;
|
||||||
@ -93,13 +94,13 @@ public:
|
|||||||
return std::move(continuable_);
|
return std::move(continuable_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void assign() {
|
void assign() {}
|
||||||
}
|
|
||||||
|
|
||||||
auto unbox() && {
|
auto unbox() && {
|
||||||
return spread_this();
|
return spread_this();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Data, typename First>
|
template <typename Data, typename First>
|
||||||
class continuable_box<continuable_base<Data, identity<First>>> {
|
class continuable_box<continuable_base<Data, identity<First>>> {
|
||||||
|
|
||||||
@ -109,8 +110,7 @@ class continuable_box<continuable_base<Data, identity<First>>> {
|
|||||||
public:
|
public:
|
||||||
explicit continuable_box(
|
explicit continuable_box(
|
||||||
continuable_base<Data, identity<First>>&& continuable)
|
continuable_base<Data, identity<First>>&& continuable)
|
||||||
: continuable_(std::move(continuable)) {
|
: continuable_(std::move(continuable)) {}
|
||||||
}
|
|
||||||
|
|
||||||
auto const& peek() const {
|
auto const& peek() const {
|
||||||
return continuable_;
|
return continuable_;
|
||||||
@ -125,7 +125,8 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto unbox() && {
|
auto unbox() && {
|
||||||
return unpack_lazy(std::move(first_));
|
return unpack_lazy(std::is_default_constructible<First>{},
|
||||||
|
std::move(first_));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
template <typename Data, typename First, typename Second, typename... Rest>
|
template <typename Data, typename First, typename Second, typename... Rest>
|
||||||
@ -138,8 +139,7 @@ class continuable_box<
|
|||||||
public:
|
public:
|
||||||
explicit continuable_box(
|
explicit continuable_box(
|
||||||
continuable_base<Data, identity<First, Second, Rest...>>&& continuable)
|
continuable_base<Data, identity<First, Second, Rest...>>&& continuable)
|
||||||
: continuable_(std::move(continuable)) {
|
: continuable_(std::move(continuable)) {}
|
||||||
}
|
|
||||||
|
|
||||||
auto const& peek() const {
|
auto const& peek() const {
|
||||||
return continuable_;
|
return continuable_;
|
||||||
@ -159,7 +159,9 @@ public:
|
|||||||
[](auto&&... args) {
|
[](auto&&... args) {
|
||||||
return spread_this(std::forward<decltype(args)>(args)...);
|
return spread_this(std::forward<decltype(args)>(args)...);
|
||||||
},
|
},
|
||||||
unpack_lazy(std::move(args_)));
|
unpack_lazy(
|
||||||
|
std::is_default_constructible<std::tuple<First, Second, Rest...>>{},
|
||||||
|
std::move(args_)));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -1,379 +0,0 @@
|
|||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
/~` _ _ _|_. _ _ |_ | _
|
|
||||||
\_,(_)| | | || ||_|(_||_)|(/_
|
|
||||||
|
|
||||||
https://github.com/Naios/continuable
|
|
||||||
v4.0.0
|
|
||||||
|
|
||||||
Copyright(c) 2015 - 2019 Denis Blank <denis.blank at outlook dot com>
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files(the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions :
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in
|
|
||||||
all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
**/
|
|
||||||
|
|
||||||
#ifndef CONTINUABLE_DETAIL_FLAT_VARIANT_HPP_INCLUDED
|
|
||||||
#define CONTINUABLE_DETAIL_FLAT_VARIANT_HPP_INCLUDED
|
|
||||||
|
|
||||||
#include <cassert>
|
|
||||||
#include <cstddef>
|
|
||||||
#include <cstdint>
|
|
||||||
#include <limits>
|
|
||||||
#include <memory>
|
|
||||||
#include <type_traits>
|
|
||||||
#include <utility>
|
|
||||||
#include <continuable/detail/utility/traits.hpp>
|
|
||||||
|
|
||||||
namespace cti {
|
|
||||||
namespace detail {
|
|
||||||
namespace container {
|
|
||||||
namespace detail {
|
|
||||||
// We don't want to pull the algorithm header in
|
|
||||||
constexpr std::size_t max_element_of(std::initializer_list<std::size_t> list) {
|
|
||||||
std::size_t m = 0;
|
|
||||||
for (auto current : list) {
|
|
||||||
if (current > m) {
|
|
||||||
m = current;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Workarround for a regression introduced in ~ MSVC 15.8.1
|
|
||||||
template <typename T>
|
|
||||||
using size_of_helper = std::integral_constant<std::size_t, sizeof(T)>;
|
|
||||||
template <typename T>
|
|
||||||
using align_of_helper = std::integral_constant<std::size_t, alignof(T)>;
|
|
||||||
|
|
||||||
template <typename... T>
|
|
||||||
constexpr auto storage_of_impl(identity<T...>) {
|
|
||||||
constexpr auto size = max_element_of({(size_of_helper<T>::value)...});
|
|
||||||
constexpr auto align = max_element_of({(align_of_helper<T>::value)...});
|
|
||||||
return std::aligned_storage_t<size, align>{};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Declares the aligned storage union for the given types
|
|
||||||
template <typename... T>
|
|
||||||
using storage_of_t = decltype(storage_of_impl(identity<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>
|
|
||||||
struct flat_variant_base {
|
|
||||||
storage_of_t<T...> storage_;
|
|
||||||
slot_t slot_;
|
|
||||||
|
|
||||||
constexpr flat_variant_base() : slot_(empty_slot::value) {
|
|
||||||
}
|
|
||||||
|
|
||||||
flat_variant_base(flat_variant_base const&) noexcept {
|
|
||||||
}
|
|
||||||
flat_variant_base(flat_variant_base&&) noexcept {
|
|
||||||
}
|
|
||||||
flat_variant_base& operator=(flat_variant_base const&) {
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
flat_variant_base& operator=(flat_variant_base&&) {
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename Base>
|
|
||||||
struct flat_variant_move_base {
|
|
||||||
constexpr flat_variant_move_base() = default;
|
|
||||||
|
|
||||||
flat_variant_move_base(flat_variant_move_base const&) = default;
|
|
||||||
explicit flat_variant_move_base(flat_variant_move_base&& right) {
|
|
||||||
Base& me = *static_cast<Base*>(this);
|
|
||||||
Base& other = *static_cast<Base*>(&right);
|
|
||||||
|
|
||||||
if (other.is_empty()) {
|
|
||||||
me.set_slot(empty_slot::value);
|
|
||||||
} else {
|
|
||||||
|
|
||||||
other.visit([&](auto&& value) {
|
|
||||||
#ifndef NDEBUG
|
|
||||||
me.set_slot(empty_slot::value);
|
|
||||||
#endif
|
|
||||||
// NOLINTNEXTLINE(misc-move-forwarding-reference)
|
|
||||||
me.init(std::move(value), other.get_slot());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
other.destroy();
|
|
||||||
}
|
|
||||||
flat_variant_move_base& operator=(flat_variant_move_base const&) = default;
|
|
||||||
flat_variant_move_base& operator=(flat_variant_move_base&& right) {
|
|
||||||
Base& me = *static_cast<Base*>(this);
|
|
||||||
Base& other = *static_cast<Base*>(&right);
|
|
||||||
|
|
||||||
me.weak_destroy();
|
|
||||||
|
|
||||||
if (other.is_empty()) {
|
|
||||||
me.set_slot(empty_slot::value);
|
|
||||||
} else {
|
|
||||||
other.visit([&](auto&& value) {
|
|
||||||
// ...
|
|
||||||
me.init(std::move(value), other.get_slot());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
other.destroy();
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
template <typename Base, bool IsCopyable /*= true*/>
|
|
||||||
struct flat_variant_copy_base : flat_variant_move_base<Base> {
|
|
||||||
constexpr flat_variant_copy_base() = default;
|
|
||||||
|
|
||||||
flat_variant_copy_base(flat_variant_copy_base&&) = default;
|
|
||||||
explicit flat_variant_copy_base(flat_variant_copy_base const& right)
|
|
||||||
: flat_variant_move_base<Base>()
|
|
||||||
// TODO noexcept(Base::is_nothrow_move_constructible)
|
|
||||||
{
|
|
||||||
Base& me = *static_cast<Base*>(this);
|
|
||||||
Base const& other = *static_cast<Base const*>(&right);
|
|
||||||
|
|
||||||
if (other.is_empty()) {
|
|
||||||
me.set_slot(empty_slot::value);
|
|
||||||
} else {
|
|
||||||
other.visit([&](auto&& value) {
|
|
||||||
#ifndef NDEBUG
|
|
||||||
me.set_slot(empty_slot::value);
|
|
||||||
#endif
|
|
||||||
me.init(std::move(value), other.get_slot());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
flat_variant_copy_base& operator=(flat_variant_copy_base&&) = default;
|
|
||||||
flat_variant_copy_base& operator=(flat_variant_copy_base const& right)
|
|
||||||
// TODO noexcept(Base::is_nothrow_move_constructible)
|
|
||||||
{
|
|
||||||
Base& me = *static_cast<Base*>(this);
|
|
||||||
Base const& other = *static_cast<Base const*>(&right);
|
|
||||||
|
|
||||||
me.weak_destroy();
|
|
||||||
|
|
||||||
if (other.is_empty()) {
|
|
||||||
me.set_slot(empty_slot::value);
|
|
||||||
} else {
|
|
||||||
other.visit([&](auto&& value) {
|
|
||||||
// ...
|
|
||||||
me.init(std::move(value), other.get_slot());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
template <typename Base /*, bool IsCopyable = false*/>
|
|
||||||
struct flat_variant_copy_base<Base, false> : flat_variant_move_base<Base> {
|
|
||||||
constexpr flat_variant_copy_base() = default;
|
|
||||||
|
|
||||||
flat_variant_copy_base(flat_variant_copy_base const&) = delete;
|
|
||||||
explicit flat_variant_copy_base(flat_variant_copy_base&& right) = default;
|
|
||||||
flat_variant_copy_base& operator=(flat_variant_copy_base const&) = delete;
|
|
||||||
flat_variant_copy_base& operator=(flat_variant_copy_base&&) = 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
|
|
||||||
|
|
||||||
/// A class similar to the one in the variant proposal,
|
|
||||||
/// however it is capable of carrying an empty state by default.
|
|
||||||
template <typename... T>
|
|
||||||
class flat_variant;
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
struct is_flat_variant : std::false_type {};
|
|
||||||
template <typename... T>
|
|
||||||
struct is_flat_variant<flat_variant<T...>> : std::true_type {};
|
|
||||||
|
|
||||||
template <typename... T>
|
|
||||||
class flat_variant
|
|
||||||
: detail::flat_variant_copy_base<
|
|
||||||
flat_variant<T...>,
|
|
||||||
detail::every<std::is_copy_constructible, T...>::value>,
|
|
||||||
detail::flat_variant_base<T...> {
|
|
||||||
|
|
||||||
static_assert(sizeof...(T) > 0, "At least one paremeter T is required!");
|
|
||||||
|
|
||||||
template <typename...>
|
|
||||||
friend class flat_variant;
|
|
||||||
template <typename>
|
|
||||||
friend struct detail::flat_variant_move_base;
|
|
||||||
template <typename, bool>
|
|
||||||
friend struct detail::flat_variant_copy_base;
|
|
||||||
|
|
||||||
template <typename V>
|
|
||||||
flat_variant(V&& value, detail::slot_t const slot) {
|
|
||||||
#ifndef NDEBUG
|
|
||||||
set_slot(detail::empty_slot::value);
|
|
||||||
#endif
|
|
||||||
init(std::forward<V>(value), slot);
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
constexpr flat_variant() = default;
|
|
||||||
flat_variant(flat_variant const&) = default;
|
|
||||||
flat_variant(flat_variant&&) = default;
|
|
||||||
flat_variant& operator=(flat_variant const&) = default;
|
|
||||||
flat_variant& operator=(flat_variant&&) = default;
|
|
||||||
|
|
||||||
~flat_variant() noexcept(
|
|
||||||
detail::every<std::is_nothrow_destructible, T...>::value) {
|
|
||||||
weak_destroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
template <
|
|
||||||
typename V,
|
|
||||||
std::enable_if_t<!is_flat_variant<std::decay_t<V>>::value>* = nullptr>
|
|
||||||
// Since the flat_variant isn't allowed through SFINAE
|
|
||||||
// this overload is safed against the linted issue.
|
|
||||||
// NOLINTNEXTLINE(misc-forwarding-reference-overload)
|
|
||||||
explicit flat_variant(V&& value)
|
|
||||||
: flat_variant(std::forward<V>(value),
|
|
||||||
traits::index_of_t<std::decay_t<V>, T...>::value) {
|
|
||||||
}
|
|
||||||
|
|
||||||
template <
|
|
||||||
typename V,
|
|
||||||
std::enable_if_t<!is_flat_variant<std::decay_t<V>>::value>* = nullptr>
|
|
||||||
flat_variant& operator=(V&& value) {
|
|
||||||
weak_destroy();
|
|
||||||
init(std::forward<V>(value),
|
|
||||||
traits::index_of_t<std::decay_t<V>, T...>::value);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
void set_empty() {
|
|
||||||
weak_destroy();
|
|
||||||
set_slot(detail::empty_slot::value);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename V, std::size_t Index =
|
|
||||||
traits::index_of_t<std::decay_t<V>, T...>::value>
|
|
||||||
bool is() const noexcept {
|
|
||||||
return is_slot(Index);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_empty() const noexcept {
|
|
||||||
return is_slot(detail::empty_slot::value);
|
|
||||||
}
|
|
||||||
|
|
||||||
explicit constexpr operator bool() const noexcept {
|
|
||||||
return !is_empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename V>
|
|
||||||
V& cast() & noexcept {
|
|
||||||
assert(is_slot(traits::index_of_t<std::decay_t<V>, T...>::value));
|
|
||||||
return *reinterpret_cast<std::decay_t<V>*>(&this->storage_);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename V>
|
|
||||||
V const& cast() const& noexcept {
|
|
||||||
assert(is_slot(traits::index_of_t<std::decay_t<V>, T...>::value));
|
|
||||||
return *reinterpret_cast<std::decay_t<V> const*>(&this->storage_);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename V>
|
|
||||||
V&& cast() && noexcept {
|
|
||||||
assert(is_slot(traits::index_of_t<std::decay_t<V>, T...>::value));
|
|
||||||
auto& value = *reinterpret_cast<std::decay_t<V>*>(&this->storage_);
|
|
||||||
return std::move(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
template <typename C, typename V>
|
|
||||||
static void visit_dispatch(flat_variant* me, V&& visitor) {
|
|
||||||
std::forward<V>(visitor)(me->cast<C>());
|
|
||||||
}
|
|
||||||
template <typename C, typename V>
|
|
||||||
static void visit_dispatch_const(flat_variant const* me, V&& visitor) {
|
|
||||||
std::forward<V>(visitor)(me->cast<C>());
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename V>
|
|
||||||
void visit(V&& visitor) {
|
|
||||||
if (!is_empty()) {
|
|
||||||
using callback_t = void (*)(flat_variant*, V &&);
|
|
||||||
constexpr callback_t const callbacks[] = {&visit_dispatch<T, V>...};
|
|
||||||
callbacks[get_slot()](this, std::forward<V>(visitor));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
template <typename V>
|
|
||||||
void visit(V&& visitor) const {
|
|
||||||
if (!is_empty()) {
|
|
||||||
using callback_t = void (*)(flat_variant const*, V&&);
|
|
||||||
constexpr callback_t const callbacks[] = {&visit_dispatch_const<T, V>...};
|
|
||||||
callbacks[get_slot()](this, std::forward<V>(visitor));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename V>
|
|
||||||
void init(V&& value, detail::slot_t const slot) {
|
|
||||||
assert(is_empty());
|
|
||||||
assert(sizeof(this->storage_) >= sizeof(std::decay_t<V>));
|
|
||||||
|
|
||||||
using type = std::decay_t<V>;
|
|
||||||
new (&this->storage_) type(std::forward<V>(value));
|
|
||||||
set_slot(slot);
|
|
||||||
}
|
|
||||||
void destroy() {
|
|
||||||
weak_destroy();
|
|
||||||
|
|
||||||
#ifdef NDEBUG
|
|
||||||
set_slot(detail::empty_slot::value);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
void weak_destroy() {
|
|
||||||
visit([&](auto&& value) {
|
|
||||||
using type = std::decay_t<decltype(value)>;
|
|
||||||
value.~type();
|
|
||||||
});
|
|
||||||
|
|
||||||
#ifndef NDEBUG
|
|
||||||
set_slot(detail::empty_slot::value);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
detail::slot_t get_slot() const noexcept {
|
|
||||||
// Check for invalid values especially for memory corruption,
|
|
||||||
// the empty element is included.
|
|
||||||
assert((this->slot_ < sizeof...(T)) ||
|
|
||||||
(this->slot_ == detail::empty_slot::value));
|
|
||||||
return this->slot_;
|
|
||||||
}
|
|
||||||
bool is_slot(detail::slot_t const slot) const noexcept {
|
|
||||||
return get_slot() == slot;
|
|
||||||
}
|
|
||||||
void set_slot(detail::slot_t const slot) {
|
|
||||||
this->slot_ = slot;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} // namespace container
|
|
||||||
} // namespace detail
|
|
||||||
} // namespace cti
|
|
||||||
|
|
||||||
#endif // CONTINUABLE_DETAIL_FLAT_VARIANT_HPP_INCLUDED
|
|
||||||
@ -40,12 +40,14 @@
|
|||||||
|
|
||||||
namespace cti {
|
namespace cti {
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
struct void_arg_t { };
|
||||||
|
|
||||||
template <typename... T>
|
template <typename... T>
|
||||||
struct result_trait;
|
struct result_trait;
|
||||||
template <>
|
template <>
|
||||||
struct result_trait<> {
|
struct result_trait<> {
|
||||||
using value_t = void;
|
using value_t = void;
|
||||||
struct surrogate_t {};
|
using surrogate_t = void_arg_t;
|
||||||
|
|
||||||
static constexpr surrogate_t wrap() noexcept {
|
static constexpr surrogate_t wrap() noexcept {
|
||||||
return {};
|
return {};
|
||||||
@ -93,8 +95,6 @@ struct result_trait<First, Second, Rest...> {
|
|||||||
return std::get<I>(std::forward<Result>(result).get_value());
|
return std::get<I>(std::forward<Result>(result).get_value());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct init_arg_t {};
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
} // namespace cti
|
} // namespace cti
|
||||||
|
|
||||||
|
|||||||
217
include/continuable/detail/utility/result-variant.hpp
Normal file
217
include/continuable/detail/utility/result-variant.hpp
Normal file
@ -0,0 +1,217 @@
|
|||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
/~` _ _ _|_. _ _ |_ | _
|
||||||
|
\_,(_)| | | || ||_|(_||_)|(/_
|
||||||
|
|
||||||
|
https://github.com/Naios/continuable
|
||||||
|
v4.0.0
|
||||||
|
|
||||||
|
Copyright(c) 2015 - 2019 Denis Blank <denis.blank at outlook dot com>
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files(the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions :
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
**/
|
||||||
|
|
||||||
|
#ifndef CONTINUABLE_DETAIL_RESULT_VARIANT_HPP_INCLUDED
|
||||||
|
#define CONTINUABLE_DETAIL_RESULT_VARIANT_HPP_INCLUDED
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <initializer_list>
|
||||||
|
#include <memory>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <utility>
|
||||||
|
#include <continuable/detail/utility/traits.hpp>
|
||||||
|
|
||||||
|
namespace cti {
|
||||||
|
namespace detail {
|
||||||
|
namespace container {
|
||||||
|
enum class result_slot_t : std::uint8_t {
|
||||||
|
slot_empty,
|
||||||
|
slot_value,
|
||||||
|
slot_exception,
|
||||||
|
};
|
||||||
|
} // namespace container
|
||||||
|
|
||||||
|
struct init_empty_arg_t {};
|
||||||
|
struct init_result_arg_t {};
|
||||||
|
struct init_exception_arg_t {};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class result_variant {
|
||||||
|
static constexpr bool is_nothrow_destructible = //
|
||||||
|
std::is_nothrow_destructible<T>::value &&
|
||||||
|
std::is_nothrow_destructible<exception_t>::value;
|
||||||
|
static constexpr bool is_nothrow_move_constructible = //
|
||||||
|
std::is_nothrow_move_constructible<T>::value &&
|
||||||
|
std::is_nothrow_move_constructible<exception_t>::value;
|
||||||
|
|
||||||
|
public:
|
||||||
|
result_variant() = default;
|
||||||
|
~result_variant() noexcept(is_nothrow_destructible) {
|
||||||
|
destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
explicit result_variant(init_empty_arg_t) noexcept
|
||||||
|
: slot_(container::result_slot_t::slot_empty) {}
|
||||||
|
explicit result_variant(init_result_arg_t, T value) noexcept(
|
||||||
|
std::is_nothrow_destructible<T>::value&&
|
||||||
|
std::is_nothrow_move_constructible<T>::value)
|
||||||
|
: slot_(container::result_slot_t::slot_value) {
|
||||||
|
new (value_ptr()) T(std::move(value));
|
||||||
|
}
|
||||||
|
explicit result_variant(init_exception_arg_t, exception_t exception) noexcept(
|
||||||
|
std::is_nothrow_destructible<exception_t>::value&&
|
||||||
|
std::is_nothrow_move_constructible<exception_t>::value)
|
||||||
|
: slot_(container::result_slot_t::slot_exception) {
|
||||||
|
new (exception_ptr()) exception_t(std::move(exception));
|
||||||
|
}
|
||||||
|
|
||||||
|
result_variant(result_variant const&) = delete;
|
||||||
|
result_variant& operator=(result_variant const&) = delete;
|
||||||
|
|
||||||
|
result_variant(result_variant&& other) noexcept(
|
||||||
|
is_nothrow_destructible&& is_nothrow_move_constructible)
|
||||||
|
: slot_(other.slot_) {
|
||||||
|
|
||||||
|
switch (other.slot_) {
|
||||||
|
case container::result_slot_t::slot_value: {
|
||||||
|
new (value_ptr()) T(std::move(*other.value_ptr()));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case container::result_slot_t::slot_exception: {
|
||||||
|
new (exception_ptr()) exception_t(std::move(*other.exception_ptr()));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
other.destroy();
|
||||||
|
other.slot_ = container::result_slot_t::slot_empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
result_variant& operator=(result_variant&& other) noexcept(
|
||||||
|
is_nothrow_destructible&& is_nothrow_move_constructible) {
|
||||||
|
|
||||||
|
destroy();
|
||||||
|
slot_ = other.slot_;
|
||||||
|
|
||||||
|
switch (other.slot_) {
|
||||||
|
case container::result_slot_t::slot_value: {
|
||||||
|
new (value_ptr()) T(std::move(*other.value_ptr()));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case container::result_slot_t::slot_exception: {
|
||||||
|
new (exception_ptr()) exception_t(std::move(*other.exception_ptr()));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
other.destroy();
|
||||||
|
other.slot_ = container::result_slot_t::slot_empty;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_empty() {
|
||||||
|
destroy();
|
||||||
|
slot_ = container::result_slot_t::slot_empty;
|
||||||
|
}
|
||||||
|
void set_value(T value) {
|
||||||
|
destroy();
|
||||||
|
new (value_ptr()) T(std::move(value));
|
||||||
|
slot_ = container::result_slot_t::slot_value;
|
||||||
|
}
|
||||||
|
void set_exception(exception_t exception) {
|
||||||
|
destroy();
|
||||||
|
new (exception_ptr()) exception_t(std::move(exception));
|
||||||
|
slot_ = container::result_slot_t::slot_exception;
|
||||||
|
}
|
||||||
|
|
||||||
|
container::result_slot_t slot() const noexcept {
|
||||||
|
return slot_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_empty() const noexcept {
|
||||||
|
return slot_ == container::result_slot_t::slot_empty;
|
||||||
|
}
|
||||||
|
bool is_value() const noexcept {
|
||||||
|
return slot_ == container::result_slot_t::slot_value;
|
||||||
|
}
|
||||||
|
bool is_exception() const noexcept {
|
||||||
|
return slot_ == container::result_slot_t::slot_exception;
|
||||||
|
}
|
||||||
|
|
||||||
|
T& get_value() noexcept {
|
||||||
|
assert(is_value());
|
||||||
|
return *reinterpret_cast<T*>(&storage_);
|
||||||
|
}
|
||||||
|
T const& get_value() const noexcept {
|
||||||
|
assert(is_value());
|
||||||
|
return *reinterpret_cast<T const*>(&storage_);
|
||||||
|
}
|
||||||
|
|
||||||
|
exception_t& get_exception() noexcept {
|
||||||
|
assert(is_exception());
|
||||||
|
return *reinterpret_cast<exception_t*>(&storage_);
|
||||||
|
}
|
||||||
|
exception_t const& get_exception() const noexcept {
|
||||||
|
assert(is_exception());
|
||||||
|
return *reinterpret_cast<exception_t const*>(&storage_);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
constexpr T* value_ptr() noexcept {
|
||||||
|
return reinterpret_cast<T*>(&storage_);
|
||||||
|
}
|
||||||
|
constexpr exception_t* exception_ptr() noexcept {
|
||||||
|
return reinterpret_cast<exception_t*>(&storage_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroy() noexcept(is_nothrow_destructible) {
|
||||||
|
switch (slot_) {
|
||||||
|
case container::result_slot_t::slot_value: {
|
||||||
|
value_ptr()->~T();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case container::result_slot_t::slot_exception: {
|
||||||
|
exception_ptr()->~exception_t();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
container::result_slot_t slot_{container::result_slot_t::slot_empty};
|
||||||
|
std::aligned_storage_t<
|
||||||
|
(sizeof(T) > sizeof(exception_t) ? sizeof(T) : sizeof(exception_t)),
|
||||||
|
(alignof(T) > alignof(exception_t) ? alignof(T) : alignof(exception_t))>
|
||||||
|
storage_;
|
||||||
|
};
|
||||||
|
} // namespace detail
|
||||||
|
} // namespace cti
|
||||||
|
|
||||||
|
#endif // CONTINUABLE_DETAIL_RESULT_VARIANT_HPP_INCLUDED
|
||||||
@ -18,7 +18,6 @@ add_executable(test-continuable-single
|
|||||||
${CMAKE_CURRENT_LIST_DIR}/single/test-continuable-promise.cpp
|
${CMAKE_CURRENT_LIST_DIR}/single/test-continuable-promise.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/single/test-continuable-connection-noinst
|
${CMAKE_CURRENT_LIST_DIR}/single/test-continuable-connection-noinst
|
||||||
${CMAKE_CURRENT_LIST_DIR}/single/test-continuable-forward-decl.cpp
|
${CMAKE_CURRENT_LIST_DIR}/single/test-continuable-forward-decl.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/single/test-continuable-flat-variant.cpp
|
|
||||||
${CMAKE_CURRENT_LIST_DIR}/single/test-continuable-result.cpp
|
${CMAKE_CURRENT_LIST_DIR}/single/test-continuable-result.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/single/test-continuable-ready.cpp
|
${CMAKE_CURRENT_LIST_DIR}/single/test-continuable-ready.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/single/test-continuable-promisify.cpp
|
${CMAKE_CURRENT_LIST_DIR}/single/test-continuable-promisify.cpp
|
||||||
|
|||||||
@ -1,161 +0,0 @@
|
|||||||
|
|
||||||
/*
|
|
||||||
Copyright(c) 2015 - 2019 Denis Blank <denis.blank at outlook dot com>
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files(the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions :
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in
|
|
||||||
all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
**/
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
#include <utility>
|
|
||||||
#include <continuable/detail/utility/flat-variant.hpp>
|
|
||||||
#include <test-continuable.hpp>
|
|
||||||
|
|
||||||
using cti::detail::container::flat_variant;
|
|
||||||
|
|
||||||
static int const CANARY = 373671;
|
|
||||||
|
|
||||||
using int_variant = flat_variant<int, tag1, tag2>;
|
|
||||||
|
|
||||||
TEST(flat_variant_single_test, is_move_constructible) {
|
|
||||||
{
|
|
||||||
int_variant e_old(CANARY);
|
|
||||||
int_variant e(std::move(e_old));
|
|
||||||
|
|
||||||
EXPECT_TRUE(bool(e));
|
|
||||||
EXPECT_TRUE(e.is<int>());
|
|
||||||
EXPECT_EQ(e.cast<int>(), CANARY);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
int_variant e(int_variant(tag1{}));
|
|
||||||
|
|
||||||
EXPECT_TRUE(bool(e));
|
|
||||||
EXPECT_TRUE(e.is<tag1>());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(flat_variant_single_test, is_value_move_assignable) {
|
|
||||||
int_variant old(CANARY);
|
|
||||||
int_variant e;
|
|
||||||
e = std::move(old);
|
|
||||||
|
|
||||||
EXPECT_TRUE(bool(e));
|
|
||||||
EXPECT_TRUE(e.is<int>());
|
|
||||||
EXPECT_EQ(e.cast<int>(), CANARY);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(flat_variant_single_test, is_copy_constructible) {
|
|
||||||
{
|
|
||||||
int_variant const e_old(CANARY);
|
|
||||||
int_variant e(e_old);
|
|
||||||
|
|
||||||
EXPECT_TRUE(bool(e));
|
|
||||||
EXPECT_TRUE(e.is<int>());
|
|
||||||
EXPECT_EQ(e.cast<int>(), CANARY);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
int_variant const e_old(tag1{});
|
|
||||||
int_variant e(e_old);
|
|
||||||
|
|
||||||
EXPECT_TRUE(bool(e));
|
|
||||||
EXPECT_TRUE(e.is<tag1>());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(flat_variant_single_test, is_copy_assignable) {
|
|
||||||
{
|
|
||||||
int_variant const e_old(CANARY);
|
|
||||||
int_variant e;
|
|
||||||
e = e_old;
|
|
||||||
|
|
||||||
EXPECT_TRUE(bool(e));
|
|
||||||
EXPECT_TRUE(e.is<int>());
|
|
||||||
EXPECT_EQ(e.cast<int>(), CANARY);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
int_variant const e_old(tag1{});
|
|
||||||
int_variant e;
|
|
||||||
e = e_old;
|
|
||||||
|
|
||||||
EXPECT_TRUE(bool(e));
|
|
||||||
EXPECT_TRUE(e.is<tag1>());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// This regression test shows a memory leak which happens when using the
|
|
||||||
// expected class move constructed from another expected object.
|
|
||||||
TEST(flat_variant_single_test, test_leak_regression) {
|
|
||||||
// expected_all_tests<cti::detail::util::expected<std::__1::unique_ptr<int,
|
|
||||||
// std::__1::default_delete<int> > > >::supply<int const&>(int const&)
|
|
||||||
// const
|
|
||||||
// continuable/build/../test/unit-test/test-continuable-expected.cpp:52
|
|
||||||
// 3: #3 0x11cf07a in
|
|
||||||
// expected_all_tests_is_value_assignable_Test<cti::detail::util::expected<std::__1::unique_ptr<int,
|
|
||||||
// std::__1::default_delete<int> > > >::TestBody()
|
|
||||||
// continuable/build/../test/unit-test/test-continuable-expected.cpp:133:15
|
|
||||||
// 3: #4 0x1339e4e in void
|
|
||||||
// testing::internal::HandleSehExceptionsInMethodIfSupported<testing::Test,
|
|
||||||
// void>(testing::Test*, void (testing::Test::*)(), char const*)
|
|
||||||
// continuable/build/../dep/googletest/googletest/googletest/src/gtest.cc:2395:10
|
|
||||||
using type = std::shared_ptr<int>;
|
|
||||||
|
|
||||||
auto const validate = [](auto&& variant, long use) {
|
|
||||||
ASSERT_TRUE(variant.template is<type>());
|
|
||||||
ASSERT_EQ((*variant.template cast<type>()), CANARY);
|
|
||||||
ASSERT_EQ(variant.template cast<type>().use_count(), use);
|
|
||||||
};
|
|
||||||
|
|
||||||
bool destroyed = false;
|
|
||||||
{
|
|
||||||
type ptr(new int(CANARY), [&](int* val) {
|
|
||||||
destroyed = true;
|
|
||||||
delete val;
|
|
||||||
});
|
|
||||||
|
|
||||||
auto e1(flat_variant<type>(std::move(ptr)));
|
|
||||||
validate(e1, 1);
|
|
||||||
|
|
||||||
auto e2 = std::move(e1);
|
|
||||||
validate(e2, 1);
|
|
||||||
|
|
||||||
flat_variant<type> e3;
|
|
||||||
e3 = std::move(e2);
|
|
||||||
validate(e3, 1);
|
|
||||||
|
|
||||||
{
|
|
||||||
flat_variant<type> ec(e3);
|
|
||||||
validate(ec, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
flat_variant<type> ec = e3;
|
|
||||||
validate(ec, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
flat_variant<type> ec;
|
|
||||||
ec = e3;
|
|
||||||
validate(ec, 2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ASSERT_TRUE(destroyed);
|
|
||||||
}
|
|
||||||
@ -144,50 +144,6 @@ TYPED_TEST(result_all_tests, is_error_move_assignable) {
|
|||||||
EXPECT_TRUE(e.is_exception());
|
EXPECT_TRUE(e.is_exception());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(result_copyable_tests, is_copy_constructible) {
|
|
||||||
{
|
|
||||||
copyable_type const e_old(CANARY);
|
|
||||||
copyable_type e(e_old);
|
|
||||||
|
|
||||||
EXPECT_TRUE(bool(e));
|
|
||||||
EXPECT_EQ(*e, CANARY);
|
|
||||||
EXPECT_TRUE(e.is_value());
|
|
||||||
EXPECT_FALSE(e.is_exception());
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
copyable_type const e_old(supply_test_exception());
|
|
||||||
copyable_type e(e_old);
|
|
||||||
|
|
||||||
EXPECT_FALSE(bool(e));
|
|
||||||
EXPECT_FALSE(e.is_value());
|
|
||||||
EXPECT_TRUE(e.is_exception());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(result_copyable_tests, is_copy_assignable) {
|
|
||||||
{
|
|
||||||
copyable_type const e_old(CANARY);
|
|
||||||
copyable_type e;
|
|
||||||
e = e_old;
|
|
||||||
|
|
||||||
EXPECT_TRUE(bool(e));
|
|
||||||
EXPECT_EQ(*e, CANARY);
|
|
||||||
EXPECT_TRUE(e.is_value());
|
|
||||||
EXPECT_FALSE(e.is_exception());
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
copyable_type const e_old(supply_test_exception());
|
|
||||||
copyable_type e;
|
|
||||||
e = e_old;
|
|
||||||
|
|
||||||
EXPECT_FALSE(bool(e));
|
|
||||||
EXPECT_FALSE(e.is_value());
|
|
||||||
EXPECT_TRUE(e.is_exception());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TYPED_TEST(result_all_tests, is_constructible_from_error_helper) {
|
TYPED_TEST(result_all_tests, is_constructible_from_error_helper) {
|
||||||
cti::exceptional_result e1(supply_test_exception());
|
cti::exceptional_result e1(supply_test_exception());
|
||||||
{
|
{
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user