Commit 999cfe25 authored by Dominik Charousset's avatar Dominik Charousset

trivariant => optional_variant

this patch replaces trivariant with optional_variant which can offer the
same semantics when used as optional_variant<void,...>
parent ff852526
......@@ -42,6 +42,7 @@ cppa/detail/memory.hpp
cppa/detail/object_array.hpp
cppa/detail/object_impl.hpp
cppa/detail/opt_impls.hpp
cppa/detail/optional_variant_data.hpp
cppa/detail/pair_member.hpp
cppa/detail/projection.hpp
cppa/detail/pseudo_tuple.hpp
......@@ -124,6 +125,7 @@ cppa/opencl/program.hpp
cppa/opencl/smart_ptr.hpp
cppa/opt.hpp
cppa/option.hpp
cppa/optional_variant.hpp
cppa/partial_function.hpp
cppa/primitive_type.hpp
cppa/primitive_variant.hpp
......@@ -149,7 +151,6 @@ cppa/threadless.hpp
cppa/timeout_definition.hpp
cppa/to_string.hpp
cppa/tpartial_function.hpp
cppa/trivariant.hpp
cppa/tuple_cast.hpp
cppa/type_lookup_table.hpp
cppa/uniform_type_info.hpp
......@@ -304,13 +305,13 @@ unit_testing/test_local_group.cpp
unit_testing/test_match.cpp
unit_testing/test_metaprogramming.cpp
unit_testing/test_opencl.cpp
unit_testing/test_optional_variant.cpp
unit_testing/test_primitive_variant.cpp
unit_testing/test_remote_actor.cpp
unit_testing/test_ripemd_160.cpp
unit_testing/test_serialization.cpp
unit_testing/test_spawn.cpp
unit_testing/test_sync_send.cpp
unit_testing/test_trivariant.cpp
unit_testing/test_tuple.cpp
unit_testing/test_uniform_type.cpp
unit_testing/test_yield_interface.cpp
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_ *
* /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\ *
* \/____/ \/_/\/___/ \/____/ \ \ \/ \ \ \/ \/__/\/_/ *
* \ \_\ \ \_\ *
* \/_/ \/_/ *
* *
* Copyright (C) 2011-2013 *
* Dominik Charousset <dominik.charousset@haw-hamburg.de> *
* *
* This file is part of libcppa. *
* libcppa is free software: you can redistribute it and/or modify it under *
* the terms of the GNU Lesser General Public License as published by the *
* Free Software Foundation; either version 2.1 of the License, *
* or (at your option) any later version. *
* *
* libcppa is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
* See the GNU Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with libcppa. If not, see <http://www.gnu.org/licenses/>. *
\******************************************************************************/
#ifndef TRIVARIANT_DATA_HPP
#define TRIVARIANT_DATA_HPP
#include <stdexcept>
#include <type_traits>
#define CPPA_OPTIONAL_VARIANT_DATA_CONCAT(x, y) x ## y
#define CPPA_OPTIONAL_VARIANT_DATA_GETTER(pos) \
inline CPPA_OPTIONAL_VARIANT_DATA_CONCAT(T, pos) & \
get(std::integral_constant<int, pos >) { \
return CPPA_OPTIONAL_VARIANT_DATA_CONCAT(v, pos) ; \
} \
inline const CPPA_OPTIONAL_VARIANT_DATA_CONCAT(T, pos) & \
get(std::integral_constant<int, pos >) const { \
return CPPA_OPTIONAL_VARIANT_DATA_CONCAT(v, pos) ; \
}
namespace cppa { struct none_t; }
namespace cppa { namespace detail {
template<typename T>
struct lift_void { typedef T type; };
template<>
struct lift_void<void> { typedef util::void_type type; };
template<typename T0, typename T1 = util::void_type,
typename T2 = util::void_type, typename T3 = util::void_type,
typename T4 = util::void_type, typename T5 = util::void_type,
typename T6 = util::void_type, typename T7 = util::void_type,
typename T8 = util::void_type, typename T9 = util::void_type>
struct optional_variant_data {
union {
T0 v0; T1 v1; T2 v2; T3 v3; T4 v4;
T5 v5; T6 v6; T7 v7; T8 v8; T9 v9;
};
optional_variant_data() { }
template<int Id, typename U>
optional_variant_data(std::integral_constant<int, Id> token, U&& arg) {
cr(get(token), std::forward<U>(arg));
}
~optional_variant_data() { }
CPPA_OPTIONAL_VARIANT_DATA_GETTER(0)
CPPA_OPTIONAL_VARIANT_DATA_GETTER(1)
CPPA_OPTIONAL_VARIANT_DATA_GETTER(2)
CPPA_OPTIONAL_VARIANT_DATA_GETTER(3)
CPPA_OPTIONAL_VARIANT_DATA_GETTER(4)
CPPA_OPTIONAL_VARIANT_DATA_GETTER(5)
CPPA_OPTIONAL_VARIANT_DATA_GETTER(6)
CPPA_OPTIONAL_VARIANT_DATA_GETTER(7)
CPPA_OPTIONAL_VARIANT_DATA_GETTER(8)
CPPA_OPTIONAL_VARIANT_DATA_GETTER(9)
private:
template<typename M, typename U>
inline void cr(M& member, U&& arg) {
new (&member) M (std::forward<U>(arg));
}
};
struct optional_variant_data_destructor {
inline void operator()() const { }
inline void operator()(const none_t&) const { }
template<typename T>
inline void operator()(T& storage) const { storage.~T(); }
};
} } // namespace cppa::detail
#endif // TRIVARIANT_DATA_HPP
......@@ -359,7 +359,6 @@ class local_actor : public extend<actor>::with<memory_cached> {
std::function<void()> m_sync_failure_handler;
std::function<void()> m_sync_timeout_handler;
/** @endcond */
};
......
......@@ -37,235 +37,204 @@
#include "cppa/util/type_list.hpp"
#include "cppa/util/void_type.hpp"
namespace cppa {
namespace detail {
template<typename T0, typename T1 = util::void_type,
typename T2 = util::void_type, typename T3 = util::void_type,
typename T4 = util::void_type, typename T5 = util::void_type,
typename T6 = util::void_type, typename T7 = util::void_type,
typename T8 = util::void_type, typename T9 = util::void_type>
struct variant_data {
#include "cppa/detail/optional_variant_data.hpp"
union {
T0 v0; T1 v1; T2 v2; T3 v3; T4 v4;
T5 v5; T6 v6; T7 v7; T8 v8; T9 v9;
};
variant_data() { }
template<int Id, typename U>
variant_data(std::integral_constant<int, Id> token, U&& arg) {
cr(get(token), std::forward<U>(arg));
}
~variant_data() { }
inline const T0& get(std::integral_constant<int, 0>) const {
return v0;
}
inline const T1& get(std::integral_constant<int, 1>) const {
return v1;
}
#define CPPA_OPTIONAL_VARIANT_CASE(x) \
case x: return do_visit(from, visitor, \
make_bool_token<void_pos == x >(), \
make_int_token< x >()) \
inline const T2& get(std::integral_constant<int, 2>) const {
return v2;
}
inline const T3& get(std::integral_constant<int, 3>) const {
return v3;
}
inline const T4& get(std::integral_constant<int, 4>) const {
return v4;
}
namespace cppa {
inline const T5& get(std::integral_constant<int, 5>) const {
return v5;
}
struct none_t { };
inline const T6& get(std::integral_constant<int, 6>) const {
return v6;
}
template<int Value>
constexpr std::integral_constant<int, Value> make_int_token() { return {}; }
inline const T7& get(std::integral_constant<int, 7>) const {
return v7;
}
template<bool Value>
constexpr std::integral_constant<bool, Value> make_bool_token() { return {}; }
inline const T8& get(std::integral_constant<int, 8>) const {
return v8;
}
/**
* @brief A optional_variant is either invalid or holds
a value of one of the types <tt>Ts</tt>.
*/
template<typename... Ts>
class optional_variant {
inline const T9& get(std::integral_constant<int, 9>) const {
return v9;
}
inline T0& get(std::integral_constant<int, 0>) {
return v0;
}
inline T1& get(std::integral_constant<int, 1>) {
return v1;
}
public:
inline T2& get(std::integral_constant<int, 2>) {
return v2;
}
typedef util::type_list<Ts...> types;
inline T3& get(std::integral_constant<int, 3>) {
return v3;
}
static constexpr int void_pos = util::tl_find<types, void>::value;
inline T4& get(std::integral_constant<int, 4>) {
return v4;
template<typename U>
inline bool is() const {
static_assert(util::tl_find<types, U>::value != -1, "invalid type");
return m_type == util::tl_find<types, U>::value;
}
inline T5& get(std::integral_constant<int, 5>) {
return v5;
template<typename U>
optional_variant& operator=(const U& arg) {
static_assert(util::tl_find<types, U>::value != -1, "invalid type");
destroy_data();
m_type = util::tl_find<types, U>::value;
auto& ref = get(make_int_token<util::tl_find<types, U>::value>());
new (&ref) U (arg);
return *this;
}
inline T6& get(std::integral_constant<int, 6>) {
return v6;
}
optional_variant() : m_type(-1) { }
inline T7& get(std::integral_constant<int, 7>) {
return v7;
template<typename U>
optional_variant(const U& value)
: m_type{util::tl_find<types, U>::value}
, m_data{std::integral_constant<int, util::tl_find<types, U>::value>{}, value} {
static_assert(util::tl_find<types, U>::value >= 0, "invalid type");
}
inline T8& get(std::integral_constant<int, 8>) {
return v8;
optional_variant(const util::void_type& value)
: m_type{void_pos}
, m_data{std::integral_constant<int, void_pos>{}, value} {
static_assert(void_pos >= 0, "this variant does not allow 'void' value");
}
inline T9& get(std::integral_constant<int, 9>) {
return v9;
~optional_variant() {
destroy_data();
}
private:
template<typename M, typename U>
inline void cr(M& member, U&& arg) {
new (&member) M (std::forward<U>(arg));
/**
* @brief Checks whether this optional_variant is valid.
*/
explicit operator bool() const {
return m_type != -1;
}
};
struct destructor {
template<typename T>
inline void operator()(T& storage) const { storage.~T(); }
};
template<typename T>
struct copy_constructor {
const T& other;
copy_constructor(const T& from) : other{from} { }
void operator()(T& storage) const { new (&storage) T (other); }
template<typename U>
void operator()(U&) const { throw std::runtime_error("type mismatch"); }
};
} // namespace detail
template<typename... T>
class trivariant {
public:
typedef util::type_list<T...> types;
inline bool undefined() const { return m_type == -2; }
inline bool empty() const { return m_type == -1; }
/** @cond PRIVATE */
template<int Pos>
inline const typename util::tl_at<types, Pos>::type& get(std::integral_constant<int, Pos> token) const {
inline const typename util::tl_at<types, Pos>::type&
get(std::integral_constant<int, Pos> token,
typename std::enable_if<Pos < sizeof...(Ts) && Pos != void_pos>::type* = nullptr) const {
return m_data.get(token);
}
template<int Pos>
inline typename util::tl_at<types, Pos>::type& get(std::integral_constant<int, Pos> token) {
return m_data.get(token);
}
template<typename U>
inline bool is() const {
return !empty() && m_type == util::tl_find<types, U>::value;
}
template<typename U>
trivariant& operator=(const U& what) {
apply(detail::destructor{});
apply(detail::copy_constructor<U>{what});
}
inline void get(std::integral_constant<int, Pos>,
typename std::enable_if<Pos >= sizeof...(Ts) || Pos == void_pos>::type* = nullptr) const { }
void clear() {
apply(detail::destructor{});
m_type = -1;
}
void invalidate() {
apply(detail::destructor{});
m_type = -2;
template<int Pos>
inline typename util::tl_at<types, Pos>::type&
get(std::integral_constant<int, Pos> token,
typename std::enable_if<Pos < sizeof...(Ts) && Pos != void_pos>::type* = nullptr) {
return m_data.get(token);
}
trivariant() : m_type(-2) { }
trivariant(const util::void_type&) : m_type(-1) { }
template<typename U>
trivariant(const U& value)
: m_type{util::tl_find<types, U>::value}
, m_data{std::integral_constant<int, util::tl_find<types, U>::value>{}, value} {
static_assert(util::tl_find<types, U>::value >= 0, "invalid type T");
template<typename Visitor>
auto apply(const Visitor& visitor) const -> decltype(visitor(none_t{})) {
return do_apply(*this, visitor);
}
~trivariant() {
apply(detail::destructor{});
template<typename Visitor>
auto apply(const Visitor& visitor) -> decltype(visitor(none_t{})) {
return do_apply(*this, visitor);
}
explicit operator bool() const {
return m_type != -2;
}
/** @endcond */
private:
template<typename Visitor>
void apply(const Visitor& visitor) {
switch (m_type) {
template<typename Self, typename Visitor, int Pos>
static auto do_visit(Self& from,
const Visitor& visitor,
std::integral_constant<bool, false> /* is_not_void */,
std::integral_constant<int, Pos> token,
typename std::enable_if<Pos < sizeof...(Ts)>::type* = nullptr)
-> decltype(visitor(none_t{})) {
return visitor(from.get(token));
}
template<typename Self, typename Visitor, int Pos>
static auto do_visit(Self&,
const Visitor& visitor,
std::integral_constant<bool, true> /* is_void */,
std::integral_constant<int, Pos>,
typename std::enable_if<Pos < sizeof...(Ts)>::type* = nullptr)
-> decltype(visitor(none_t{})) {
return visitor();
}
template<typename Self, typename Visitor, int Pos>
static auto do_visit(Self&,
const Visitor& visitor,
std::integral_constant<bool, false>,
std::integral_constant<int, Pos>,
typename std::enable_if<Pos >= sizeof...(Ts)>::type* = nullptr)
-> decltype(visitor(none_t{})) {
// this is not the function you are looking for
throw std::runtime_error("invalid type found");
}
template<typename Self, typename Visitor>
static auto do_apply(Self& from, const Visitor& visitor) -> decltype(visitor(none_t{})) {
switch (from.m_type) {
default: throw std::runtime_error("invalid type found");
case -2: break;
case -1: break;
case 0: visitor(m_data.v0); break;
case 1: visitor(m_data.v1); break;
case 2: visitor(m_data.v2); break;
case 3: visitor(m_data.v3); break;
case 4: visitor(m_data.v4); break;
case 5: visitor(m_data.v5); break;
case 6: visitor(m_data.v6); break;
case 7: visitor(m_data.v7); break;
case 8: visitor(m_data.v8); break;
case 9: visitor(m_data.v9); break;
case -1: return visitor(none_t{});
CPPA_OPTIONAL_VARIANT_CASE(0);
CPPA_OPTIONAL_VARIANT_CASE(1);
CPPA_OPTIONAL_VARIANT_CASE(2);
CPPA_OPTIONAL_VARIANT_CASE(3);
CPPA_OPTIONAL_VARIANT_CASE(4);
CPPA_OPTIONAL_VARIANT_CASE(5);
CPPA_OPTIONAL_VARIANT_CASE(6);
CPPA_OPTIONAL_VARIANT_CASE(7);
CPPA_OPTIONAL_VARIANT_CASE(8);
CPPA_OPTIONAL_VARIANT_CASE(9);
}
}
inline void destroy_data() {
apply(detail::optional_variant_data_destructor{});
}
int m_type;
detail::variant_data<T...> m_data;
detail::optional_variant_data<typename detail::lift_void<Ts>::type...> m_data;
};
/**
* @relates optional_variant
*/
template<typename T, typename... Us>
const T& get(const trivariant<Us...>& value) {
const T& get(const optional_variant<Us...>& value) {
std::integral_constant<int, util::tl_find<util::type_list<Us...>, T>::value> token;
return value.get(token);
}
/**
* @relates optional_variant
*/
template<typename T, typename... Us>
T& get_ref(trivariant<Us...>& value) {
T& get_ref(optional_variant<Us...>& value) {
std::integral_constant<int, util::tl_find<util::type_list<Us...>, T>::value> token;
return value.get(token);
}
/**
* @relates optional_variant
*/
template<typename Visitor, typename... Ts>
auto apply_visitor(const Visitor& visitor, const optional_variant<Ts...>& data) -> decltype(visitor(none_t{})) {
return data.apply(visitor);
}
/**
* @relates optional_variant
*/
template<typename Visitor, typename... Ts>
auto apply_visitor(const Visitor& visitor, optional_variant<Ts...>& data) -> decltype(visitor(none_t{})) {
return data.apply(visitor);
}
} // namespace cppa
#endif // OPTIONAL_VARIANT_HPP
......@@ -12,7 +12,7 @@ endmacro()
add_unit_test(ripemd_160)
add_unit_test(atom)
add_unit_test(trivariant)
add_unit_test(optional_variant)
add_unit_test(metaprogramming)
add_unit_test(intrusive_containers)
add_unit_test(serialization)
......
#include <iostream>
#include <functional>
#include "test.hpp"
#include "cppa/cppa.hpp"
#include "cppa/optional_variant.hpp"
using namespace std;
using namespace cppa;
namespace { std::atomic<size_t> some_struct_instances; }
struct some_struct {
some_struct() { ++some_struct_instances; }
some_struct(const some_struct&) { ++some_struct_instances; }
~some_struct() { --some_struct_instances; }
};
struct int_visitor {
int operator()(none_t) const { return -1; }
int operator()(int i) const { return i; }
int operator()(const some_struct&) const { return 0; }
};
using dlimits = std::numeric_limits<double>;
struct double_visitor {
double operator()(none_t) const { return dlimits::signaling_NaN(); }
double operator()(void) const { return dlimits::quiet_NaN(); }
double operator()(int i) const { return i; }
double operator()(float f) const { return f; }
double operator()(double d) const { return d; }
};
int main() {
CPPA_TEST(test_optional_variant);
/* run tets using primitive types */ {
using tri_type = optional_variant<void, int, double, float>;
tri_type t0;
tri_type t1{util::void_type{}};
tri_type t2{0};
tri_type t3{0.0};
tri_type t4{0.0f};
CPPA_CHECK(!t0);
CPPA_CHECK(t1 && t1.is<void>());
CPPA_CHECK(t2.is<int>());
CPPA_CHECK(!t2.is<double>());
CPPA_CHECK(!t2.is<float>());
CPPA_CHECK_EQUAL(get<int>(t2), 0);
get_ref<int>(t2) = 42;
CPPA_CHECK_EQUAL(get<int>(t2), 42);
CPPA_CHECK(!t3.is<int>());
CPPA_CHECK(t3.is<double>());
CPPA_CHECK(!t3.is<float>());
CPPA_CHECK_EQUAL(get<double>(t3), 0.0);
get_ref<double>(t3) = 4.2;
CPPA_CHECK_EQUAL(get<double>(t3), 4.2);
CPPA_CHECK(!t4.is<int>());
CPPA_CHECK(!t4.is<double>());
CPPA_CHECK(t4.is<float>());
CPPA_CHECK_EQUAL(get<float>(t4), 0.0f);
get_ref<float>(t4) = 2.3f;
CPPA_CHECK_EQUAL(get<float>(t4), 2.3f);
double_visitor dv;
auto v = apply_visitor(dv, t0);
CPPA_CHECK(v != v); // only true if v is NaN
v = apply_visitor(dv, t1);
CPPA_CHECK(v != v); // only true if v is NaN
CPPA_CHECK_EQUAL(apply_visitor(dv, t2), 42.0);
CPPA_CHECK_EQUAL(apply_visitor(dv, t3), 4.2);
// converting 2.3f to double is not exactly 2.3
CPPA_CHECK_EQUAL(apply_visitor(dv, t4), static_cast<double>(2.3f));
t4 = 1;
CPPA_CHECK(t4.is<int>() && get<int>(t4) == 1);
}
/* run tests using user-defined types */ {
using tri_type = optional_variant<int, some_struct>;
tri_type t0;
tri_type t1{42};
CPPA_CHECK_EQUAL(some_struct_instances.load(), 0);
tri_type t2{some_struct{}};
CPPA_CHECK_EQUAL(some_struct_instances.load(), 1);
CPPA_CHECK(!t0);
CPPA_CHECK(t1 && t1.is<int>() && get<int>(t1) == 42);
CPPA_CHECK(t2 && t2.is<some_struct>());
int_visitor iVisit;
CPPA_CHECK_EQUAL(apply_visitor(iVisit, t0), -1);
CPPA_CHECK_EQUAL(apply_visitor(iVisit, t1), 42);
CPPA_CHECK_EQUAL(apply_visitor(iVisit, t2), 0);
}
CPPA_CHECK_EQUAL(some_struct_instances.load(), 0);
return CPPA_TEST_RESULT();
}
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