Updates from BitShares FC #22

Closed
nathanielhourt wants to merge 693 commits from dapp-support into latest-fc
8 changed files with 669 additions and 294 deletions
Showing only changes of commit 4b7bcb951d - Show all commits

View file

@ -1,6 +1,6 @@
#pragma once
/**
* @file fc/reflect.hpp
* @file fc/reflect/reflect.hpp
*
* @brief Defines types and macros used to provide reflection.
*
@ -18,9 +18,114 @@
#include <type_traits>
#include <fc/reflect/typename.hpp>
#include <fc/reflect/typelist.hpp>
namespace fc {
template<typename> struct reflector;
namespace member_names {
/// A template which stores the name of the native member at a given index in a given class
template<typename Class, std::size_t index> struct member_name {
constexpr static const char* value = "Unknown member";
};
}
/**
* @brief A template to store compile-time information about a field in a reflected struct
*
* @tparam Container The type of the struct or class containing the field
* @tparam Member The type of the field
* @tparam field A pointer-to-member for the reflected field
*/
template<std::size_t Index, typename Container, typename Member, Member Container::*field>
struct field_reflection {
using container = Container;
using type = Member;
using reflector = fc::reflector<type>;
constexpr static std::size_t index = Index;
constexpr static bool is_derived = false;
constexpr static type container::*pointer = field;
/// @brief Given a reference to the container type, get a reference to the field
static type& get(container& c) { return c.*field; }
static const type& get(const container& c) { return c.*field; }
/// @brief Get the name of the field
static const char* get_name() { return fc::member_names::member_name<container, index>::value; }
};
/// Basically the same as @ref field_reflection, but for inherited fields
/// Note that inherited field reflections do not have an index field; indexes are for native fields only
template<std::size_t IndexInBase, typename Base, typename Derived, typename Member, Member Base::*field>
struct inherited_field_reflection {
using container = Derived;
using field_container = Base;
using type = Member;
using reflector = fc::reflector<type>;
constexpr static std::size_t index_in_base = IndexInBase;
constexpr static bool is_derived = true;
constexpr static type field_container::*pointer = field;
static type& get(container& c) {
// And we need a distinct inherited_field_reflection type because this conversion can't be done statically
type container::* derived_field = field;
return c.*derived_field;
}
static const type& get(const container& c) {
type container::* derived_field = field;
return c.*derived_field;
}
static const char* get_name() {
using Reflector = typename fc::reflector<Base>::native_members::template at<IndexInBase>;
return Reflector::get_name();
}
};
namespace impl {
/// Helper template to create a @ref field_reflection without any commas (makes it macro-friendly)
template<typename Container>
struct Reflect_type {
template<typename Member>
struct with_field_type {
template<std::size_t Index>
struct at_index {
template<Member Container::*field>
struct with_field_pointer {
using type = field_reflection<Index, Container, Member, field>;
};
};
};
};
/// Template to make a transformer of a @ref field_reflection from a base class to a derived class
template<typename Derived>
struct Derivation_reflection_transformer {
template<typename> struct transform;
template<std::size_t IndexInBase, typename BaseContainer, typename Member, Member BaseContainer::*field>
struct transform<field_reflection<IndexInBase, BaseContainer, Member, field>> {
using type = inherited_field_reflection<IndexInBase, BaseContainer, Derived, Member, field>;
};
template<std::size_t IndexInBase, typename BaseContainer, typename IntermediateContainer,
typename Member, Member BaseContainer::*field>
struct transform<inherited_field_reflection<IndexInBase, BaseContainer, IntermediateContainer, Member, field>> {
using type = inherited_field_reflection<IndexInBase, BaseContainer, Derived, Member, field>;
};
};
} // namespace impl
/// Macro to transform reflected fields of a base class to a derived class and concatenate them to a type list
#define FC_CONCAT_BASE_MEMBER_REFLECTIONS(r, derived, base) \
::add_list<typelist::transform<reflector<base>::members, impl::Derivation_reflection_transformer<derived>>>
/// Macro to concatenate a new @ref field_reflection to a typelist
#define FC_CONCAT_MEMBER_REFLECTION(r, container, idx, member) \
::add<typename impl::Reflect_type<container>::template with_field_type<decltype(container::member)> \
::template at_index<idx> \
::template with_field_pointer<&container::member>::type>
#define FC_REFLECT_MEMBER_NAME(r, container, idx, member) \
template<> struct member_name<container, idx> { constexpr static const char* value = BOOST_PP_STRINGIZE(member); };
#define FC_REFLECT_TEMPLATE_MEMBER_NAME(r, data, idx, member) \
template<BOOST_PP_SEQ_ENUM(BOOST_PP_SEQ_ELEM(0, data))> struct member_name<BOOST_PP_SEQ_ELEM(1, data), idx> { \
constexpr static const char* value = BOOST_PP_STRINGIZE(member); };
/// Macro to concatenate a new type to a typelist
#define FC_CONCAT_TYPE(r, x, TYPE) ::add<TYPE>
/**
* @brief defines visit functions for T
* Unless this is specialized, visit() will not be defined for T.
@ -34,6 +139,14 @@ template<typename T>
struct reflector{
typedef T type;
typedef std::false_type is_defined;
/// A typelist with a @ref field_reflection for each native member (non-inherited) of the struct
using native_members = typelist::list<>;
/// A typelist with a @ref field_reflection for each inherited member of the struct
using inherited_members = typelist::list<>;
/// A typelist with a @ref field_reflection for each member of the struct, starting with inherited members
using members = typelist::list<>;
/// A typelist of base classes for this type
using base_classes = typelist::list<>;
/**
* @tparam Visitor a function object of the form:
@ -91,31 +204,11 @@ void throw_bad_enum_cast( const char* k, const char* e );
case I: FC_REFLECT_VISIT_MEMBER( r, visitor, elem ) break;
#define FC_REFLECT_BASE_MEMBER_COUNT( r, OP, elem ) \
OP fc::reflector<elem>::total_member_count
#define FC_REFLECT_MEMBER_COUNT( r, OP, elem ) \
OP 1
#define FC_REFLECT_DERIVED_IMPL_INLINE( TYPE, INHERITS, MEMBERS ) \
template<typename Visitor>\
static inline void visit( const Visitor& v ) { \
BOOST_PP_SEQ_FOR_EACH( FC_REFLECT_VISIT_BASE, v, INHERITS ) \
BOOST_PP_SEQ_FOR_EACH( FC_REFLECT_VISIT_MEMBER, v, MEMBERS ) \
}\
template<typename Visitor, typename IndexType>\
static inline void visit_local_member( const Visitor& v, IndexType index ) { \
switch( index ) {\
BOOST_PP_SEQ_FOR_EACH_I( FC_REFLECT_VISIT_MEMBER_I, v, MEMBERS ) \
default: break;\
}\
}
#define FC_REFLECT_DERIVED_IMPL_EXT( TYPE, INHERITS, MEMBERS ) \
template<typename Visitor>\
void fc::reflector<TYPE>::visit( const Visitor& v ) { \
BOOST_PP_SEQ_FOR_EACH( FC_REFLECT_VISIT_BASE, v, INHERITS ) \
BOOST_PP_SEQ_FOR_EACH( FC_REFLECT_VISIT_MEMBER, v, MEMBERS ) \
}
#endif // DOXYGEN
@ -214,26 +307,50 @@ namespace fc { \
template<> struct reflector<TYPE> {\
typedef TYPE type; \
typedef std::true_type is_defined; \
using native_members = \
typename typelist::builder<>::type \
BOOST_PP_SEQ_FOR_EACH_I( FC_CONCAT_MEMBER_REFLECTION, TYPE, MEMBERS ) ::finalize; \
using inherited_members = \
typename typelist::builder<>::type \
BOOST_PP_SEQ_FOR_EACH( FC_CONCAT_BASE_MEMBER_REFLECTIONS, TYPE, INHERITS ) ::finalize; \
using members = typename typelist::concat<inherited_members, native_members>::type; \
using base_classes = typename typelist::builder<>::type \
BOOST_PP_SEQ_FOR_EACH( FC_CONCAT_TYPE, x, INHERITS ) ::finalize; \
enum member_count_enum { \
local_member_count = 0 BOOST_PP_SEQ_FOR_EACH( FC_REFLECT_MEMBER_COUNT, +, MEMBERS ),\
total_member_count = local_member_count BOOST_PP_SEQ_FOR_EACH( FC_REFLECT_BASE_MEMBER_COUNT, +, INHERITS )\
local_member_count = typelist::length<native_members>(), \
total_member_count = typelist::length<members>() \
}; \
FC_REFLECT_DERIVED_IMPL_INLINE( TYPE, INHERITS, MEMBERS ) \
}; }
}; \
namespace member_names { \
BOOST_PP_SEQ_FOR_EACH_I( FC_REFLECT_MEMBER_NAME, TYPE, MEMBERS ) \
} }
#define FC_REFLECT_DERIVED_TEMPLATE( TEMPLATE_ARGS, TYPE, INHERITS, MEMBERS ) \
namespace fc { \
template<BOOST_PP_SEQ_ENUM(TEMPLATE_ARGS)> struct get_typename<TYPE> { static const char* name() { return BOOST_PP_STRINGIZE(TYPE); } }; \
template<BOOST_PP_SEQ_ENUM(TEMPLATE_ARGS)> struct get_typename<TYPE> { \
static const char* name() { return BOOST_PP_STRINGIZE(TYPE); } \
}; \
template<BOOST_PP_SEQ_ENUM(TEMPLATE_ARGS)> struct reflector<TYPE> {\
typedef TYPE type; \
typedef std::true_type is_defined; \
using native_members = \
typename typelist::builder<>::type \
BOOST_PP_SEQ_FOR_EACH_I( FC_CONCAT_MEMBER_REFLECTION, TYPE, MEMBERS ) ::finalize; \
using inherited_members = \
typename typelist::builder<>::type \
BOOST_PP_SEQ_FOR_EACH( FC_CONCAT_BASE_MEMBER_REFLECTIONS, TYPE, INHERITS ) ::finalize; \
using members = typename typelist::concat<inherited_members, native_members>::type; \
using base_classes = typename typelist::builder<>::type \
BOOST_PP_SEQ_FOR_EACH( FC_CONCAT_TYPE, x, INHERITS ) ::finalize; \
enum member_count_enum { \
local_member_count = 0 BOOST_PP_SEQ_FOR_EACH( FC_REFLECT_MEMBER_COUNT, +, MEMBERS ),\
total_member_count = local_member_count BOOST_PP_SEQ_FOR_EACH( FC_REFLECT_BASE_MEMBER_COUNT, +, INHERITS )\
local_member_count = typelist::length<native_members>(), \
total_member_count = typelist::length<members>() \
}; \
FC_REFLECT_DERIVED_IMPL_INLINE( TYPE, INHERITS, MEMBERS ) \
}; }
//BOOST_PP_SEQ_SIZE(MEMBERS),
}; \
namespace member_names { \
BOOST_PP_SEQ_FOR_EACH_I( FC_REFLECT_TEMPLATE_MEMBER_NAME, (TEMPLATE_ARGS)(TYPE), MEMBERS ) \
} }
/**
* @def FC_REFLECT(TYPE,MEMBERS)
@ -244,7 +361,8 @@ template<BOOST_PP_SEQ_ENUM(TEMPLATE_ARGS)> struct reflector<TYPE> {\
* @see FC_REFLECT_DERIVED
*/
#define FC_REFLECT( TYPE, MEMBERS ) \
FC_REFLECT_DERIVED( TYPE, BOOST_PP_SEQ_NIL, MEMBERS )
FC_REFLECT_DERIVED( TYPE, BOOST_PP_SEQ_NIL, MEMBERS )
#define FC_REFLECT_TEMPLATE( TEMPLATE_ARGS, TYPE, MEMBERS ) \
FC_REFLECT_DERIVED_TEMPLATE( TEMPLATE_ARGS, TYPE, BOOST_PP_SEQ_NIL, MEMBERS )
@ -257,25 +375,3 @@ namespace fc { \
template<> struct get_typename<TYPE> { static const char* name() { return BOOST_PP_STRINGIZE(TYPE); } }; \
}
#define FC_REFLECT_FWD( TYPE ) \
namespace fc { \
template<> struct get_typename<TYPE> { static const char* name() { return BOOST_PP_STRINGIZE(TYPE); } }; \
template<> struct reflector<TYPE> {\
typedef TYPE type; \
typedef std::true_type is_defined; \
enum member_count_enum { \
local_member_count = BOOST_PP_SEQ_SIZE(MEMBERS), \
total_member_count = local_member_count BOOST_PP_SEQ_FOR_EACH( FC_REFLECT_BASE_MEMBER_COUNT, +, INHERITS )\
}; \
template<typename Visitor> static void visit( const Visitor& v ); \
}; }
#define FC_REFLECT_DERIVED_IMPL( TYPE, MEMBERS ) \
FC_REFLECT_IMPL_DERIVED_EXT( TYPE, BOOST_PP_SEQ_NIL, MEMBERS )
#define FC_REFLECT_IMPL( TYPE, MEMBERS ) \
FC_REFLECT_DERIVED_IMPL_EXT( TYPE, BOOST_PP_SEQ_NIL, MEMBERS )

