Commit 3bd185d4 authored by Dominik Charousset's avatar Dominik Charousset

Drop custom variant implementation

The `caf::variant` type came with a `sum_type` API that unfortunately
had some greedy template that did not behave nicely when switching to
`std::variant`. So instead of deprecating them, we actually remove them
right away since implementing workarounds for dead code is not worth the
time investment.
parent 89cee7a7
......@@ -70,7 +70,7 @@ namespace client {
// a simple calculator task: operation + operands
struct task {
caf::variant<add_atom, sub_atom> op;
std::variant<add_atom, sub_atom> op;
int lhs;
int rhs;
};
......@@ -170,7 +170,7 @@ behavior running(stateful_actor<state>* self, const actor& calculator) {
};
for (auto& x : self->state.tasks) {
auto f = [&](auto op) { send_task(op, x.lhs, x.rhs); };
caf::visit(f, x.op);
std::visit(f, x.op);
}
self->state.tasks.clear();
return {
......
......@@ -343,7 +343,6 @@ caf_add_component(
stateful_actor
string_algorithms
string_view
sum_type
telemetry.collector.prometheus
telemetry.counter
telemetry.gauge
......@@ -360,8 +359,7 @@ caf_add_component(
typed_spawn
unit
uri
uuid
variant)
uuid)
if(CAF_ENABLE_TESTING AND CAF_ENABLE_EXCEPTIONS)
caf_add_test_suites(caf-core-test custom_exception_handler)
......
......@@ -16,6 +16,7 @@
#include <string_view>
#include <tuple>
#include <type_traits>
#include <variant>
#include <vector>
#include "caf/config_value_reader.hpp"
......@@ -32,13 +33,10 @@
#include "caf/inspector_access_type.hpp"
#include "caf/raise_error.hpp"
#include "caf/string_algorithms.hpp"
#include "caf/sum_type.hpp"
#include "caf/sum_type_access.hpp"
#include "caf/sum_type_token.hpp"
#include "caf/timespan.hpp"
#include "caf/timestamp.hpp"
#include "caf/uri.hpp"
#include "caf/variant.hpp"
#include "caf/variant_wrapper.hpp"
namespace caf::detail {
......@@ -90,7 +88,7 @@ public:
using types = detail::type_list<none_t, integer, boolean, real, timespan, uri,
string, list, dictionary>;
using variant_type = detail::tl_apply_t<types, variant>;
using variant_type = detail::tl_apply_t<types, std::variant>;
// -- constructors, destructors, and assignment operators --------------------
......@@ -158,24 +156,19 @@ public:
/// Returns a human-readable type name of the current value.
const char* type_name() const noexcept;
/// Returns the underlying variant.
variant_type& get_data() {
/// @private
variant_type& get_data() & {
return data_;
}
/// Returns the underlying variant.
const variant_type& get_data() const {
/// @private
const variant_type& get_data() const& {
return data_;
}
/// Returns a pointer to the underlying variant.
variant_type* get_data_ptr() {
return &data_;
}
/// Returns a pointer to the underlying variant.
const variant_type* get_data_ptr() const {
return &data_;
/// @private
variant_type&& get_data() && {
return std::move(data_);
}
/// Checks whether this config value is not null.
......@@ -321,6 +314,11 @@ private:
/// @relates config_value
CAF_CORE_EXPORT std::string to_string(const config_value& x);
// -- std::variant-like access -------------------------------------------------
template <>
struct is_variant_wrapper<config_value> : std::true_type {};
// -- conversion via get_as ----------------------------------------------------
template <class T>
......@@ -559,33 +557,6 @@ auto get_or(const config_value& x, Fallback&& fallback) {
}
}
// -- SumType-like access ------------------------------------------------------
template <class T, class = std::enable_if_t<detail::is_config_value_type_v<T>>>
auto get_if(const config_value* x) {
return get_if<T>(x->get_data_ptr());
}
template <class T, class = std::enable_if_t<detail::is_config_value_type_v<T>>>
auto get_if(config_value* x) {
return get_if<T>(x->get_data_ptr());
}
template <class T, class = std::enable_if_t<detail::is_config_value_type_v<T>>>
decltype(auto) get(const config_value& x) {
return get<T>(x.get_data());
}
template <class T, class = std::enable_if_t<detail::is_config_value_type_v<T>>>
decltype(auto) get(config_value& x) {
return get<T>(x.get_data());
}
template <class T, class = std::enable_if_t<detail::is_config_value_type_v<T>>>
auto holds_alternative(const config_value& x) {
return holds_alternative<T>(x.get_data());
}
// -- comparison operator overloads --------------------------------------------
/// @relates config_value
......@@ -644,7 +615,7 @@ struct variant_inspector_traits<config_value> {
template <class F, class Value>
static auto visit(F&& f, Value&& x) {
return caf::visit(std::forward<F>(f), x.get_data());
return std::visit(std::forward<F>(f), x.get_data());
}
template <class U>
......
......@@ -11,6 +11,7 @@
#include <memory>
#include <stack>
#include <variant>
#include <vector>
namespace caf {
......@@ -47,7 +48,7 @@ public:
const std::pair<const std::string, config_value>& current();
};
using value_type = variant<const settings*, const config_value*, key_ptr,
using value_type = std::variant<const settings*, const config_value*, key_ptr,
absent_field, sequence, associative_array>;
using stack_type = std::stack<value_type, std::vector<value_type>>;
......
......@@ -28,7 +28,7 @@ public:
struct absent_field {};
using value_type = variant<config_value*, settings*, absent_field,
using value_type = std::variant<config_value*, settings*, absent_field,
present_field, std::vector<config_value>*>;
using stack_type = std::stack<value_type, std::vector<value_type>>;
......
// This file is part of CAF, the C++ Actor Framework. See the file LICENSE in
// the main distribution directory for license terms and copyright or visit
// https://github.com/actor-framework/actor-framework/blob/master/LICENSE.
#pragma once
#include <cstddef>
#include <type_traits>
#include <utility>
#include "caf/detail/type_list.hpp"
#include "caf/sum_type_token.hpp"
namespace caf {
/// Allows specializing the `sum_type_access` trait for any type that simply
/// wraps a `variant` and exposes it with a `get_data()` member function.
template <class T>
struct default_sum_type_access {
using types = typename T::types;
using type0 = typename detail::tl_head<types>::type;
static constexpr bool specialized = true;
template <class U, int Pos>
static bool is(const T& x, sum_type_token<U, Pos> token) {
return x.get_data().is(pos(token));
}
template <class U, int Pos>
static U& get(T& x, sum_type_token<U, Pos> token) {
return x.get_data().get(pos(token));
}
template <class U, int Pos>
static const U& get(const T& x, sum_type_token<U, Pos> token) {
return x.get_data().get(pos(token));
}
template <class U, int Pos>
static U* get_if(T* x, sum_type_token<U, Pos> token) {
return is(*x, token) ? &get(*x, token) : nullptr;
}
template <class U, int Pos>
static const U* get_if(const T* x, sum_type_token<U, Pos> token) {
return is(*x, token) ? &get(*x, token) : nullptr;
}
template <class Result, class Visitor, class... Ts>
static Result apply(T& x, Visitor&& visitor, Ts&&... xs) {
return x.get_data().template apply<Result>(std::forward<Visitor>(visitor),
std::forward<Ts>(xs)...);
}
template <class Result, class Visitor, class... Ts>
static Result apply(const T& x, Visitor&& visitor, Ts&&... xs) {
return x.get_data().template apply<Result>(std::forward<Visitor>(visitor),
std::forward<Ts>(xs)...);
}
};
} // namespace caf
......@@ -27,7 +27,6 @@
#include "caf/timespan.hpp"
#include "caf/typed_message_view.hpp"
#include "caf/typed_response_promise.hpp"
#include "caf/variant.hpp"
namespace caf {
......
......@@ -59,7 +59,7 @@ private:
// -- member variables -------------------------------------------------------
const config_option_set* options_ = nullptr;
variant<none_t, config_consumer*, config_list_consumer*,
std::variant<none_t, config_consumer*, config_list_consumer*,
config_value_consumer*>
parent_;
};
......@@ -119,7 +119,7 @@ private:
// -- member variables -------------------------------------------------------
const config_option_set* options_ = nullptr;
variant<none_t, config_consumer*, config_list_consumer*> parent_;
std::variant<none_t, config_consumer*, config_list_consumer*> parent_;
settings* cfg_ = nullptr;
std::string current_key_;
std::string category_;
......
......@@ -60,7 +60,7 @@ public:
/// Dispatches on the runtime-type of `x`.
template <class... Ts>
void operator()(result<Ts...>& res) {
caf::visit([this](auto& x) { (*this)(x); }, res);
std::visit([this](auto& x) { (*this)(x); }, res.get_data());
}
// -- special-purpose handlers that don't produce results --------------------
......
......@@ -17,7 +17,6 @@
#include "caf/none.hpp"
#include "caf/pec.hpp"
#include "caf/timestamp.hpp"
#include "caf/variant.hpp"
CAF_PUSH_UNUSED_LABEL_WARNING
......@@ -34,15 +33,15 @@ void read_number_or_timespan(State& ps, Consumer& consumer,
struct interim_consumer {
size_t invocations = 0;
Consumer* outer = nullptr;
variant<none_t, int64_t, double> interim;
std::variant<none_t, int64_t, double> interim;
void value(int64_t x) {
switch (++invocations) {
case 1:
interim = x;
break;
case 2:
CAF_ASSERT(holds_alternative<int64_t>(interim));
outer->value(get<int64_t>(interim));
CAF_ASSERT(std::holds_alternative<int64_t>(interim));
outer->value(std::get<int64_t>(interim));
interim = none;
[[fallthrough]];
default:
......@@ -55,13 +54,13 @@ void read_number_or_timespan(State& ps, Consumer& consumer,
};
interim_consumer ic;
ic.outer = &consumer;
auto has_int = [&] { return holds_alternative<int64_t>(ic.interim); };
auto has_dbl = [&] { return holds_alternative<double>(ic.interim); };
auto get_int = [&] { return get<int64_t>(ic.interim); };
auto has_int = [&] { return std::holds_alternative<int64_t>(ic.interim); };
auto has_dbl = [&] { return std::holds_alternative<double>(ic.interim); };
auto get_int = [&] { return std::get<int64_t>(ic.interim); };
auto g = make_scope_guard([&] {
if (ps.code <= pec::trailing_character) {
if (has_dbl())
consumer.value(get<double>(ic.interim));
consumer.value(std::get<double>(ic.interim));
else if (has_int())
consumer.value(get_int());
}
......
......@@ -17,7 +17,6 @@
#include "caf/save_inspector_base.hpp"
#include "caf/timespan.hpp"
#include "caf/timestamp.hpp"
#include "caf/variant.hpp"
namespace caf::detail {
......
......@@ -321,9 +321,8 @@ struct tl_index_of<type_list<Ts...>, T> {
static constexpr int value = tl_index_of_impl<0, T, Ts...>::value;
};
// Uncomment after having switched to C++14
// template <class List, class T>
// inline constexpr int tl_index_of_v = tl_index_of<List, T>::value;
template <class List, class T>
constexpr int tl_index_of_v = tl_index_of<List, T>::value;
// int index_of(list, predicate)
......
// This file is part of CAF, the C++ Actor Framework. See the file LICENSE in
// the main distribution directory for license terms and copyright or visit
// https://github.com/actor-framework/actor-framework/blob/master/LICENSE.
#pragma once
#include <stdexcept>
#include <type_traits>
#include "caf/none.hpp"
#include "caf/unit.hpp"
#define CAF_VARIANT_DATA_CONCAT(x, y) x##y
#define CAF_VARIANT_DATA_GETTER(pos) \
CAF_VARIANT_DATA_CONCAT(T, pos) \
&get(std::integral_constant<int, pos>) { \
return CAF_VARIANT_DATA_CONCAT(v, pos); \
} \
const CAF_VARIANT_DATA_CONCAT(T, pos) \
& get(std::integral_constant<int, pos>) const { \
return CAF_VARIANT_DATA_CONCAT(v, pos); \
}
namespace caf::detail {
template <class T0 = unit_t, class T1 = unit_t, class T2 = unit_t,
class T3 = unit_t, class T4 = unit_t, class T5 = unit_t,
class T6 = unit_t, class T7 = unit_t, class T8 = unit_t,
class T9 = unit_t, class T10 = unit_t, class T11 = unit_t,
class T12 = unit_t, class T13 = unit_t, class T14 = unit_t,
class T15 = unit_t, class T16 = unit_t, class T17 = unit_t,
class T18 = unit_t, class T19 = unit_t, class T20 = unit_t,
class T21 = unit_t, class T22 = unit_t, class T23 = unit_t,
class T24 = unit_t, class T25 = unit_t, class T26 = unit_t,
class T27 = unit_t, class T28 = unit_t, class T29 = unit_t>
struct variant_data {
union {
T0 v0;
T1 v1;
T2 v2;
T3 v3;
T4 v4;
T5 v5;
T6 v6;
T7 v7;
T8 v8;
T9 v9;
T10 v10;
T11 v11;
T12 v12;
T13 v13;
T14 v14;
T15 v15;
T16 v16;
T17 v17;
T18 v18;
T19 v19;
T20 v20;
T21 v21;
T22 v22;
T23 v23;
T24 v24;
T25 v25;
T26 v26;
T27 v27;
T28 v28;
T29 v29;
};
variant_data() {
// nop
}
~variant_data() {
// nop
}
CAF_VARIANT_DATA_GETTER(0)
CAF_VARIANT_DATA_GETTER(1)
CAF_VARIANT_DATA_GETTER(2)
CAF_VARIANT_DATA_GETTER(3)
CAF_VARIANT_DATA_GETTER(4)
CAF_VARIANT_DATA_GETTER(5)
CAF_VARIANT_DATA_GETTER(6)
CAF_VARIANT_DATA_GETTER(7)
CAF_VARIANT_DATA_GETTER(8)
CAF_VARIANT_DATA_GETTER(9)
CAF_VARIANT_DATA_GETTER(10)
CAF_VARIANT_DATA_GETTER(11)
CAF_VARIANT_DATA_GETTER(12)
CAF_VARIANT_DATA_GETTER(13)
CAF_VARIANT_DATA_GETTER(14)
CAF_VARIANT_DATA_GETTER(15)
CAF_VARIANT_DATA_GETTER(16)
CAF_VARIANT_DATA_GETTER(17)
CAF_VARIANT_DATA_GETTER(18)
CAF_VARIANT_DATA_GETTER(19)
CAF_VARIANT_DATA_GETTER(20)
CAF_VARIANT_DATA_GETTER(21)
CAF_VARIANT_DATA_GETTER(22)
CAF_VARIANT_DATA_GETTER(23)
CAF_VARIANT_DATA_GETTER(24)
CAF_VARIANT_DATA_GETTER(25)
CAF_VARIANT_DATA_GETTER(26)
CAF_VARIANT_DATA_GETTER(27)
CAF_VARIANT_DATA_GETTER(28)
CAF_VARIANT_DATA_GETTER(29)
};
struct variant_data_destructor {
using result_type = void;
template <class T>
void operator()(T& storage) const {
storage.~T();
}
};
} // namespace caf::detail
......@@ -8,6 +8,7 @@
#include <cstdint>
#include <memory>
#include <string_view>
#include <variant>
#include <vector>
#include "caf/detail/core_export.hpp"
......@@ -59,7 +60,6 @@ template <class...> class typed_actor_view;
template <class...> class typed_event_based_actor;
template <class...> class typed_message_view;
template <class...> class typed_response_promise;
template <class...> class variant;
// clang-format on
......@@ -120,6 +120,7 @@ class scheduled_actor;
class scoped_actor;
class serializer;
class skip_t;
class skippable_result;
class tracing_data;
class tracing_data_factory;
class type_id_list;
......@@ -178,7 +179,6 @@ using ip_address = ipv6_address;
using ip_endpoint = ipv6_endpoint;
using ip_subnet = ipv6_subnet;
using settings = dictionary<config_value>;
using skippable_result = variant<delegated<message>, message, error, skip_t>;
using type_id_t = uint16_t;
// -- functions ----------------------------------------------------------------
......
......@@ -11,17 +11,6 @@
#include <tuple>
#include <utility>
#ifdef __has_include
# if __has_include(<optional>)
# include <optional>
# define CAF_HAS_STD_OPTIONAL
# endif
# if __has_include(<variant>)
# include <variant>
# define CAF_HAS_STD_VARIANT
# endif
#endif
#include "caf/allowed_unsafe_message_type.hpp"
#include "caf/detail/as_mutable_ref.hpp"
#include "caf/detail/parse.hpp"
......@@ -36,8 +25,6 @@
#include "caf/optional.hpp"
#include "caf/sec.hpp"
#include "caf/span.hpp"
#include "caf/sum_type_access.hpp"
#include "caf/variant.hpp"
namespace caf::detail {
......@@ -306,11 +293,11 @@ struct optional_inspector_traits_base {
}
};
CAF_PUSH_DEPRECATED_WARNING
template <class T>
struct optional_inspector_traits;
CAF_PUSH_DEPRECATED_WARNING
template <class T>
struct optional_inspector_traits<optional<T>> : optional_inspector_traits_base {
using container_type = optional<T>;
......@@ -443,8 +430,6 @@ struct inspector_access<optional<T>> : optional_inspector_access<optional<T>> {
CAF_POP_WARNINGS
#ifdef CAF_HAS_STD_OPTIONAL
template <class T>
struct optional_inspector_traits<std::optional<T>>
: optional_inspector_traits_base {
......@@ -464,8 +449,6 @@ struct inspector_access<std::optional<T>>
// nop
};
#endif
// -- inspection support for error ---------------------------------------------
template <>
......@@ -492,51 +475,6 @@ struct inspector_access<std::byte> : inspector_access_base<std::byte> {
template <class T>
struct variant_inspector_traits;
template <class... Ts>
struct variant_inspector_traits<variant<Ts...>> {
static_assert(
(has_type_id_v<Ts> && ...),
"inspectors requires that each type in a variant has a type_id");
using value_type = variant<Ts...>;
static constexpr type_id_t allowed_types[] = {type_id_v<Ts>...};
static auto type_index(const value_type& x) {
return x.index();
}
template <class F, class Value>
static auto visit(F&& f, Value&& x) {
return caf::visit(std::forward<F>(f), std::forward<Value>(x));
}
template <class U>
static auto assign(value_type& x, U&& value) {
x = std::forward<U>(value);
}
template <class F>
static bool load(type_id_t, F&, detail::type_list<>) {
return false;
}
template <class F, class U, class... Us>
static bool
load(type_id_t type, F& continuation, detail::type_list<U, Us...>) {
if (type_id_v<U> == type) {
auto tmp = U{};
continuation(tmp);
return true;
}
return load(type, continuation, detail::type_list<Us...>{});
}
template <class F>
static bool load(type_id_t type, F continuation) {
return load(type, continuation, detail::type_list<Ts...>{});
}
};
template <class T>
struct variant_inspector_access {
using value_type = T;
......@@ -654,14 +592,6 @@ struct variant_inspector_access {
}
};
template <class... Ts>
struct inspector_access<variant<Ts...>>
: variant_inspector_access<variant<Ts...>> {
// nop
};
#ifdef CAF_HAS_STD_VARIANT
template <class... Ts>
struct variant_inspector_traits<std::variant<Ts...>> {
static_assert(
......@@ -714,8 +644,6 @@ struct inspector_access<std::variant<Ts...>>
// nop
};
#endif
// -- inspection support for std::chrono types ---------------------------------
template <class Rep, class Period>
......
......@@ -82,7 +82,7 @@ public:
template <class T, size_t... Is>
bool tuple(T& xs, std::index_sequence<Is...>) {
return dref().begin_tuple(sizeof...(Is))
&& (detail::load(dref(), get<Is>(xs)) && ...) //
&& (detail::load(dref(), std::get<Is>(xs)) && ...) //
&& dref().end_tuple();
}
......
......@@ -18,7 +18,6 @@
#include "caf/none.hpp"
#include "caf/ref_counted.hpp"
#include "caf/uri.hpp"
#include "caf/variant.hpp"
namespace caf {
......@@ -74,7 +73,7 @@ class CAF_CORE_EXPORT node_id_data : public ref_counted {
public:
// -- member types -----------------------------------------------------------
using variant_type = variant<uri, hashed_node_id>;
using variant_type = std::variant<uri, hashed_node_id>;
// -- constructors, destructors, and assignment operators --------------------
......@@ -203,7 +202,7 @@ private:
/// Returns whether `x` contains an URI.
/// @relates node_id
inline bool wraps_uri(const node_id& x) noexcept {
return x && holds_alternative<uri>(x->content);
return x && std::holds_alternative<uri>(x->content);
}
/// @relates node_id
......
......@@ -12,6 +12,8 @@
#include "caf/none.hpp"
#include "caf/unit.hpp"
CAF_PUSH_DEPRECATED_WARNING
namespace caf {
/// A C++17 compatible `optional` implementation.
......@@ -268,8 +270,6 @@ private:
bool m_value;
};
CAF_PUSH_DEPRECATED_WARNING
/// @relates optional
template <class T>
auto to_string(const optional<T>& x)
......@@ -478,6 +478,6 @@ bool operator>=(const T& lhs, const optional<T>& rhs) {
return !rhs || !(lhs < *rhs);
}
CAF_POP_WARNINGS
} // namespace caf
CAF_POP_WARNINGS
......@@ -4,9 +4,6 @@
#pragma once
#include <type_traits>
#include "caf/default_sum_type_access.hpp"
#include "caf/delegated.hpp"
#include "caf/detail/type_list.hpp"
#include "caf/detail/type_traits.hpp"
......@@ -16,8 +13,10 @@
#include "caf/message.hpp"
#include "caf/none.hpp"
#include "caf/skip.hpp"
#include "caf/sum_type.hpp"
#include "caf/variant.hpp"
#include "caf/variant_wrapper.hpp"
#include <type_traits>
#include <variant>
namespace caf::detail {
......@@ -71,15 +70,20 @@ public:
}
/// @private
auto& get_data() {
auto& get_data() & {
return content_;
}
/// @private
const auto& get_data() const {
const auto& get_data() const& {
return content_;
}
/// @private
auto&& get_data() && {
return std::move(content_);
}
protected:
explicit result_base(detail::result_base_message_init) : content_(message{}) {
// nop
......@@ -91,7 +95,7 @@ protected:
// nop
}
variant<delegated<Ts...>, message, error> content_;
std::variant<delegated<Ts...>, message, error> content_;
};
// -- result<Ts...> and its specializations ------------------------------------
......@@ -235,19 +239,73 @@ auto make_result(Ts&&... xs) {
// -- special type alias for a skippable result<message> -----------------------
/// Similar to `result<message>`, but also allows to *skip* a message.
using skippable_result = variant<delegated<message>, message, error, skip_t>;
class skippable_result {
public:
skippable_result() = default;
skippable_result(skippable_result&&) = default;
skippable_result(const skippable_result&) = default;
skippable_result& operator=(skippable_result&&) = default;
skippable_result& operator=(const skippable_result&) = default;
// -- sum type access to result<Ts...> -----------------------------------------
skippable_result(delegated<message> x) : content_(std::move(x)) {
// nop
}
template <class... Ts>
struct sum_type_access<result<Ts...>> : default_sum_type_access<result<Ts...>> {
skippable_result(message x) : content_(std::move(x)) {
// nop
}
skippable_result(error x) : content_(std::move(x)) {
// nop
}
skippable_result(skip_t x) : content_(std::move(x)) {
// nop
}
skippable_result(expected<message> x) {
if (x)
this->content_ = std::move(*x);
else
this->content_ = std::move(x.error());
}
skippable_result& operator=(expected<message> x) {
if (x)
this->content_ = std::move(*x);
else
this->content_ = std::move(x.error());
return *this;
}
/// @private
auto& get_data() {
return content_;
}
/// @private
const auto& get_data() const {
return content_;
}
private:
std::variant<delegated<message>, message, error, skip_t> content_;
};
// -- type traits --------------------------------------------------------------
template <class T>
struct is_result : std::false_type {};
template <class... Ts>
struct is_result<result<Ts...>> : std::true_type {};
// -- enable std::variant-style interface --------------------------------------
template <class... Ts>
struct is_variant_wrapper<result<Ts...>> : std::true_type {};
template <>
struct is_variant_wrapper<skippable_result> : std::true_type {};
} // namespace caf
......@@ -5,6 +5,7 @@
#pragma once
#include <string_view>
#include <tuple>
#include "caf/inspector_access.hpp"
#include "caf/save_inspector.hpp"
......@@ -72,6 +73,7 @@ public:
template <class T, size_t... Is>
bool tuple(const T& xs, std::index_sequence<Is...>) {
using std::get;
return dref().begin_tuple(sizeof...(Is)) //
&& (detail::save(dref(), get<Is>(xs)) && ...) //
&& dref().end_tuple();
......
......@@ -11,7 +11,6 @@
#include "caf/detail/move_if_not_ptr.hpp"
#include "caf/dictionary.hpp"
#include "caf/raise_error.hpp"
#include "caf/sum_type.hpp"
namespace caf {
......
// This file is part of CAF, the C++ Actor Framework. See the file LICENSE in
// the main distribution directory for license terms and copyright or visit
// https://github.com/actor-framework/actor-framework/blob/master/LICENSE.
#pragma once
#include "caf/detail/type_list.hpp"
#include "caf/detail/type_traits.hpp"
#include "caf/sum_type_access.hpp"
#include "caf/sum_type_token.hpp"
namespace caf {
/// @defgroup SumType Sum Types
/// Opt-in sum type concept for `variant`-style types.
/// @{
/// Concept for checking whether `T` supports the sum type API by specializing
/// `sum_type_access`.
template <class T>
constexpr bool SumType() {
return has_sum_type_access<typename std::decay<T>::type>::value;
}
/// Concept for checking whether all `Ts` support the sum type API by
/// specializing `sum_type_access`.
template <class... Ts>
constexpr bool SumTypes() {
using namespace detail;
using types = type_list<decay_t<Ts>...>;
return tl_forall<types, has_sum_type_access>::value;
}
template <class Trait, class T, bool = Trait::specialized>
struct sum_type_index {
static constexpr int value = -1;
};
template <class Trait, class T>
struct sum_type_index<Trait, T, true> {
static constexpr int value
= detail::tl_index_of<typename Trait::types, T>::value;
};
template <class Trait, class T>
constexpr sum_type_token<T, sum_type_index<Trait, T>::value>
make_sum_type_token() {
return {};
}
/// Returns a reference to the value of a sum type.
/// @pre `holds_alternative<T>(x)`
template <class T, class U, class Trait = sum_type_access<U>>
auto get(U& x) -> decltype(Trait::get(x, make_sum_type_token<Trait, T>())) {
return Trait::get(x, make_sum_type_token<Trait, T>());
}
/// Returns a reference to the value of a sum type.
/// @pre `holds_alternative<T>(x)`
template <class T, class U, class Trait = sum_type_access<U>>
auto get(const U& x)
-> decltype(Trait::get(x, make_sum_type_token<Trait, T>())) {
return Trait::get(x, make_sum_type_token<Trait, T>());
}
/// Returns a pointer to the value of a sum type if it is of type `T`,
/// `nullptr` otherwise.
template <class T, class U, class Trait = sum_type_access<U>>
auto get_if(U* x)
-> decltype(Trait::get_if(x, make_sum_type_token<Trait, T>())) {
return Trait::get_if(x, make_sum_type_token<Trait, T>());
}
/// Returns a pointer to the value of a sum type if it is of type `T`,
/// `nullptr` otherwise.
template <class T, class U, class Trait = sum_type_access<U>>
auto get_if(const U* x)
-> decltype(Trait::get_if(x, make_sum_type_token<Trait, T>())) {
return Trait::get_if(x, make_sum_type_token<Trait, T>());
}
/// Returns whether a sum type has a value of type `T`.
template <class T, class U>
bool holds_alternative(const U& x) {
using namespace detail;
using trait = sum_type_access<U>;
return trait::is(x, make_sum_type_token<trait, T>());
}
template <bool Valid, class F, class... Ts>
struct sum_type_visit_result_impl {
using type = decltype((std::declval<F&>())(
std::declval<typename sum_type_access<Ts>::type0&>()...));
};
template <class F, class... Ts>
struct sum_type_visit_result_impl<false, F, Ts...> {};
template <class F, class... Ts>
struct sum_type_visit_result
: sum_type_visit_result_impl<detail::conjunction<SumType<Ts>()...>::value, F,
Ts...> {};
template <class F, class... Ts>
using sum_type_visit_result_t =
typename sum_type_visit_result<detail::decay_t<F>,
detail::decay_t<Ts>...>::type;
template <class Result, size_t I, class Visitor>
struct visit_impl_continuation;
template <class Result, size_t I>
struct visit_impl {
template <class Visitor, class T, class... Ts>
static Result apply(Visitor&& f, T&& x, Ts&&... xs) {
visit_impl_continuation<Result, I - 1, Visitor> continuation{f};
using trait = sum_type_access<detail::decay_t<T>>;
return trait::template apply<Result>(x, continuation,
std::forward<Ts>(xs)...);
}
};
template <class Result>
struct visit_impl<Result, 0> {
template <class Visitor, class... Ts>
static Result apply(Visitor&& f, Ts&&... xs) {
return f(std::forward<Ts>(xs)...);
}
};
template <class Result, size_t I, class Visitor>
struct visit_impl_continuation {
Visitor& f;
template <class... Ts>
Result operator()(Ts&&... xs) {
return visit_impl<Result, I>::apply(f, std::forward<Ts>(xs)...);
}
};
/// Applies the values of any number of sum types to the visitor.
template <class Visitor, class T, class... Ts,
class Result = sum_type_visit_result_t<Visitor, T, Ts...>>
detail::enable_if_t<SumTypes<T, Ts...>(), Result>
visit(Visitor&& f, T&& x, Ts&&... xs) {
return visit_impl<Result, sizeof...(Ts) + 1>::apply(std::forward<Visitor>(f),
std::forward<T>(x),
std::forward<Ts>(xs)...);
}
/// @}
} // namespace caf
// This file is part of CAF, the C++ Actor Framework. See the file LICENSE in
// the main distribution directory for license terms and copyright or visit
// https://github.com/actor-framework/actor-framework/blob/master/LICENSE.
#pragma once
#include <type_traits>
namespace caf {
/// Specializing this trait allows users to enable `holds_alternative`, `get`,
/// `get_if`, and `visit` for any user-defined sum type.
/// @relates SumType
template <class T>
struct sum_type_access {
static constexpr bool specialized = false;
};
/// Evaluates to `true` if `T` specializes `sum_type_access`.
/// @relates SumType
template <class T>
struct has_sum_type_access {
static constexpr bool value = sum_type_access<T>::specialized;
};
} // namespace caf
// This file is part of CAF, the C++ Actor Framework. See the file LICENSE in
// the main distribution directory for license terms and copyright or visit
// https://github.com/actor-framework/actor-framework/blob/master/LICENSE.
#pragma once
#include <type_traits>
namespace caf {
template <class T, int Pos>
struct sum_type_token {};
template <class T, int Pos>
constexpr std::integral_constant<int, Pos> pos(sum_type_token<T, Pos>) {
return {};
}
} // namespace caf
......@@ -18,7 +18,6 @@
#include "caf/intrusive_ptr.hpp"
#include "caf/ip_address.hpp"
#include "caf/make_counted.hpp"
#include "caf/variant.hpp"
namespace caf {
......@@ -35,7 +34,7 @@ public:
/// Host subcomponent of the authority component. Either an IP address or
/// an hostname as string.
using host_type = variant<std::string, ip_address>;
using host_type = std::variant<std::string, ip_address>;
/// Bundles the authority component of the URI, i.e., userinfo, host, and
/// port.
......@@ -51,7 +50,7 @@ public:
/// Returns whether `host` is empty, i.e., the host is not an IP address
/// and the string is empty.
bool empty() const noexcept {
auto str = get_if<std::string>(&host);
auto str = std::get_if<std::string>(&host);
return str != nullptr && str->empty();
}
};
......
// This file is part of CAF, the C++ Actor Framework. See the file LICENSE in
// the main distribution directory for license terms and copyright or visit
// https://github.com/actor-framework/actor-framework/blob/master/LICENSE.
#pragma once
#include <functional>
#include <memory>
#include <type_traits>
#include "caf/config.hpp"
#include "caf/default_sum_type_access.hpp"
#include "caf/detail/type_list.hpp"
#include "caf/detail/type_traits.hpp"
#include "caf/detail/variant_data.hpp"
#include "caf/fwd.hpp"
#include "caf/raise_error.hpp"
#include "caf/sum_type.hpp"
#include "caf/sum_type_access.hpp"
#define CAF_VARIANT_CASE(n) \
case n: \
return f(std::forward<Us>(xs)..., \
x.get(std::integral_constant<int, (n <= max_type_id ? n : 0)>()))
#define CAF_VARIANT_ASSIGN_CASE(n) \
case n: { \
using tmp_t = typename detail::tl_at<detail::type_list<Ts...>, \
(n < sizeof...(Ts) ? n : 0)>::type; \
x.x = tmp_t{}; \
return f(get<tmp_t>(x.x)); \
}
namespace caf {
constexpr size_t variant_npos = static_cast<size_t>(-1);
template <class T>
struct is_variant : std::false_type {};
template <class... Ts>
struct is_variant<variant<Ts...>> : std::true_type {};
template <class... Ts>
struct is_variant<variant<Ts...>&> : std::true_type {};
template <class... Ts>
struct is_variant<const variant<Ts...>&> : std::true_type {};
template <class... Ts>
struct is_variant<const variant<Ts...>&&> : std::true_type {};
template <class... Ts>
using is_variant_t = typename is_variant<Ts...>::type;
template <class T>
struct variant_assign_helper {
using result_type = void;
T& lhs;
variant_assign_helper(T& lhs_ref) : lhs(lhs_ref) {
}
template <class U>
void operator()(const U& rhs) const {
lhs = rhs;
}
};
template <class T>
struct variant_move_helper {
using result_type = void;
T& lhs;
variant_move_helper(T& lhs_ref) : lhs(lhs_ref) {
}
template <class U>
void operator()(U& rhs) const {
lhs = std::move(rhs);
}
};
template <bool Valid, class F, class... Ts>
struct variant_visit_result_impl {
using type
= decltype((std::declval<F&>())(std::declval<typename Ts::type0&>()...));
};
template <class F, class... Ts>
struct variant_visit_result_impl<false, F, Ts...> {};
template <class F, class... Ts>
struct variant_visit_result
: variant_visit_result_impl<
detail::conjunction<is_variant<Ts>::value...>::value, F, Ts...> {};
template <class F, class... Ts>
using variant_visit_result_t =
typename variant_visit_result<detail::decay_t<F>,
detail::decay_t<Ts>...>::type;
/// A variant represents always a valid value of one of the types `Ts...`.
template <class... Ts>
class variant {
public:
// -- member types -----------------------------------------------------------
using types = detail::type_list<Ts...>;
using type0 = typename detail::tl_at<types, 0>::type;
// -- constants --------------------------------------------------------------
/// Stores the ID for the last type.
static constexpr int max_type_id = sizeof...(Ts) - 1;
/// Stores whether all types are nothrow constructible.
static constexpr bool nothrow_move_construct = detail::conjunction<
std::is_nothrow_move_constructible<Ts>::value...>::value;
/// Stores whether all types are nothrow assignable *and* constructible. We
/// need to check both, since assigning to a variant results in a
/// move-construct unless the before and after types are the same.
static constexpr bool nothrow_move_assign
= nothrow_move_construct
&& detail::conjunction<
std::is_nothrow_move_assignable<Ts>::value...>::value;
// -- sanity checks ----------------------------------------------------------
static_assert(sizeof...(Ts) <= 30, "Too many template arguments given.");
static_assert(sizeof...(Ts) > 0, "No template argument given.");
static_assert(!detail::tl_exists<types, std::is_reference>::value,
"Cannot create a variant of references");
// -- constructors, destructors, and assignment operators --------------------
variant() : type_(variant_npos) {
// Never empty ...
set(typename detail::tl_head<types>::type());
// ... unless an exception was thrown above.
type_ = 0;
}
template <class U>
variant(U&& arg) noexcept(
std::is_rvalue_reference<U&&>::value&& nothrow_move_assign)
: type_(variant_npos) {
set(std::forward<U>(arg));
}
variant(variant&& other) noexcept(nothrow_move_construct)
: type_(variant_npos) {
variant_move_helper<variant> helper{*this};
other.template apply<void>(helper);
}
variant(const variant& other) : type_(variant_npos) {
variant_assign_helper<variant> helper{*this};
other.template apply<void>(helper);
}
variant& operator=(const variant& other) {
variant_assign_helper<variant> helper{*this};
other.template apply<void>(helper);
return *this;
}
variant& operator=(variant&& other) noexcept(nothrow_move_assign) {
variant_move_helper<variant> helper{*this};
other.template apply<void>(helper);
return *this;
}
template <class U>
variant& operator=(U&& arg) noexcept(nothrow_move_assign) {
set(std::forward<U>(arg));
return *this;
}
~variant() {
destroy_data();
}
// -- properties -------------------------------------------------------------
constexpr size_t index() const {
return static_cast<size_t>(type_);
}
bool valueless_by_exception() const {
return index() == variant_npos;
}
/// @cond PRIVATE
variant& get_data() {
return *this;
}
const variant& get_data() const {
return *this;
}
template <int Pos>
bool is(std::integral_constant<int, Pos>) const {
return type_ == static_cast<size_t>(Pos);
}
template <class T>
bool is() const {
using namespace detail;
int_token<tl_index_where<type_list<Ts...>,
tbind<is_same_ish, T>::template type>::value>
token;
return is(token);
}
template <int Pos>
const typename detail::tl_at<types, Pos>::type&
get(std::integral_constant<int, Pos> token) const {
return data_.get(token);
}
template <int Pos>
typename detail::tl_at<types, Pos>::type&
get(std::integral_constant<int, Pos> token) {
return data_.get(token);
}
template <class Result, class Visitor, class... Variants>
Result apply(Visitor&& visitor, Variants&&... xs) const {
return apply_impl<Result>(*this, std::forward<Visitor>(visitor),
std::forward<Variants>(xs)...);
}
template <class Result, class Visitor, class... Variants>
Result apply(Visitor&& visitor, Variants&&... xs) {
return apply_impl<Result>(*this, std::forward<Visitor>(visitor),
std::forward<Variants>(xs)...);
}
template <class Result, class Self, class Visitor, class... Us>
static Result apply_impl(Self& x, Visitor&& f, Us&&... xs) {
switch (x.type_) {
default:
CAF_RAISE_ERROR("invalid type found");
CAF_VARIANT_CASE(0);
CAF_VARIANT_CASE(1);
CAF_VARIANT_CASE(2);
CAF_VARIANT_CASE(3);
CAF_VARIANT_CASE(4);
CAF_VARIANT_CASE(5);
CAF_VARIANT_CASE(6);
CAF_VARIANT_CASE(7);
CAF_VARIANT_CASE(8);
CAF_VARIANT_CASE(9);
CAF_VARIANT_CASE(10);
CAF_VARIANT_CASE(11);
CAF_VARIANT_CASE(12);
CAF_VARIANT_CASE(13);
CAF_VARIANT_CASE(14);
CAF_VARIANT_CASE(15);
CAF_VARIANT_CASE(16);
CAF_VARIANT_CASE(17);
CAF_VARIANT_CASE(18);
CAF_VARIANT_CASE(19);
CAF_VARIANT_CASE(20);
CAF_VARIANT_CASE(21);
CAF_VARIANT_CASE(22);
CAF_VARIANT_CASE(23);
CAF_VARIANT_CASE(24);
CAF_VARIANT_CASE(25);
CAF_VARIANT_CASE(26);
CAF_VARIANT_CASE(27);
CAF_VARIANT_CASE(28);
CAF_VARIANT_CASE(29);
}
}
/// @endcond
private:
void destroy_data() {
if (type_ == variant_npos)
return; // nothing to do
detail::variant_data_destructor f;
apply<void>(f);
}
template <class U>
void set(U&& arg) {
using namespace detail;
using type = typename std::decay<U>::type;
static constexpr int type_id = detail::tl_index_where<
types, detail::tbind<is_same_ish, type>::template type>::value;
static_assert(type_id >= 0, "invalid type for variant");
std::integral_constant<int, type_id> token;
if (type_ != type_id) {
destroy_data();
type_ = type_id;
auto& ref = data_.get(token);
new (std::addressof(ref)) type(std::forward<U>(arg));
} else {
data_.get(token) = std::forward<U>(arg);
}
}
template <class... Us>
void set(const variant<Us...>& other) {
using namespace detail;
static_assert(tl_subset_of<type_list<Us...>, types>::value,
"cannot set variant of type A to variant of type B "
"unless the element types of A are a strict subset of "
"the element types of B");
variant_assign_helper<variant> helper{*this};
other.template apply<void>(helper);
}
template <class... Us>
void set(variant<Us...>& other) {
set(const_cast<const variant<Us...>&>(other));
}
template <class... Us>
void set(variant<Us...>&& other) {
using namespace detail;
static_assert(tl_subset_of<type_list<Us...>, types>::value,
"cannot set variant of type A to variant of type B "
"unless the element types of A are a strict subset of "
"the element types of B");
variant_move_helper<variant> helper{*this};
other.template apply<void>(helper);
}
size_t type_;
detail::variant_data<typename lift_void<Ts>::type...> data_;
};
/// Enable `holds_alternative`, `get`, `get_if`, and `visit` for `variant`.
/// @relates variant
/// @relates SumType
template <class... Ts>
struct sum_type_access<variant<Ts...>>
: default_sum_type_access<variant<Ts...>> {
// nop
};
/// @relates variant
template <template <class> class Predicate>
struct variant_compare_helper {
template <class T>
bool operator()(const T& x, const T& y) const {
Predicate<T> f;
return f(x, y);
}
template <class T, class U>
bool operator()(const T&, const U&) const {
return false;
}
};
/// @relates variant
template <class... Ts>
bool operator==(const variant<Ts...>& x, const variant<Ts...>& y) {
variant_compare_helper<std::equal_to> f;
return x.index() == y.index() && visit(f, x, y);
}
/// @relates variant
template <class... Ts>
bool operator!=(const variant<Ts...>& x, const variant<Ts...>& y) {
return !(x == y);
}
/// @relates variant
template <class... Ts>
bool operator<(const variant<Ts...>& x, const variant<Ts...>& y) {
if (y.valueless_by_exception())
return false;
if (x.valueless_by_exception())
return true;
if (x.index() != y.index())
return x.index() < y.index();
variant_compare_helper<std::less> f;
return visit(f, x, y);
}
/// @relates variant
template <class... Ts>
bool operator>(const variant<Ts...>& x, const variant<Ts...>& y) {
if (x.valueless_by_exception())
return false;
if (y.valueless_by_exception())
return true;
if (x.index() != y.index())
return x.index() > y.index();
variant_compare_helper<std::greater> f;
return visit(f, x, y);
}
/// @relates variant
template <class... Ts>
bool operator<=(const variant<Ts...>& x, const variant<Ts...>& y) {
return !(x > y);
}
/// @relates variant
template <class... Ts>
bool operator>=(const variant<Ts...>& x, const variant<Ts...>& y) {
return !(x < y);
}
} // namespace caf
// This file is part of CAF, the C++ Actor Framework. See the file LICENSE in
// the main distribution directory for license terms and copyright or visit
// https://github.com/actor-framework/actor-framework/blob/master/LICENSE.
#pragma once
#include <type_traits>
#include <variant>
namespace caf {
/// Customization point. Any type that declares itself as a variant wrapper
/// enables `visit`, `holds_alternative`, `get` and `get_if`. Each type must
/// provide a member function `get_data()` to expose the internal
/// `std::variant`.
template <class>
struct is_variant_wrapper : std::false_type {};
/// @relates is_variant_wrapper
template <class T>
constexpr bool is_variant_wrapper_v = is_variant_wrapper<T>::value;
/// @relates is_variant_wrapper
template <class T>
using enable_variant_wrapper_t = std::enable_if_t<is_variant_wrapper_v<T>>;
/// @relates is_variant_wrapper
template <class F, class V, class = enable_variant_wrapper_t<std::decay_t<V>>>
decltype(auto) visit(F&& f, V&& x) {
return std::visit(std::forward<F>(f), std::forward<V>(x).get_data());
}
/// @relates is_variant_wrapper
template <class T, class V, class = enable_variant_wrapper_t<V>>
bool holds_alternative(const V& x) noexcept {
return std::holds_alternative<T>(x.get_data());
}
/// @relates is_variant_wrapper
template <class T, class V, class = enable_variant_wrapper_t<V>>
T& get(V& x) {
return std::get<T>(x.get_data());
}
/// @relates is_variant_wrapper
template <class T, class V, class = enable_variant_wrapper_t<V>>
const T& get(const V& x) {
return std::get<T>(x.get_data());
}
/// @relates is_variant_wrapper
template <class T, class V, class = enable_variant_wrapper_t<V>>
T* get_if(V* ptr) noexcept {
return std::get_if<T>(&ptr->get_data());
}
/// @relates is_variant_wrapper
template <class T, class V, class = enable_variant_wrapper_t<V>>
const T* get_if(const V* ptr) noexcept {
return std::get_if<T>(&ptr->get_data());
}
} // namespace caf
......@@ -17,20 +17,10 @@
} \
} while (false)
#define CHECK_VALID() \
do { \
CHECK_NOT_EMPTY(); \
if (holds_alternative<none_t>(st_.top())) { \
emplace_error(sec::runtime_error, \
"attempted to write to a non-existent optional field"); \
return false; \
} \
} while (false)
#define SCOPE(top_type) \
CHECK_VALID(); \
CHECK_NOT_EMPTY(); \
if (!holds_alternative<top_type>(st_.top())) { \
if constexpr (std::is_same<top_type, settings>::value) { \
if constexpr (std::is_same<top_type, settings*>::value) { \
emplace_error(sec::runtime_error, \
"attempted to add list items before calling " \
"begin_sequence or begin_tuple"); \
......
......@@ -199,7 +199,7 @@ bool json_reader::fetch_next_object_name(std::string_view& type_name) {
FN_DECL;
return consume<false>(fn, [this, &type_name](const detail::json::value& val) {
if (val.data.index() == detail::json::value::object_index) {
auto& obj = get<detail::json::object>(val.data);
auto& obj = std::get<detail::json::object>(val.data);
if (auto mem_ptr = find_member(&obj, "@type")) {
if (mem_ptr->val->data.index() == detail::json::value::string_index) {
type_name = std::get<std::string_view>(mem_ptr->val->data);
......@@ -227,7 +227,7 @@ bool json_reader::begin_object(type_id_t, std::string_view) {
FN_DECL;
return consume<false>(fn, [this](const detail::json::value& val) {
if (val.data.index() == detail::json::value::object_index) {
push(&get<detail::json::object>(val.data));
push(&std::get<detail::json::object>(val.data));
return true;
} else {
emplace_error(sec::runtime_error, class_name, fn, current_field_name(),
......@@ -379,7 +379,7 @@ bool json_reader::begin_sequence(size_t& size) {
FN_DECL;
return consume<false>(fn, [this, &size](const detail::json::value& val) {
if (val.data.index() == detail::json::value::array_index) {
auto& ls = get<detail::json::array>(val.data);
auto& ls = std::get<detail::json::array>(val.data);
size = ls.size();
push(sequence{ls.begin(), ls.end()});
return true;
......@@ -410,7 +410,7 @@ bool json_reader::begin_associative_array(size_t& size) {
FN_DECL;
return consume<false>(fn, [this, &size](const detail::json::value& val) {
if (val.data.index() == detail::json::value::object_index) {
auto* obj = std::addressof(get<detail::json::object>(val.data));
auto* obj = std::addressof(std::get<detail::json::object>(val.data));
pop();
size = obj->size();
push(members{obj->begin(), obj->end()});
......
......@@ -26,7 +26,6 @@
#include "caf/make_config_option.hpp"
#include "caf/none.hpp"
#include "caf/pec.hpp"
#include "caf/variant.hpp"
#include "caf/detail/bounds_checker.hpp"
#include "caf/detail/overload.hpp"
......
......@@ -360,7 +360,7 @@ bool inspect(Inspector& f, circle& x) {
struct widget {
std::string color;
caf::variant<rectangle, circle> shape;
std::variant<rectangle, circle> shape;
};
template <class Inspector>
......
......@@ -10,9 +10,9 @@
#include <string>
#include <string_view>
#include <variant>
#include "caf/parser_state.hpp"
#include "caf/variant.hpp"
using namespace caf;
......@@ -25,7 +25,7 @@ struct bool_parser_consumer {
}
};
using res_t = variant<pec, bool>;
using res_t = std::variant<pec, bool>;
struct bool_parser {
res_t operator()(std::string_view str) {
......
......@@ -10,9 +10,9 @@
#include <string>
#include <string_view>
#include <variant>
#include "caf/parser_state.hpp"
#include "caf/variant.hpp"
using namespace caf;
......
......@@ -10,20 +10,20 @@
#include <string>
#include <string_view>
#include <variant>
#include "caf/detail/parser/add_ascii.hpp"
#include "caf/detail/parser/sub_ascii.hpp"
#include "caf/expected.hpp"
#include "caf/parser_state.hpp"
#include "caf/pec.hpp"
#include "caf/variant.hpp"
using namespace caf;
namespace {
struct number_consumer {
variant<int64_t, double> x;
std::variant<int64_t, double> x;
void value(double y) {
x = y;
}
......@@ -43,7 +43,7 @@ struct range_consumer {
};
struct res_t {
variant<pec, double, int64_t> val;
std::variant<pec, double, int64_t> val;
template <class T>
res_t(T&& x) : val(std::forward<T>(x)) {
// nop
......@@ -51,7 +51,7 @@ struct res_t {
};
std::string to_string(const res_t& x) {
return caf::visit([](auto& y) { return deep_to_string(y); }, x.val);
return std::visit([](auto& y) { return deep_to_string(y); }, x.val);
}
bool operator==(const res_t& x, const res_t& y) {
......@@ -74,8 +74,9 @@ struct numbers_parser {
string_parser_state res{str.begin(), str.end()};
detail::parser::read_number(res, f);
if (res.code == pec::success)
return f.x;
return res.code;
return std::visit([](auto val) { return res_t{val}; }, f.x);
else
return res_t{res.code};
}
};
......@@ -85,7 +86,8 @@ struct range_parser {
string_parser_state res{str.begin(), str.end()};
detail::parser::read_number(res, f, std::true_type{}, std::true_type{});
if (res.code == pec::success)
return std::move(f.xs);
return expected<std::vector<int64_t>>{std::move(f.xs)};
else
return make_error(res);
}
};
......
......@@ -8,11 +8,11 @@
#include "core-test.hpp"
#include "caf/parser_state.hpp"
#include <string>
#include <string_view>
#include "caf/parser_state.hpp"
#include "caf/variant.hpp"
#include <variant>
using namespace caf;
using namespace std::chrono;
......@@ -20,7 +20,7 @@ using namespace std::chrono;
namespace {
struct number_or_timespan_parser_consumer {
variant<int64_t, double, timespan> x;
std::variant<int64_t, double, timespan> x;
template <class T>
void value(T y) {
x = y;
......@@ -28,9 +28,9 @@ struct number_or_timespan_parser_consumer {
};
struct res_t {
variant<pec, double, int64_t, timespan> val;
std::variant<pec, double, int64_t, timespan> val;
template <class T>
res_t(T&& x) : val(std::forward<T>(x)) {
explicit res_t(T&& x) : val(std::forward<T>(x)) {
// nop
}
};
......@@ -61,8 +61,9 @@ struct number_or_timespan_parser {
string_parser_state res{str.begin(), str.end()};
detail::parser::read_number_or_timespan(res, f);
if (res.code == pec::success)
return f.x;
return res.code;
return std::visit([](auto val) { return res_t{val}; }, f.x);
else
return res_t{res.code};
}
};
......@@ -72,18 +73,18 @@ struct fixture {
template <class T>
typename std::enable_if<std::is_integral<T>::value, res_t>::type res(T x) {
return {static_cast<int64_t>(x)};
return res_t{static_cast<int64_t>(x)};
}
template <class T>
typename std::enable_if<std::is_floating_point<T>::value, res_t>::type
res(T x) {
return {static_cast<double>(x)};
return res_t{static_cast<double>(x)};
}
template <class Rep, class Period>
res_t res(std::chrono::duration<Rep, Period> x) {
return std::chrono::duration_cast<timespan>(x);
return res_t{std::chrono::duration_cast<timespan>(x)};
}
} // namespace
......@@ -101,20 +102,20 @@ CAF_TEST(valid numbers and timespans) {
}
CAF_TEST(invalid timespans) {
CHECK_EQ(p("12.3s"), pec::fractional_timespan);
CHECK_EQ(p("12.3n"), pec::fractional_timespan);
CHECK_EQ(p("12.3ns"), pec::fractional_timespan);
CHECK_EQ(p("12.3m"), pec::fractional_timespan);
CHECK_EQ(p("12.3ms"), pec::fractional_timespan);
CHECK_EQ(p("12.3n"), pec::fractional_timespan);
CHECK_EQ(p("12.3ns"), pec::fractional_timespan);
CHECK_EQ(p("12.3mi"), pec::fractional_timespan);
CHECK_EQ(p("12.3min"), pec::fractional_timespan);
CHECK_EQ(p("123ss"), pec::trailing_character);
CHECK_EQ(p("123m"), pec::unexpected_eof);
CHECK_EQ(p("123mi"), pec::unexpected_eof);
CHECK_EQ(p("123u"), pec::unexpected_eof);
CHECK_EQ(p("123n"), pec::unexpected_eof);
CHECK_EQ(p("12.3s"), res_t{pec::fractional_timespan});
CHECK_EQ(p("12.3n"), res_t{pec::fractional_timespan});
CHECK_EQ(p("12.3ns"), res_t{pec::fractional_timespan});
CHECK_EQ(p("12.3m"), res_t{pec::fractional_timespan});
CHECK_EQ(p("12.3ms"), res_t{pec::fractional_timespan});
CHECK_EQ(p("12.3n"), res_t{pec::fractional_timespan});
CHECK_EQ(p("12.3ns"), res_t{pec::fractional_timespan});
CHECK_EQ(p("12.3mi"), res_t{pec::fractional_timespan});
CHECK_EQ(p("12.3min"), res_t{pec::fractional_timespan});
CHECK_EQ(p("123ss"), res_t{pec::trailing_character});
CHECK_EQ(p("123m"), res_t{pec::unexpected_eof});
CHECK_EQ(p("123mi"), res_t{pec::unexpected_eof});
CHECK_EQ(p("123u"), res_t{pec::unexpected_eof});
CHECK_EQ(p("123n"), res_t{pec::unexpected_eof});
}
END_FIXTURE_SCOPE()
......@@ -8,10 +8,9 @@
#include "core-test.hpp"
#include <string_view>
#include "caf/parser_state.hpp"
#include "caf/variant.hpp"
#include <string_view>
using namespace caf;
......
......@@ -13,7 +13,6 @@
#include "caf/expected.hpp"
#include "caf/parser_state.hpp"
#include "caf/variant.hpp"
using namespace caf;
using namespace std::literals;
......
......@@ -8,12 +8,11 @@
#include "core-test.hpp"
#include "caf/parser_state.hpp"
#include <chrono>
#include <string_view>
#include "caf/parser_state.hpp"
#include "caf/variant.hpp"
using namespace caf;
namespace {
......
......@@ -11,7 +11,6 @@
#include <string_view>
#include "caf/parser_state.hpp"
#include "caf/variant.hpp"
using namespace caf;
......
......@@ -3,9 +3,9 @@
#pragma once
#include "caf/type_id.hpp"
#include "caf/variant.hpp"
#include <optional>
#include <variant>
#include "nasty.hpp"
......@@ -151,7 +151,7 @@ bool inspect(Inspector& f, foobar& x) {
}
struct dummy_message {
caf::variant<std::string, double> content;
std::variant<std::string, double> content;
};
[[maybe_unused]] bool operator==(const dummy_message& x,
......@@ -165,7 +165,7 @@ bool inspect(Inspector& f, dummy_message& x) {
}
struct fallback_dummy_message {
caf::variant<std::string, double> content;
std::variant<std::string, double> content;
};
template <class Inspector>
......
......@@ -17,7 +17,6 @@
#include "caf/message.hpp"
#include "caf/span.hpp"
#include "caf/type_id.hpp"
#include "caf/variant.hpp"
#include "inspector-tests.hpp"
......
......@@ -22,7 +22,7 @@ using discarding_server_type = typed_actor<result<void>(int, int)>;
using adding_server_type = typed_actor<result<int>(int, int)>;
using result_type = variant<none_t, unit_t, int>;
using result_type = std::variant<none_t, unit_t, int>;
struct fixture : test_coordinator_fixture<> {
template <class F>
......
#pragma once
#include "caf/inspector_access.hpp"
#include <cstdint>
#include <optional>
#include <string>
#include <string_view>
#include <tuple>
#include "caf/inspector_access.hpp"
#include "caf/variant.hpp"
#include <variant>
enum class weekday : uint8_t {
monday,
......@@ -62,7 +62,7 @@ public:
using optional_type = std::optional<int32_t>;
using variant_type = caf::variant<std::string, int32_t>;
using variant_type = std::variant<std::string, int32_t>;
using tuple_type = std::tuple<std::string, int32_t>;
......@@ -200,8 +200,8 @@ public:
template <class Inspector>
bool inspect(Inspector& f, nasty& x) {
using caf::get;
using caf::get_if;
using std::get;
using std::get_if;
struct {
bool operator()(int32_t x) {
return x >= 0;
......
......@@ -4,12 +4,12 @@
#define CAF_SUITE result
#include "caf/result.hpp"
#include "core-test.hpp"
#include "caf/result.hpp"
#include "caf/sec.hpp"
using namespace std;
using namespace caf;
namespace {
......@@ -24,20 +24,20 @@ void test_unit_void() {
CAF_TEST(value) {
auto x = result<int>{42};
CAF_REQUIRE(holds_alternative<message>(x));
REQUIRE(holds_alternative<message>(x));
if (auto view = make_typed_message_view<int>(get<message>(x)))
CHECK_EQ(get<0>(view), 42);
else
CAF_FAIL("unexpected types in result message");
FAIL("unexpected types in result message");
}
CAF_TEST(expected) {
auto x = result<int>{expected<int>{42}};
CAF_REQUIRE(holds_alternative<message>(x));
REQUIRE(holds_alternative<message>(x));
if (auto view = make_typed_message_view<int>(get<message>(x)))
CHECK_EQ(get<0>(view), 42);
else
CAF_FAIL("unexpected types in result message");
FAIL("unexpected types in result message");
}
CAF_TEST(void_specialization) {
......
......@@ -50,7 +50,6 @@
#include "caf/ref_counted.hpp"
#include "caf/sec.hpp"
#include "caf/serializer.hpp"
#include "caf/variant.hpp"
struct opaque {
int secret;
......@@ -77,7 +76,8 @@ struct access_of {
= std::is_same<decltype(inspect_access_type<Inspector, T>()), What>::value;
};
static_assert(access_of<bs, variant<int, double>>::is<iat::specialization>);
static_assert(
access_of<bs, std::variant<int, double>>::is<iat::specialization>);
static_assert(access_of<bs, sec>::is<iat::inspect>);
......@@ -409,8 +409,8 @@ CAF_TEST(non_empty_vector) {
CAF_TEST(variant_with_tree_types) {
MESSAGE("deserializing into a non-empty vector overrides any content");
using test_variant = variant<int, double, std::string>;
test_variant x{42};
using test_variant = std::variant<int, double, std::string>;
auto x = test_variant{42};
CHECK_EQ(x, roundtrip(x, false));
x = 12.34;
CHECK_EQ(x, roundtrip(x, false));
......
// This file is part of CAF, the C++ Actor Framework. See the file LICENSE in
// the main distribution directory for license terms and copyright or visit
// https://github.com/actor-framework/actor-framework/blob/master/LICENSE.
#define CAF_SUITE sum_type
#include "caf/sum_type.hpp"
#include "core-test.hpp"
#include <map>
#include <new>
#include <string>
#include "caf/default_sum_type_access.hpp"
#include "caf/detail/overload.hpp"
#include "caf/raise_error.hpp"
#include "caf/sum_type_access.hpp"
namespace {
class union_type {
public:
friend struct caf::default_sum_type_access<union_type>;
using T0 = int;
using T1 = std::string;
using T2 = std::map<int, int>;
using types = caf::detail::type_list<T0, T1, T2>;
union_type() : index_(0), v0(0) {
// nop
}
~union_type() {
destroy();
}
union_type& operator=(T0 value) {
destroy();
index_ = 0;
v0 = value;
return *this;
}
union_type& operator=(T1 value) {
destroy();
index_ = 1;
new (&v1) T1(std::move(value));
return *this;
}
union_type& operator=(T2 value) {
destroy();
index_ = 2;
new (&v2) T2(std::move(value));
return *this;
}
private:
inline union_type& get_data() {
return *this;
}
inline const union_type& get_data() const {
return *this;
}
inline T0& get(std::integral_constant<int, 0>) {
CAF_REQUIRE_EQUAL(index_, 0);
return v0;
}
inline const T0& get(std::integral_constant<int, 0>) const {
CAF_REQUIRE_EQUAL(index_, 0);
return v0;
}
inline T1& get(std::integral_constant<int, 1>) {
CAF_REQUIRE_EQUAL(index_, 1);
return v1;
}
inline const T1& get(std::integral_constant<int, 1>) const {
CAF_REQUIRE_EQUAL(index_, 1);
return v1;
}
inline T2& get(std::integral_constant<int, 2>) {
CAF_REQUIRE_EQUAL(index_, 2);
return v2;
}
inline const T2& get(std::integral_constant<int, 2>) const {
CAF_REQUIRE_EQUAL(index_, 2);
return v2;
}
template <int Index>
inline bool is(std::integral_constant<int, Index>) const {
return index_ == Index;
}
template <class Result, class Visitor, class... Ts>
inline Result apply(Visitor&& f, Ts&&... xs) const {
switch (index_) {
case 0:
return f(std::forward<Ts>(xs)..., v0);
case 1:
return f(std::forward<Ts>(xs)..., v1);
case 2:
return f(std::forward<Ts>(xs)..., v2);
}
CAF_RAISE_ERROR("invalid index in union_type");
}
void destroy() {
if (index_ == 1)
v1.~T1();
else if (index_ == 2)
v2.~T2();
}
int index_;
union {
T0 v0;
T1 v1;
T2 v2;
};
};
} // namespace
namespace caf {
template <>
struct sum_type_access<union_type> : default_sum_type_access<union_type> {};
} // namespace caf
using namespace caf;
using std::string;
using map_type = std::map<int, int>;
namespace {
struct stringify_t {
string operator()(int x) const {
return std::to_string(x);
}
string operator()(std::string x) const {
return x;
}
string operator()(const map_type& x) const {
return deep_to_string(x);
}
template <class T0, class T1>
string operator()(const T0& x0, const T1& x1) const {
return (*this)(x0) + ", " + (*this)(x1);
}
template <class T0, class T1, class T2>
string operator()(const T0& x0, const T1& x1, const T2& x2) const {
return (*this)(x0, x1) + ", " + (*this)(x2);
}
};
constexpr stringify_t stringify = stringify_t{};
} // namespace
CAF_TEST(holds_alternative) {
union_type x;
CHECK_EQ(holds_alternative<int>(x), true);
CHECK_EQ(holds_alternative<string>(x), false);
CHECK_EQ(holds_alternative<map_type>(x), false);
x = string{"hello world"};
CHECK_EQ(holds_alternative<int>(x), false);
CHECK_EQ(holds_alternative<string>(x), true);
CHECK_EQ(holds_alternative<map_type>(x), false);
x = map_type{{1, 1}, {2, 2}};
CHECK_EQ(holds_alternative<int>(x), false);
CHECK_EQ(holds_alternative<string>(x), false);
CHECK_EQ(holds_alternative<map_type>(x), true);
}
CAF_TEST(get) {
union_type x;
CHECK_EQ(get<int>(x), 0);
x = 42;
CHECK_EQ(get<int>(x), 42);
x = string{"hello world"};
CHECK_EQ(get<string>(x), "hello world");
x = map_type{{1, 1}, {2, 2}};
CHECK_EQ(get<map_type>(x), map_type({{1, 1}, {2, 2}}));
}
CAF_TEST(get_if) {
union_type x;
CHECK_EQ(get_if<int>(&x), &get<int>(x));
CHECK_EQ(get_if<string>(&x), nullptr);
CHECK_EQ(get_if<map_type>(&x), nullptr);
x = string{"hello world"};
CHECK_EQ(get_if<int>(&x), nullptr);
CHECK_EQ(get_if<string>(&x), &get<string>(x));
CHECK_EQ(get_if<map_type>(&x), nullptr);
x = map_type{{1, 1}, {2, 2}};
CHECK_EQ(get_if<int>(&x), nullptr);
CHECK_EQ(get_if<string>(&x), nullptr);
CHECK_EQ(get_if<map_type>(&x), &get<map_type>(x));
}
CAF_TEST(unary visit) {
union_type x;
CHECK_EQ(visit(stringify, x), "0");
x = string{"hello world"};
CHECK_EQ(visit(stringify, x), "hello world");
x = map_type{{1, 1}, {2, 2}};
CHECK_EQ(visit(stringify, x), "{1 = 1, 2 = 2}");
}
CAF_TEST(binary visit) {
union_type x;
union_type y;
CHECK_EQ(visit(stringify, x, y), "0, 0");
x = 42;
y = string{"hello world"};
CHECK_EQ(visit(stringify, x, y), "42, hello world");
}
CAF_TEST(ternary visit) {
union_type x;
union_type y;
union_type z;
x = 42;
y = string{"foo"};
z = map_type{{1, 1}, {2, 2}};
CHECK_EQ(visit(stringify, x, y, z), "42, foo, {1 = 1, 2 = 2}");
}
// This file is part of CAF, the C++ Actor Framework. See the file LICENSE in
// the main distribution directory for license terms and copyright or visit
// https://github.com/actor-framework/actor-framework/blob/master/LICENSE.
#define CAF_SUITE variant
#include "caf/variant.hpp"
#include "core-test.hpp"
#include <string>
#include "caf/actor_system.hpp"
#include "caf/actor_system_config.hpp"
#include "caf/byte_buffer.hpp"
#include "caf/deep_to_string.hpp"
#include "caf/none.hpp"
using namespace std::string_literals;
using namespace caf;
// 20 integer wrappers for building a variant with 20 distinct types
#define i_n(n) \
class i##n { \
public: \
i##n(int y = 0) : x(y) { \
} \
i##n(i##n&& other) : x(other.x) { \
other.x = 0; \
} \
i##n& operator=(i##n&& other) { \
x = other.x; \
other.x = 0; \
return *this; \
} \
i##n(const i##n&) = default; \
i##n& operator=(const i##n&) = default; \
int x; \
}; \
bool operator==(int x, i##n y) { \
return x == y.x; \
} \
bool operator==(i##n x, int y) { \
return y == x; \
} \
bool operator==(i##n x, i##n y) { \
return x.x == y.x; \
} \
template <class Inspector> \
bool inspect(Inspector& f, i##n& x) { \
return f.object(x).fields(f.field("x", x.x)); \
}
#define macro_repeat20(macro) \
macro(01) macro(02) macro(03) macro(04) macro(05) macro(06) macro(07) \
macro(08) macro(09) macro(10) macro(11) macro(12) macro(13) macro(14) \
macro(15) macro(16) macro(17) macro(18) macro(19) macro(20)
macro_repeat20(i_n)
// a variant with 20 element types
using v20 = variant<i01, i02, i03, i04, i05, i06, i07, i08, i09, i10, i11,
i12, i13, i14, i15, i16, i17, i18, i19, i20>;
#define VARIANT_EQ(x, y) \
do { \
using type = std::decay_t<decltype(y)>; \
auto&& tmp = x; \
if (CHECK(holds_alternative<type>(tmp))) \
CHECK_EQ(get<type>(tmp), y); \
} while (false)
#define v20_test(n) \
x3 = i##n{0x##n}; \
VARIANT_EQ(v20{x3}, i##n{0x##n}); \
x4 = x3; \
VARIANT_EQ(x4, i##n{0x##n}); \
VARIANT_EQ(v20{std::move(x3)}, i##n{0x##n}); \
VARIANT_EQ(x3, i##n{0}); \
x3 = std::move(x4); \
VARIANT_EQ(x4, i##n{0}); \
VARIANT_EQ(x3, i##n{0x##n});
// copy construction, copy assign, move construction, move assign
// and finally serialization round-trip
CAF_TEST(copying_moving_roundtrips) {
actor_system_config cfg;
actor_system sys{cfg};
variant<int, none_t> x2;
VARIANT_EQ(x2, 0);
v20 x3;
VARIANT_EQ(x3, i01{0});
v20 x4;
macro_repeat20(v20_test);
}
namespace {
struct test_visitor {
template <class... Ts>
std::string operator()(const Ts&... xs) {
return deep_to_string_as_tuple(xs...);
}
};
} // namespace
CAF_TEST(constructors) {
variant<int, std::string> a{42};
variant<float, int, std::string> b{"bar"s};
variant<int, std::string, double> c{123};
variant<bool, uint8_t> d{uint8_t{252}};
VARIANT_EQ(a, 42);
VARIANT_EQ(b, "bar"s);
VARIANT_EQ(c, 123);
VARIANT_EQ(d, uint8_t{252});
}
CAF_TEST(n_ary_visit) {
variant<int, std::string> a{42};
variant<float, int, std::string> b{"bar"s};
variant<int, std::string, double> c{123};
test_visitor f;
CHECK_EQ(visit(f, a), R"__([42])__");
CHECK_EQ(visit(f, a, b), R"__([42, "bar"])__");
CHECK_EQ(visit(f, a, b, c), R"__([42, "bar", 123])__");
}
CAF_TEST(get_if) {
variant<int, std::string> b = "foo"s;
MESSAGE("test get_if directly");
CHECK_EQ(get_if<int>(&b), nullptr);
CHECK_NE(get_if<std::string>(&b), nullptr);
MESSAGE("test get_if via unit test framework");
VARIANT_EQ(b, "foo"s);
}
CAF_TEST(less_than) {
using variant_type = variant<char, int>;
auto a = variant_type{'x'};
auto b = variant_type{'y'};
CHECK(a < b);
CHECK(!(a > b));
CHECK(a <= b);
CHECK(!(a >= b));
b = 42;
CHECK(a < b);
CHECK(!(a > b));
CHECK(a <= b);
CHECK(!(a >= b));
a = 42;
CHECK(!(a < b));
CHECK(!(a > b));
CHECK(a <= b);
CHECK(a >= b);
b = 'x';
}
CAF_TEST(equality) {
variant<uint16_t, int> x = 42;
variant<uint16_t, int> y = uint16_t{42};
CHECK_NE(x, y);
}
......@@ -13,7 +13,6 @@
#include "caf/io/datagram_handle.hpp"
#include "caf/response_promise.hpp"
#include "caf/timestamp.hpp"
#include "caf/variant.hpp"
namespace caf::io::basp {
......
......@@ -19,7 +19,6 @@
#include "caf/io/basp/routing_table.hpp"
#include "caf/io/basp/worker.hpp"
#include "caf/io/middleman.hpp"
#include "caf/variant.hpp"
namespace caf::io::basp {
......
......@@ -21,7 +21,6 @@
#include "caf/logger.hpp"
#include "caf/raise_error.hpp"
#include "caf/term.hpp"
#include "caf/variant.hpp"
#include "caf/detail/arg_wrapper.hpp"
#include "caf/detail/type_traits.hpp"
......@@ -147,43 +146,11 @@ struct comparison_unbox_helper {
template <class Operator>
class comparison {
public:
// -- default case -----------------------------------------------------------
template <class T, class U>
bool operator()(const T& x, const U& y) const {
std::integral_constant<bool, SumType<T>()> lhs_is_sum_type;
std::integral_constant<bool, SumType<U>()> rhs_is_sum_type;
return cmp(x, y, lhs_is_sum_type, rhs_is_sum_type);
}
private:
// -- automagic unboxing of sum types ----------------------------------------
template <class T, class U>
bool cmp(const T& x, const U& y, std::false_type, std::false_type) const {
Operator f;
return f(x, y);
}
template <class T, class U>
bool cmp(const T& x, const U& y, std::true_type, std::false_type) const {
Operator f;
auto inner_x = caf::get_if<U>(&x);
return inner_x ? f(*inner_x, y) : Operator::default_value;
}
template <class T, class U>
bool cmp(const T& x, const U& y, std::false_type, std::true_type) const {
Operator f;
auto inner_y = caf::get_if<T>(&y);
return inner_y ? f(x, *inner_y) : Operator::default_value;
}
template <class T, class U>
bool cmp(const T& x, const U& y, std::true_type, std::true_type) const {
comparison_unbox_helper<comparison, U> f{*this, y};
return visit(f, x);
}
};
using equal_to = comparison<equality_operator>;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment