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 ...@@ -42,6 +42,7 @@ cppa/detail/memory.hpp
cppa/detail/object_array.hpp cppa/detail/object_array.hpp
cppa/detail/object_impl.hpp cppa/detail/object_impl.hpp
cppa/detail/opt_impls.hpp cppa/detail/opt_impls.hpp
cppa/detail/optional_variant_data.hpp
cppa/detail/pair_member.hpp cppa/detail/pair_member.hpp
cppa/detail/projection.hpp cppa/detail/projection.hpp
cppa/detail/pseudo_tuple.hpp cppa/detail/pseudo_tuple.hpp
...@@ -124,6 +125,7 @@ cppa/opencl/program.hpp ...@@ -124,6 +125,7 @@ cppa/opencl/program.hpp
cppa/opencl/smart_ptr.hpp cppa/opencl/smart_ptr.hpp
cppa/opt.hpp cppa/opt.hpp
cppa/option.hpp cppa/option.hpp
cppa/optional_variant.hpp
cppa/partial_function.hpp cppa/partial_function.hpp
cppa/primitive_type.hpp cppa/primitive_type.hpp
cppa/primitive_variant.hpp cppa/primitive_variant.hpp
...@@ -149,7 +151,6 @@ cppa/threadless.hpp ...@@ -149,7 +151,6 @@ cppa/threadless.hpp
cppa/timeout_definition.hpp cppa/timeout_definition.hpp
cppa/to_string.hpp cppa/to_string.hpp
cppa/tpartial_function.hpp cppa/tpartial_function.hpp
cppa/trivariant.hpp
cppa/tuple_cast.hpp cppa/tuple_cast.hpp
cppa/type_lookup_table.hpp cppa/type_lookup_table.hpp
cppa/uniform_type_info.hpp cppa/uniform_type_info.hpp
...@@ -304,13 +305,13 @@ unit_testing/test_local_group.cpp ...@@ -304,13 +305,13 @@ unit_testing/test_local_group.cpp
unit_testing/test_match.cpp unit_testing/test_match.cpp
unit_testing/test_metaprogramming.cpp unit_testing/test_metaprogramming.cpp
unit_testing/test_opencl.cpp unit_testing/test_opencl.cpp
unit_testing/test_optional_variant.cpp
unit_testing/test_primitive_variant.cpp unit_testing/test_primitive_variant.cpp
unit_testing/test_remote_actor.cpp unit_testing/test_remote_actor.cpp
unit_testing/test_ripemd_160.cpp unit_testing/test_ripemd_160.cpp
unit_testing/test_serialization.cpp unit_testing/test_serialization.cpp
unit_testing/test_spawn.cpp unit_testing/test_spawn.cpp
unit_testing/test_sync_send.cpp unit_testing/test_sync_send.cpp
unit_testing/test_trivariant.cpp
unit_testing/test_tuple.cpp unit_testing/test_tuple.cpp
unit_testing/test_uniform_type.cpp unit_testing/test_uniform_type.cpp
unit_testing/test_yield_interface.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> { ...@@ -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_failure_handler;
std::function<void()> m_sync_timeout_handler; std::function<void()> m_sync_timeout_handler;
/** @endcond */
}; };
......
...@@ -37,235 +37,204 @@ ...@@ -37,235 +37,204 @@
#include "cppa/util/type_list.hpp" #include "cppa/util/type_list.hpp"
#include "cppa/util/void_type.hpp" #include "cppa/util/void_type.hpp"
namespace cppa { #include "cppa/detail/optional_variant_data.hpp"
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 {
union { #define CPPA_OPTIONAL_VARIANT_CASE(x) \
T0 v0; T1 v1; T2 v2; T3 v3; T4 v4; case x: return do_visit(from, visitor, \
T5 v5; T6 v6; T7 v7; T8 v8; T9 v9; make_bool_token<void_pos == x >(), \
}; make_int_token< x >()) \
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;
}
inline const T2& get(std::integral_constant<int, 2>) const { namespace cppa {
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;
}
inline const T5& get(std::integral_constant<int, 5>) const { struct none_t { };
return v5;
}
inline const T6& get(std::integral_constant<int, 6>) const { template<int Value>
return v6; constexpr std::integral_constant<int, Value> make_int_token() { return {}; }
}
inline const T7& get(std::integral_constant<int, 7>) const { template<bool Value>
return v7; 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 { public:
return v9;
}
inline T0& get(std::integral_constant<int, 0>) {
return v0;
}
inline T1& get(std::integral_constant<int, 1>) {
return v1;
}
inline T2& get(std::integral_constant<int, 2>) { typedef util::type_list<Ts...> types;
return v2;
}
inline T3& get(std::integral_constant<int, 3>) { static constexpr int void_pos = util::tl_find<types, void>::value;
return v3;
}
inline T4& get(std::integral_constant<int, 4>) { template<typename U>
return v4; 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>) { template<typename U>
return v5; 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>) { optional_variant() : m_type(-1) { }
return v6;
}
inline T7& get(std::integral_constant<int, 7>) { template<typename U>
return v7; 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>) { optional_variant(const util::void_type& value)
return v8; : 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>) { ~optional_variant() {
return v9; destroy_data();
} }
private: /**
* @brief Checks whether this optional_variant is valid.
template<typename M, typename U> */
inline void cr(M& member, U&& arg) { explicit operator bool() const {
new (&member) M (std::forward<U>(arg)); return m_type != -1;
} }
}; /** @cond PRIVATE */
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; }
template<int Pos> 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); return m_data.get(token);
} }
template<int Pos> template<int Pos>
inline typename util::tl_at<types, Pos>::type& get(std::integral_constant<int, Pos> token) { inline void get(std::integral_constant<int, Pos>,
return m_data.get(token); typename std::enable_if<Pos >= sizeof...(Ts) || Pos == void_pos>::type* = nullptr) const { }
}
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});
}
void clear() { template<int Pos>
apply(detail::destructor{}); inline typename util::tl_at<types, Pos>::type&
m_type = -1; get(std::integral_constant<int, Pos> token,
} typename std::enable_if<Pos < sizeof...(Ts) && Pos != void_pos>::type* = nullptr) {
return m_data.get(token);
void invalidate() {
apply(detail::destructor{});
m_type = -2;
} }
trivariant() : m_type(-2) { } template<typename Visitor>
auto apply(const Visitor& visitor) const -> decltype(visitor(none_t{})) {
trivariant(const util::void_type&) : m_type(-1) { } return do_apply(*this, visitor);
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");
} }
~trivariant() { template<typename Visitor>
apply(detail::destructor{}); auto apply(const Visitor& visitor) -> decltype(visitor(none_t{})) {
return do_apply(*this, visitor);
} }
explicit operator bool() const { /** @endcond */
return m_type != -2;
}
private: private:
template<typename Visitor> template<typename Self, typename Visitor, int Pos>
void apply(const Visitor& visitor) { static auto do_visit(Self& from,
switch (m_type) { 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"); default: throw std::runtime_error("invalid type found");
case -2: break; case -1: return visitor(none_t{});
case -1: break; CPPA_OPTIONAL_VARIANT_CASE(0);
case 0: visitor(m_data.v0); break; CPPA_OPTIONAL_VARIANT_CASE(1);
case 1: visitor(m_data.v1); break; CPPA_OPTIONAL_VARIANT_CASE(2);
case 2: visitor(m_data.v2); break; CPPA_OPTIONAL_VARIANT_CASE(3);
case 3: visitor(m_data.v3); break; CPPA_OPTIONAL_VARIANT_CASE(4);
case 4: visitor(m_data.v4); break; CPPA_OPTIONAL_VARIANT_CASE(5);
case 5: visitor(m_data.v5); break; CPPA_OPTIONAL_VARIANT_CASE(6);
case 6: visitor(m_data.v6); break; CPPA_OPTIONAL_VARIANT_CASE(7);
case 7: visitor(m_data.v7); break; CPPA_OPTIONAL_VARIANT_CASE(8);
case 8: visitor(m_data.v8); break; CPPA_OPTIONAL_VARIANT_CASE(9);
case 9: visitor(m_data.v9); break;
} }
} }
inline void destroy_data() {
apply(detail::optional_variant_data_destructor{});
}
int m_type; 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> 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; std::integral_constant<int, util::tl_find<util::type_list<Us...>, T>::value> token;
return value.get(token); return value.get(token);
} }
/**
* @relates optional_variant
*/
template<typename T, typename... Us> 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; std::integral_constant<int, util::tl_find<util::type_list<Us...>, T>::value> token;
return value.get(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 } // namespace cppa
#endif // OPTIONAL_VARIANT_HPP #endif // OPTIONAL_VARIANT_HPP
...@@ -12,7 +12,7 @@ endmacro() ...@@ -12,7 +12,7 @@ endmacro()
add_unit_test(ripemd_160) add_unit_test(ripemd_160)
add_unit_test(atom) add_unit_test(atom)
add_unit_test(trivariant) add_unit_test(optional_variant)
add_unit_test(metaprogramming) add_unit_test(metaprogramming)
add_unit_test(intrusive_containers) add_unit_test(intrusive_containers)
add_unit_test(serialization) 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