View file

@ -0,0 +1,262 @@
#pragma once
/**
* @file fc/reflect/typelist.hpp
*
* @brief Defines a template for manipulating and storing compile-time lists of types
*/
#include <type_traits>
#include <functional>
namespace fc {
/// This namespace contains the list type, and all of the operations and queries which can be performed upon it
namespace typelist {
// Forward declare the list so impl can see it
template<typename...> struct list;
namespace impl {
using typelist::list;
template<typename, template<typename...> class> struct apply;
template<typename... Ts, template<typename...> class Delegate>
struct apply<list<Ts...>, Delegate> { using type = Delegate<Ts...>; };
template<typename... Ts>
struct length;
template<> struct length<> { constexpr static std::size_t value = 0; };
template<typename T, typename... Ts>
struct length<T, Ts...> { constexpr static std::size_t value = length<Ts...>::value+1; };
template<typename...> struct concat;
template<typename... OldTypes, typename... NewTypes>
struct concat<list<OldTypes...>, list<NewTypes...>> {
using type = list<OldTypes..., NewTypes...>;
};
template<typename... OldTypes, typename... NewTypes, typename NextList, typename... Lists>
struct concat<list<OldTypes...>, list<NewTypes...>, NextList, Lists...> {
using type = typename concat<list<OldTypes..., NewTypes...>, NextList, Lists...>::type;
};
template<std::size_t count> struct make_sequence;
template<> struct make_sequence<0> { using type = list<>; };
template<> struct make_sequence<1> { using type = list<std::integral_constant<std::size_t, 0>>; };
template<std::size_t count>
struct make_sequence {
using type = typename concat<typename make_sequence<count-1>::type,
list<std::integral_constant<std::size_t, count-1>>>::type;
};
template<typename, typename> struct transform;
template<typename... List, typename Transformer>
struct transform<list<List...>, Transformer> {
using type = list<typename Transformer::template transform<List>::type...>;
};
template<typename Search, typename List> struct index_of;
template<typename Search> struct index_of<Search, list<>> { constexpr static int value = -1; };
template<typename Search, typename T, typename... Ts>
struct index_of<Search, list<T, Ts...>> {
constexpr static int deeper = index_of<Search, list<Ts...>>::value;
constexpr static int value = std::is_same<Search, T>::value? 0 : (deeper == -1? -1 : deeper + 1);
};
template<typename...> struct concat_unique;
template<typename... Uniques>
struct concat_unique<list<Uniques...>, list<>> {
using type = list<Uniques...>;
};
template<typename... Uniques, typename T>
struct concat_unique<list<Uniques...>, list<T>> {
using type = std::conditional_t<index_of<T, list<Uniques...>>::value >= 0,
list<Uniques...>, list<Uniques..., T>>;
};
template<typename... Uniques, typename T1, typename T2, typename... Types>
struct concat_unique<list<Uniques...>, list<T1, T2, Types...>> {
using type = typename concat_unique<
typename concat_unique<list<Uniques...>, list<T1>>::type, list<T2, Types...>>::type;
};
template<typename... Uniques, typename... Lists>
struct concat_unique<list<Uniques...>, list<>, Lists...> {
using type = typename concat_unique<list<Uniques...>, Lists...>::type;
};
template<typename Uniques, typename L1a, typename... L1s, typename L2, typename... Lists>
struct concat_unique<Uniques, list<L1a, L1s...>, L2, Lists...> {
using type = typename concat_unique<typename concat_unique<Uniques, list<L1a, L1s...>>::type, L2, Lists...>::type;
};
template<typename, std::size_t> struct at;
template<typename T, typename... Types>
struct at<list<T, Types...>, 0> { using type = T; };
template<typename T, typename... Types, std::size_t index>
struct at<list<T, Types...>, index> : at<list<Types...>, index-1> {};
template<typename, typename, std::size_t> struct remove_at;
template<typename... Left, typename T, typename... Right>
struct remove_at<list<Left...>, list<T, Right...>, 0> { using type = list<Left..., Right...>; };
template<typename... Left, typename T, typename... Right, std::size_t index>
struct remove_at<list<Left...>, list<T, Right...>, index> {
using type = typename remove_at<list<Left..., T>, list<Right...>, index-1>::type;
};
template<template<typename> class Filter, typename Filtered, typename List> struct filter;
template<template<typename> class Filter, typename... Filtered>
struct filter<Filter, list<Filtered...>, list<>> { using type = list<Filtered...>; };
template<template<typename> class Filter, typename... Filtered, typename T1, typename... Types>
struct filter<Filter, list<Filtered...>, list<T1, Types...>> {
using type = typename std::conditional_t<Filter<T1>::value,
filter<Filter, list<Filtered..., T1>, list<Types...>>,
filter<Filter, list<Filtered...>, list<Types...>>>::type;
};
template<typename, typename, std::size_t, std::size_t, typename = void> struct slice;
template<typename... Results, typename... Types, std::size_t index>
struct slice<list<Results...>, list<Types...>, index, index, void> { using type = list<Results...>; };
template<typename... Results, typename T, typename... Types, std::size_t end>
struct slice<list<Results...>, list<T, Types...>, 0, end, std::enable_if_t<end != 0>>
: slice<list<Results..., T>, list<Types...>, 0, end-1> {};
template<typename T, typename... Types, std::size_t start, std::size_t end>
struct slice<list<>, list<T, Types...>, start, end, std::enable_if_t<start != 0>>
: slice<list<>, list<Types...>, start-1, end-1> {};
template<typename, typename> struct zip;
template<>
struct zip<list<>, list<>> { using type = list<>; };
template<typename A, typename... As, typename B, typename... Bs>
struct zip<list<A, As...>, list<B, Bs...>> {
using type = typename concat<list<list<A, B>>, typename zip<list<As...>, list<Bs...>>::type>::type;
};
template<typename Callable, typename Ret, typename T>
Ret dispatch_helper(Callable& c) { return c(T()); }
} // namespace impl
/// The actual list type
template<typename... Types>
struct list { using type = list; };
/// Apply a list of types as arguments to another template
template<typename List, template<typename...> class Delegate>
using apply = typename impl::apply<List, Delegate>::type;
/// Get the number of types in a list
template<typename List>
constexpr static std::size_t length() { return apply<List, impl::length>::value; }
/// Concatenate two or more typelists together
template<typename... Lists>
using concat = typename impl::concat<Lists...>::type;
/// Create a list of sequential integers ranging from [0, count)
template<std::size_t count>
using make_sequence = typename impl::make_sequence<count>::type;
/// Template to build typelists using the following syntax:
/// builder<>::type::add<T1>::add<T2>::add<T3>[...]::finalize
/// Or:
/// builder<>::type::add_list<list<T1, T2>>::add_list<T3, T4>>[...]::finalize
template<typename List = list<>>
struct builder {
template<typename NewType> using add = typename builder<typename impl::concat<List, list<NewType>>::type>::type;
template<typename NewList> using add_list = typename builder<typename impl::concat<List, NewList>::type>::type;
using type = builder;
using finalize = List;
};
/// Transform elements of a typelist
template<typename List, typename Transformer>
using transform = typename impl::transform<List, Transformer>::type;
/// Get the index of the given type within a list, or -1 if type is not found
template<typename List, typename T>
constexpr static int index_of() { return impl::index_of<T, List>::value; }
/// Check if a given type is in a list
template<typename List, typename T>
constexpr static bool contains() { return impl::index_of<T, List>::value != -1; }
/// Remove duplicate items from one or more typelists and concatenate them all together
template<typename... TypeLists>
using concat_unique = typename impl::concat_unique<list<>, TypeLists...>::type;
/// Get the type at the specified list index
template<typename List, std::size_t index>
using at = typename impl::at<List, index>::type;
/// Get the type at the beginning of the list
template<typename List>
using first = at<List, 0>;
/// Get the type at the end of the list
template<typename List>
using last = at<List, length<List>()-1>;
/// Get the list with the element at the given index removed
template<typename List, std::size_t index>
using remove_at = typename impl::remove_at<list<>, List, index>::type;
/// Get the list with the given type removed
template<typename List, typename Remove>
using remove_element = remove_at<List, index_of<List, Remove>()>;
/// Get a list with all elements that do not pass a filter removed
template<typename List, template<typename> class Filter>
using filter = typename impl::filter<Filter, list<>, List>::type;
/// Template to invert a filter, i.e. filter<mylist, filter_inverter<myfilter>::type>
template<template<typename> class Filter>
struct invert_filter {
template<typename T>
struct type { constexpr static bool value = !Filter<T>::value; };
};
/// Take the sublist at indexes [start, end)
template<typename List, std::size_t start, std::size_t end = length<List>()>
using slice = typename impl::slice<list<>, List, start, end>::type;
/// Zip two equal-length typelists together, i.e. zip<list<X, Y>, list<A, B>> == list<list<X, A>, list<Y, B>>
template<typename ListA, typename ListB>
using zip = typename impl::zip<ListA, ListB>::type;
/// Add indexes to types in the list, i.e. index<list<A, B, C>> == list<list<0, A>, list<1, B>, list<2, C>> where
/// 0, 1, and 2 are std::integral_constants of type std::size_t
template<typename List>
using index = typename impl::zip<typename impl::make_sequence<length<List>()>::type, List>::type;
/// This namespace contains some utilities that provide runtime operations on typelists
namespace runtime {
/// Type wrapper object allowing arbitrary types to be passed to functions as information rather than data
template<typename T> struct wrapper { using type = T; };
/**
* @brief Index into the typelist for a type T, and invoke the callable with an argument wrapper<T>()
* @param index Index of the type in the typelist to invoke the callable with
* @param c The callable to invoke
* @return The value returned by the callable
* @note The callable return type must be the same for all list elements
*
* If index is out of bounds, throws std::out_of_range exception
*/
template<typename... Types, typename Callable, typename = std::enable_if_t<impl::length<Types...>::value != 0>,
typename Return = decltype(std::declval<Callable>()(wrapper<at<list<Types...>, 0>>()))>
Return dispatch(list<Types...>, std::size_t index, Callable c) {
static std::function<Return(Callable&)> call_table[] =
{ impl::dispatch_helper<Callable, Return, wrapper<Types>>... };
if (index < impl::length<Types...>::value) return call_table[index](c);
throw std::out_of_range("Invalid index to fc::typelist::runtime::dispatch()");
}
template<typename List, typename Callable>
auto dispatch(List l, int64_t index, Callable c) {
if (index < 0) throw std::out_of_range("Negative index to fc::typelist::runtime::dispatch()");
return dispatch(l, std::size_t(index), std::move(c));
}
/// @brief Invoke the provided callable with an argument wrapper<Type>() for each type in the list
template<typename... Types, typename Callable>
void for_each(list<Types...>, Callable c) {
bool trues[] = { [](Callable& c, auto t) { c(t); return true; }(c, wrapper<Types>())... };
(void)(trues);
}
} } } // namespace fc::typelist::runtime

View file

@ -112,6 +112,22 @@ namespace fc {
return _name.c_str();
}
};
template<typename T> struct get_typename< const T* >
{
static const char* name()
{
static std::string n = std::string("const ") + get_typename<T>::name() + "*";
return n.c_str();
}
};
template<typename T> struct get_typename< T* >
{
static const char* name()
{
static std::string n = std::string(get_typename<T>::name()) + "*";
return n.c_str();
}
};
struct unsigned_int;
class variant_object;

View file

@ -23,174 +23,6 @@ namespace fc {
// Implementation details, the user should not import this:
namespace impl {
template<int N, typename... Ts>
struct storage_ops;
template<typename X, typename... Ts>
struct position;
template<typename... Ts>
struct type_info;
template<typename StaticVariant>
struct copy_construct
{
typedef void result_type;
StaticVariant& sv;
copy_construct( StaticVariant& s ):sv(s){}
template<typename T>
void operator()( const T& v )const
{
sv.init(v);
}
};
template<typename StaticVariant>
struct move_construct
{
typedef void result_type;
StaticVariant& sv;
move_construct( StaticVariant& s ):sv(s){}
template<typename T>
void operator()( T& v )const
{
sv.init( std::move(v) );
}
};
template<int N, typename T, typename... Ts>
struct storage_ops<N, T&, Ts...> {
static void del(int n, void *data) {}
static void con(int n, void *data) {}
template<typename visitor>
static typename visitor::result_type apply(int n, void *data, visitor& v) {}
template<typename visitor>
static typename visitor::result_type apply(int n, void *data, const visitor& v) {}
template<typename visitor>
static typename visitor::result_type apply(int n, const void *data, visitor& v) {}
template<typename visitor>
static typename visitor::result_type apply(int n, const void *data, const visitor& v) {}
};
template<int N, typename T, typename... Ts>
struct storage_ops<N, T, Ts...> {
static void del(int n, void *data) {
if(n == N) reinterpret_cast<T*>(data)->~T();
else storage_ops<N + 1, Ts...>::del(n, data);
}
static void con(int n, void *data) {
if(n == N) new(reinterpret_cast<T*>(data)) T();
else storage_ops<N + 1, Ts...>::con(n, data);
}
template<typename visitor>
static typename visitor::result_type apply(int n, void *data, visitor& v) {
if(n == N) return v(*reinterpret_cast<T*>(data));
else return storage_ops<N + 1, Ts...>::apply(n, data, v);
}
template<typename visitor>
static typename visitor::result_type apply(int n, void *data, const visitor& v) {
if(n == N) return v(*reinterpret_cast<T*>(data));
else return storage_ops<N + 1, Ts...>::apply(n, data, v);
}
template<typename visitor>
static typename visitor::result_type apply(int n, const void *data, visitor& v) {
if(n == N) return v(*reinterpret_cast<const T*>(data));
else return storage_ops<N + 1, Ts...>::apply(n, data, v);
}
template<typename visitor>
static typename visitor::result_type apply(int n, const void *data, const visitor& v) {
if(n == N) return v(*reinterpret_cast<const T*>(data));
else return storage_ops<N + 1, Ts...>::apply(n, data, v);
}
};
template<int N>
struct storage_ops<N> {
static void del(int n, void *data) {
FC_THROW_EXCEPTION( fc::assert_exception, "Internal error: static_variant tag is invalid.");
}
static void con(int n, void *data) {
FC_THROW_EXCEPTION( fc::assert_exception, "Internal error: static_variant tag is invalid." );
}
template<typename visitor>
static typename visitor::result_type apply(int n, void *data, visitor& v) {
FC_THROW_EXCEPTION( fc::assert_exception, "Internal error: static_variant tag is invalid." );
}
template<typename visitor>
static typename visitor::result_type apply(int n, void *data, const visitor& v) {
FC_THROW_EXCEPTION( fc::assert_exception, "Internal error: static_variant tag is invalid." );
}
template<typename visitor>
static typename visitor::result_type apply(int n, const void *data, visitor& v) {
FC_THROW_EXCEPTION( fc::assert_exception, "Internal error: static_variant tag is invalid." );
}
template<typename visitor>
static typename visitor::result_type apply(int n, const void *data, const visitor& v) {
FC_THROW_EXCEPTION( fc::assert_exception, "Internal error: static_variant tag is invalid." );
}
};
template<typename X>
struct position<X> {
static constexpr int pos = -1;
};
template<typename X, typename... Ts>
struct position<X, X, Ts...> {
static constexpr int pos = 0;
};
template<typename X, typename T, typename... Ts>
struct position<X, T, Ts...> {
static constexpr int pos = position<X, Ts...>::pos != -1 ? position<X, Ts...>::pos + 1 : -1;
};
template<typename T, typename... Ts>
struct type_info<T&, Ts...> {
static constexpr bool no_reference_types = false;
static constexpr bool no_duplicates = position<T, Ts...>::pos == -1 && type_info<Ts...>::no_duplicates;
static constexpr size_t size = type_info<Ts...>::size > sizeof(T&) ? type_info<Ts...>::size : sizeof(T&);
static constexpr size_t count = 1 + type_info<Ts...>::count;
};
template<typename T, typename... Ts>
struct type_info<T, Ts...> {
static constexpr bool no_reference_types = type_info<Ts...>::no_reference_types;
static constexpr bool no_duplicates = position<T, Ts...>::pos == -1 && type_info<Ts...>::no_duplicates;
static constexpr size_t size = type_info<Ts...>::size > sizeof(T) ? type_info<Ts...>::size : sizeof(T&);
static constexpr size_t count = 1 + type_info<Ts...>::count;
};
template<>
struct type_info<> {
static constexpr bool no_reference_types = true;
static constexpr bool no_duplicates = true;
static constexpr size_t count = 0;
static constexpr size_t size = 0;
};
template<typename TTag>
constexpr size_t size( TTag )
{
return 0;
}
template<typename TTag, typename A, typename...Ts>
constexpr size_t size( TTag tag )
{
return tag <= 0 ? sizeof(A) : size<TTag, Ts...>( --tag );
}
class dynamic_storage
{
char* storage;
@ -206,71 +38,36 @@ public:
void release();
};
} // namespace impl
template<int L,typename Visitor,typename Data>
static const std::array<typename Visitor::result_type(*)(Visitor&,Data),L>
init_wrappers( Visitor& v, Data d, typename Visitor::result_type(**funcs)(Visitor&,Data) = 0)
{
return std::array<typename Visitor::result_type(*)(Visitor&,Data),L>();
}
template<int L,typename Visitor,typename Data,typename T, typename ... Types>
static const std::array<typename Visitor::result_type(*)(Visitor&,Data),L>
init_wrappers( Visitor& v, Data d, typename Visitor::result_type(**funcs)(Visitor&,Data) = 0 )
{
std::array<typename Visitor::result_type(*)(Visitor&,Data),L> result{};
if( !funcs ) funcs = result.data();
*funcs++ = [] ( Visitor& v, Data d ) { return v( *reinterpret_cast<T*>( d ) ); };
init_wrappers<L,Visitor,Data,Types...>( v, d, funcs );
return result;
}
template<int L,typename Visitor,typename Data>
static const std::array<typename Visitor::result_type(*)(Visitor&,Data),L>
init_const_wrappers( Visitor& v, Data d, typename Visitor::result_type(**funcs)(Visitor&,Data) = 0 )
{
return std::array<typename Visitor::result_type(*)(Visitor&,Data),L>();
}
template<int L,typename Visitor,typename Data,typename T, typename ... Types>
static const std::array<typename Visitor::result_type(*)(Visitor&,Data),L>
init_const_wrappers( Visitor& v, Data d, typename Visitor::result_type(**funcs)(Visitor&,Data) = 0 )
{
std::array<typename Visitor::result_type(*)(Visitor&,Data),L> result{};
if( !funcs ) funcs = result.data();
*funcs++ = [] ( Visitor& v, Data d ) { return v( *reinterpret_cast<const T*>( d ) ); };
init_const_wrappers<L,Visitor,Data,Types...>( v, d, funcs );
return result;
}
template<typename... Types>
class static_variant {
public:
using tag_type = int64_t;
using list = typelist::list<Types...>;
protected:
static_assert(impl::type_info<Types...>::no_reference_types, "Reference types are not permitted in static_variant.");
static_assert(impl::type_info<Types...>::no_duplicates, "static_variant type arguments contain duplicate types.");
static_assert(typelist::length<typelist::filter<list, std::is_reference>>() == 0,
"Reference types are not permitted in static_variant.");
static_assert(typelist::length<typelist::concat_unique<list>>() == typelist::length<list>(),
"static_variant type arguments contain duplicate types.");
template<typename X>
using type_in_typelist = typename std::enable_if<impl::position<X, Types...>::pos != -1, X>::type; // type is in typelist of static_variant.
using type_in_typelist = std::enable_if_t<typelist::index_of<list, X>() != -1>;
tag_type _tag;
impl::dynamic_storage storage;
template<typename X, typename = type_in_typelist<X>>
void init(const X& x) {
_tag = impl::position<X, Types...>::pos;
_tag = typelist::index_of<list, X>();
storage.alloc( sizeof(X) );
new(storage.data()) X(x);
}
template<typename X, typename = type_in_typelist<X>>
void init(X&& x) {
_tag = impl::position<X, Types...>::pos;
_tag = typelist::index_of<list, X>();
storage.alloc( sizeof(X) );
new(storage.data()) X( std::move(x) );
}
@ -280,26 +77,48 @@ protected:
FC_ASSERT( tag >= 0 );
FC_ASSERT( tag < count() );
_tag = tag;
storage.alloc( impl::size<tag_type, Types...>( tag ) );
impl::storage_ops<0, Types...>::con(_tag, storage.data());
typelist::runtime::dispatch(list(), tag, [this](auto t) {
using T = typename decltype(t)::type;
storage.alloc(sizeof(T));
new(reinterpret_cast<T*>(storage.data())) T();
});
}
void clean()
{
impl::storage_ops<0, Types...>::del(_tag, storage.data() );
typelist::runtime::dispatch(list(), _tag, [data=storage.data()](auto t) {
using T = typename decltype(t)::type;
reinterpret_cast<T*>(data)->~T();
});
storage.release();
}
template<typename T, typename = void>
struct import_helper {
static static_variant construct(const T&) {
FC_THROW_EXCEPTION(assert_exception, "Cannot import unsupported type ${T} into static_variant",
("T", get_typename<T>::name()));
}
static static_variant construct(T&&) {
FC_THROW_EXCEPTION(assert_exception, "Cannot import unsupported type ${T} into static_variant",
("T", get_typename<T>::name()));
}
};
template<typename T>
struct import_helper<T, type_in_typelist<T>> {
static static_variant construct(const T& t) {
return static_variant(t);
}
static static_variant construct(T&& t) {
return static_variant(std::move(t));
}
};
template<typename StaticVariant>
friend struct impl::copy_construct;
template<typename StaticVariant>
friend struct impl::move_construct;
public:
template<typename X, typename = type_in_typelist<X>>
struct tag
{
static constexpr int value = impl::position<X, Types...>::pos;
static constexpr int value = typelist::index_of<list, X>();
};
struct type_lt {
@ -310,6 +129,25 @@ public:
};
using flat_set_type = flat_set<static_variant, type_lt>;
/// Import the value from a foreign static_variant with types not in this one, and throw if the value is an
/// incompatible type
template<typename... Other>
static static_variant import_from(const static_variant<Other...>& other) {
return typelist::runtime::dispatch(typelist::list<Other...>(), other.which(), [&other](auto t) {
using other_type = typename decltype(t)::type;
return import_helper<other_type>::construct(other.template get<other_type>());
});
}
/// Import the value from a foreign static_variant with types not in this one, and throw if the value is an
/// incompatible type
template<typename... Other>
static static_variant import_from(static_variant<Other...>&& other) {
return typelist::runtime::dispatch(typelist::list<Other...>(), other.which(), [&other](auto t) {
using other_type = typename decltype(t)::type;
return import_helper<other_type>::construct(std::move(other.template get<other_type>()));
});
}
static_variant()
{
init_from_tag(0);
@ -318,23 +156,41 @@ public:
template<typename... Other>
static_variant( const static_variant<Other...>& cpy )
{
cpy.visit( impl::copy_construct<static_variant>(*this) );
typelist::runtime::dispatch(typelist::list<Other...>(), cpy.which(), [this, &cpy](auto t) mutable {
this->init(cpy.template get<typename decltype(t)::type>());
});
}
static_variant( const static_variant& cpy )
{
cpy.visit( impl::copy_construct<static_variant>(*this) );
typelist::runtime::dispatch(list(), cpy.which(), [this, &cpy](auto t) mutable {
this->init(cpy.template get<typename decltype(t)::type>());
});
}
static_variant( static_variant&& mv )
{
mv.visit( impl::move_construct<static_variant>(*this) );
typelist::runtime::dispatch(list(), mv.which(), [this, &mv](auto t) mutable {
this->init(std::move(mv.template get<typename decltype(t)::type>()));
});
}
template<typename... Other>
static_variant( static_variant<Other...>&& mv )
{
typelist::runtime::dispatch(typelist::list<Other...>(), mv.which(), [this, &mv](auto t) mutable {
this->init(std::move(mv.template get<typename decltype(t)::type>()));
});
}
template<typename X, typename = type_in_typelist<X>>
static_variant(const X& v) {
init(v);
}
template<typename X, typename = type_in_typelist<X>>
static_variant(X&& v) {
init(std::move(v));
}
~static_variant() {
clean();
@ -350,20 +206,32 @@ public:
{
if( this == &v ) return *this;
clean();
v.visit( impl::copy_construct<static_variant>(*this) );
typelist::runtime::dispatch(list(), v.which(), [this, &v](auto t)mutable {
this->init(v.template get<typename decltype(t)::type>());
});
return *this;
}
static_variant& operator=( static_variant&& v )
{
if( this == &v ) return *this;
clean();
v.visit( impl::move_construct<static_variant>(*this) );
typelist::runtime::dispatch(list(), v.which(), [this, &v](auto t)mutable {
this->init(std::move(v.template get<typename decltype(t)::type>()));
});
return *this;
}
friend bool operator==( const static_variant& a, const static_variant& b ) {
if (a.which() != b.which())
return false;
return typelist::runtime::dispatch(list(), a.which(), [&a, &b](auto t) {
return a.get<typename decltype(t)::type>() == b.get<typename decltype(t)::type>();
});
}
template<typename X, typename = type_in_typelist<X>>
X& get() {
if(_tag == impl::position<X, Types...>::pos) {
if(_tag == typelist::index_of<list, X>()) {
return *reinterpret_cast<X*>(storage.data());
} else {
FC_THROW_EXCEPTION( fc::assert_exception, "static_variant does not contain a value of type ${t}", ("t",fc::get_typename<X>::name()) );
@ -371,7 +239,7 @@ public:
}
template<typename X, typename = type_in_typelist<X>>
const X& get() const {
if(_tag == impl::position<X, Types...>::pos) {
if(_tag == typelist::index_of<list, X>()) {
return *reinterpret_cast<const X*>(storage.data());
} else {
FC_THROW_EXCEPTION( fc::assert_exception, "static_variant does not contain a value of type ${t}", ("t",fc::get_typename<X>::name()) );
@ -400,36 +268,40 @@ public:
template<typename visitor>
static typename visitor::result_type visit( tag_type tag, visitor& v, void* data )
{
static const auto wrappers = init_wrappers<impl::type_info<Types...>::count,visitor,void*,Types...>( v, data );
FC_ASSERT( tag >= 0 && tag < count(), "Unsupported type ${tag}!", ("tag",tag) );
return wrappers[tag]( v, data );
return typelist::runtime::dispatch(list(), tag, [&v, data](auto t) {
return v(*reinterpret_cast<typename decltype(t)::type*>(data));
});
}
template<typename visitor>
static typename visitor::result_type visit( tag_type tag, const visitor& v, void* data )
{
static const auto wrappers = init_wrappers<impl::type_info<Types...>::count,const visitor,void*,Types...>( v, data );
FC_ASSERT( tag >= 0 && tag < count(), "Unsupported type ${tag}!", ("tag",tag) );
return wrappers[tag]( v, data );
return typelist::runtime::dispatch(list(), tag, [&v, data](auto t) {
return v(*reinterpret_cast<typename decltype(t)::type*>(data));
});
}
template<typename visitor>
static typename visitor::result_type visit( tag_type tag, visitor& v, const void* data )
{
static const auto wrappers = init_const_wrappers<impl::type_info<Types...>::count,visitor,const void*,Types...>( v, data );
FC_ASSERT( tag >= 0 && tag < count(), "Unsupported type ${tag}!", ("tag",tag) );
return wrappers[tag]( v, data );
return typelist::runtime::dispatch(list(), tag, [&v, data](auto t) {
return v(*reinterpret_cast<const typename decltype(t)::type*>(data));
});
}
template<typename visitor>
static typename visitor::result_type visit( tag_type tag, const visitor& v, const void* data )
{
static const auto wrappers = init_const_wrappers<impl::type_info<Types...>::count,const visitor,const void*,Types...>( v, data );
FC_ASSERT( tag >= 0 && tag < count(), "Unsupported type ${tag}!", ("tag",tag) );
return wrappers[tag]( v, data );
return typelist::runtime::dispatch(list(), tag, [&v, data](auto t) {
return v(*reinterpret_cast<const typename decltype(t)::type*>(data));
});
}
static constexpr int count() { return impl::type_info<Types...>::count; }
static constexpr int count() { return typelist::length<list>(); }
void set_which( tag_type w ) {
FC_ASSERT( w >= 0 );
FC_ASSERT( w < count() );
@ -442,6 +314,12 @@ public:
template<typename T>
bool is_type() const { return _tag == tag<T>::value; }
};
template<> class static_variant<> {
public:
using tag_type = int64_t;
static_variant() { FC_THROW_EXCEPTION(assert_exception, "Cannot create static_variant with no types"); }
};
template<typename... Types> class static_variant<typelist::list<Types...>> : public static_variant<Types...> {};
struct from_static_variant
{

View file

@ -41,6 +41,7 @@ add_executable( all_tests all_tests.cpp
thread/thread_tests.cpp
thread/parallel_tests.cpp
bloom_test.cpp
reflection_tests.cpp
serialization_test.cpp
stacktrace_test.cpp
time_test.cpp

126
tests/reflection_tests.cpp Normal file
View file

@ -0,0 +1,126 @@
#include <boost/test/unit_test.hpp>
#include <fc/exception/exception.hpp>
#include <type_traits>
struct reflect_test_base {
int x = 1;
char y = 'a';
};
struct reflect_test_derived : reflect_test_base {
double z = 3.14;
};
struct reflect_layer_1 { reflect_test_base b; int32_t n; };
struct reflect_layer_2 { reflect_layer_1 l1; reflect_test_derived d; };
struct reflect_layer_3 { reflect_layer_2 l2; int32_t i; };
FC_REFLECT( reflect_test_base, (x)(y) );
FC_REFLECT_DERIVED( reflect_test_derived, (reflect_test_base), (z) );
FC_REFLECT( reflect_layer_1, (b)(n) );
FC_REFLECT( reflect_layer_2, (l1)(d) );
FC_REFLECT( reflect_layer_3, (l2)(i) );
BOOST_AUTO_TEST_SUITE( fc_reflection )
BOOST_AUTO_TEST_CASE( reflection_static_tests )
{
// These are all compile-time tests, nothing actually happens here at runtime
using base_reflection = fc::reflector<reflect_test_base>;
using derived_reflection = fc::reflector<reflect_test_derived>;
static_assert(fc::typelist::length<base_reflection::members>() == 2, "");
static_assert(fc::typelist::length<derived_reflection::members>() == 3, "");
static_assert(fc::typelist::at<derived_reflection::members, 0>::is_derived, "");
static_assert(std::is_same<fc::typelist::at<derived_reflection::members, 0>::field_container,
reflect_test_base>::value, "");
static_assert(fc::typelist::at<derived_reflection::members, 1>::is_derived, "");
static_assert(std::is_same<fc::typelist::at<derived_reflection::members, 1>::field_container,
reflect_test_base>::value, "");
static_assert(fc::typelist::at<derived_reflection::members, 2>::is_derived == false, "");
static_assert(std::is_same<fc::typelist::slice<fc::typelist::list<int, bool, char>, 0, 1>,
fc::typelist::list<int>>::value, "");
static_assert(std::is_same<fc::typelist::slice<fc::typelist::list<int, bool, char>, 0, 2>,
fc::typelist::list<int, bool>>::value, "");
static_assert(std::is_same<fc::typelist::slice<fc::typelist::list<int, bool, char>, 0, 3>,
fc::typelist::list<int, bool, char>>::value, "");
static_assert(std::is_same<fc::typelist::slice<fc::typelist::list<int, bool, char>, 1, 3>,
fc::typelist::list<bool, char>>::value, "");
static_assert(std::is_same<fc::typelist::slice<fc::typelist::list<int, bool, char>, 2, 3>,
fc::typelist::list<char>>::value, "");
static_assert(std::is_same<fc::typelist::slice<fc::typelist::list<int, bool, char>, 1, 2>,
fc::typelist::list<bool>>::value, "");
static_assert(std::is_same<fc::typelist::slice<fc::typelist::list<int, bool, char>, 1>,
fc::typelist::list<bool, char>>::value, "");
static_assert(std::is_same<fc::typelist::make_sequence<0>, fc::typelist::list<>>::value, "");
static_assert(std::is_same<fc::typelist::make_sequence<1>,
fc::typelist::list<std::integral_constant<size_t, 0>>>::value, "");
static_assert(std::is_same<fc::typelist::make_sequence<2>,
fc::typelist::list<std::integral_constant<size_t, 0>,
std::integral_constant<size_t, 1>>>::value, "");
static_assert(std::is_same<fc::typelist::make_sequence<3>,
fc::typelist::list<std::integral_constant<size_t, 0>,
std::integral_constant<size_t, 1>,
std::integral_constant<size_t, 2>>>::value, "");
static_assert(std::is_same<fc::typelist::zip<fc::typelist::list<>, fc::typelist::list<>>,
fc::typelist::list<>>::value, "");
static_assert(std::is_same<fc::typelist::zip<fc::typelist::list<bool>, fc::typelist::list<char>>,
fc::typelist::list<fc::typelist::list<bool, char>>>::value, "");
static_assert(std::is_same<fc::typelist::zip<fc::typelist::list<int, bool>, fc::typelist::list<char, double>>,
fc::typelist::list<fc::typelist::list<int, char>,
fc::typelist::list<bool, double>>>::value, "");
static_assert(std::is_same<fc::typelist::index<fc::typelist::list<>>, fc::typelist::list<>>::value, "");
static_assert(std::is_same<fc::typelist::index<fc::typelist::list<int, bool, char, double>>,
fc::typelist::list<fc::typelist::list<std::integral_constant<size_t, 0>, int>,
fc::typelist::list<std::integral_constant<size_t, 1>, bool>,
fc::typelist::list<std::integral_constant<size_t, 2>, char>,
fc::typelist::list<std::integral_constant<size_t, 3>, double>>
>::value, "");
}
BOOST_AUTO_TEST_CASE( typelist_dispatch_test )
{
using list = fc::typelist::list<float, bool, char>;
auto get_name = [](auto t) -> std::string { return fc::get_typename<typename decltype(t)::type>::name(); };
BOOST_CHECK_EQUAL(fc::typelist::runtime::dispatch(list(), 0ul, get_name), "float");
BOOST_CHECK_EQUAL(fc::typelist::runtime::dispatch(list(), 1ul, get_name), "bool");
BOOST_CHECK_EQUAL(fc::typelist::runtime::dispatch(list(), 2ul, get_name), "char");
}
// Helper template to use fc::typelist::at without a comma, for macro friendliness
template<typename T> struct index_from { template<std::size_t idx> using at = fc::typelist::at<T, idx>; };
BOOST_AUTO_TEST_CASE( reflection_get_test )
{ try {
reflect_test_derived derived;
reflect_test_base& base = derived;
using base_reflector = fc::reflector<reflect_test_base>;
using derived_reflector = fc::reflector<reflect_test_derived>;
BOOST_CHECK(index_from<base_reflector::members>::at<0>::get(base) == 1);
BOOST_CHECK(index_from<base_reflector::members>::at<1>::get(base) == 'a');
fc::typelist::at<base_reflector::members, 0>::get(base) = 5;
fc::typelist::at<base_reflector::members, 1>::get(base) = 'q';
BOOST_CHECK(index_from<base_reflector::members>::at<0>::get(base) == 5);
BOOST_CHECK(index_from<base_reflector::members>::at<1>::get(base) == 'q');
BOOST_CHECK(index_from<derived_reflector::members>::at<0>::get(derived) == 5);
BOOST_CHECK(index_from<derived_reflector::members>::at<1>::get(derived) == 'q');
BOOST_CHECK(index_from<derived_reflector::members>::at<2>::get(derived) == 3.14);
fc::typelist::at<derived_reflector::members, 1>::get(derived) = 'X';
BOOST_CHECK(index_from<base_reflector::members>::at<1>::get(base) == 'X');
reflect_layer_3 l3;
BOOST_CHECK(index_from<index_from<index_from<index_from<fc::reflector<reflect_layer_3>::members>::at<0>
::reflector::members>::at<0>::reflector::members>::at<0>::reflector::members>::at<1>::get(l3.l2.l1.b)
== 'a');
BOOST_CHECK(index_from<index_from<index_from<fc::reflector<reflect_layer_3>::members>::at<0>::reflector::members>
::at<1>::reflector::members>::at<1>::get(l3.l2.d) == 'a');
BOOST_CHECK(index_from<index_from<index_from<fc::reflector<reflect_layer_3>::members>::at<0>::reflector::members>
::at<1>::reflector::members>::at<2>::get(l3.l2.d) == 3.14);
} FC_CAPTURE_LOG_AND_RETHROW( (0) ) }
BOOST_AUTO_TEST_SUITE_END()

View file

@ -35,7 +35,6 @@ namespace fc { namespace test {
inline bool operator < ( const item& a, const item& b )
{ return ( std::tie( a.level, a.w ) < std::tie( b.level, b.w ) ); }
} } // namespace fc::test
FC_REFLECT( fc::test::item_wrapper, (v) );

View file

@ -182,10 +182,7 @@ BOOST_AUTO_TEST_CASE( nested_objects_test )
from_variant( v, sv1, nested_levels + 2 );
auto sv_equal = [](const fc::static_variant<fc::test::item>& v1, const fc::static_variant<fc::test::item>& v2) {
return v1.get<fc::test::item>() == v2.get<fc::test::item>();
};
BOOST_CHECK( sv_equal(sv, sv1) );
BOOST_CHECK( sv == sv1 );
// both log and dump should never throw
BOOST_TEST_MESSAGE( "========== About to log static_variant. ==========" );
@ -218,7 +215,7 @@ BOOST_AUTO_TEST_CASE( nested_objects_test )
from_variant( v, vec1, nested_levels + 3 );
BOOST_CHECK( std::equal(vec.begin(), vec.end(), vec1.begin(), sv_equal) );
BOOST_CHECK( vec == vec1 );
// both log and dump should never throw
BOOST_TEST_MESSAGE( "========== About to log vector. ==========" );