BitShares-Core  4.0.0
BitShares blockchain implementation and command-line interface software
static_variant.hpp
Go to the documentation of this file.
1 
12 #pragma once
13 
14 #include <array>
15 #include <functional>
16 #include <stdexcept>
17 #include <typeinfo>
18 
20 
21 namespace fc {
22 
23 // Implementation details, the user should not import this:
24 namespace impl {
25 
27 {
28  char* storage;
29 public:
31 
33 
34  void* data() const;
35 
36  void alloc( size_t size );
37 
38  void release();
39 };
40 
41 } // namespace impl
42 
43 template<typename... Types>
44 class static_variant {
45 public:
46  using tag_type = int64_t;
47  using list = typelist::list<Types...>;
48 
49 protected:
50  static_assert(typelist::length<typelist::filter<list, std::is_reference>>() == 0,
51  "Reference types are not permitted in static_variant.");
52  static_assert(typelist::length<typelist::concat_unique<list>>() == typelist::length<list>(),
53  "static_variant type arguments contain duplicate types.");
54 
55  template<typename X>
56  using type_in_typelist = std::enable_if_t<typelist::index_of<list, X>() != -1>;
57 
60 
61  template<typename X, typename = type_in_typelist<X>>
62  void init(const X& x) {
63  _tag = typelist::index_of<list, X>();
64  storage.alloc( sizeof(X) );
65  new(storage.data()) X(x);
66  }
67 
68  template<typename X, typename = type_in_typelist<X>>
69  void init(X&& x) {
70  _tag = typelist::index_of<list, X>();
71  storage.alloc( sizeof(X) );
72  new(storage.data()) X( std::move(x) );
73  }
74 
76  {
77  FC_ASSERT( tag >= 0 );
78  FC_ASSERT( static_cast<size_t>(tag) < count() );
79  _tag = tag;
80  typelist::runtime::dispatch(list(), tag, [this](auto t) {
81  using T = typename decltype(t)::type;
82  storage.alloc(sizeof(T));
83  new(reinterpret_cast<T*>(storage.data())) T();
84  });
85  }
86 
87  void clean()
88  {
89  typelist::runtime::dispatch(list(), _tag, [data=storage.data()](auto t) {
90  using T = typename decltype(t)::type;
91  reinterpret_cast<T*>(data)->~T();
92  });
93  storage.release();
94  }
95 
96  template<typename T, typename = void>
97  struct import_helper {
98  static static_variant construct(const T&) {
99  FC_THROW_EXCEPTION(assert_exception, "Cannot import unsupported type ${T} into static_variant",
100  ("T", get_typename<T>::name()));
101  }
102  static static_variant construct(T&&) {
103  FC_THROW_EXCEPTION(assert_exception, "Cannot import unsupported type ${T} into static_variant",
104  ("T", get_typename<T>::name()));
105  }
106  };
107  template<typename T>
109  static static_variant construct(const T& t) {
110  return static_variant(t);
111  }
112  static static_variant construct(T&& t) {
113  return static_variant(std::move(t));
114  }
115  };
116 
117 public:
118  template<typename X, typename = type_in_typelist<X>>
119  struct tag
120  {
121  static constexpr tag_type value = typelist::index_of<list, X>();
122  };
123 
124  struct type_lt {
125  bool operator()(const static_variant& a, const static_variant& b) const { return a.which() < b.which(); }
126  };
127  struct type_eq {
128  bool operator()(const static_variant& a, const static_variant& b) const { return a.which() == b.which(); }
129  };
130  using flat_set_type = flat_set<static_variant, type_lt>;
131 
134  template<typename... Other>
136  return typelist::runtime::dispatch(typelist::list<Other...>(), other.which(), [&other](auto t) {
137  using other_type = typename decltype(t)::type;
138  return import_helper<other_type>::construct(other.template get<other_type>());
139  });
140  }
143  template<typename... Other>
145  return typelist::runtime::dispatch(typelist::list<Other...>(), other.which(), [&other](auto t) {
146  using other_type = typename decltype(t)::type;
147  return import_helper<other_type>::construct(std::move(other.template get<other_type>()));
148  });
149  }
150 
152  {
153  init_from_tag(0);
154  }
155 
156  template<typename... Other>
158  {
159  typelist::runtime::dispatch(typelist::list<Other...>(), cpy.which(), [this, &cpy](auto t) mutable {
160  this->init(cpy.template get<typename decltype(t)::type>());
161  });
162  }
163 
165  {
166  typelist::runtime::dispatch(list(), cpy.which(), [this, &cpy](auto t) mutable {
167  this->init(cpy.template get<typename decltype(t)::type>());
168  });
169  }
170 
172  {
173  typelist::runtime::dispatch(list(), mv.which(), [this, &mv](auto t) mutable {
174  this->init(std::move(mv.template get<typename decltype(t)::type>()));
175  });
176  }
177 
178  template<typename... Other>
180  {
181  typelist::runtime::dispatch(typelist::list<Other...>(), mv.which(), [this, &mv](auto t) mutable {
182  this->init(std::move(mv.template get<typename decltype(t)::type>()));
183  });
184  }
185 
186  template<typename X, typename = type_in_typelist<X>>
187  static_variant(const X& v) {
188  init(v);
189  }
190  template<typename X, typename = type_in_typelist<X>>
191  static_variant(X&& v) {
192  init(std::move(v));
193  }
194 
196  clean();
197  }
198 
199  template<typename X, typename = type_in_typelist<X>>
200  static_variant& operator=(const X& v) {
201  clean();
202  init(v);
203  return *this;
204  }
206  {
207  if( this == &v ) return *this;
208  clean();
209  typelist::runtime::dispatch(list(), v.which(), [this, &v](auto t)mutable {
210  this->init(v.template get<typename decltype(t)::type>());
211  });
212  return *this;
213  }
215  {
216  if( this == &v ) return *this;
217  clean();
218  typelist::runtime::dispatch(list(), v.which(), [this, &v](auto t)mutable {
219  this->init(std::move(v.template get<typename decltype(t)::type>()));
220  });
221  return *this;
222  }
223 
224  friend bool operator==( const static_variant& a, const static_variant& b ) {
225  if (a.which() != b.which())
226  return false;
227  return typelist::runtime::dispatch(list(), a.which(), [&a, &b](auto t) {
228  using Value = typename decltype(t)::type;
229  return a.template get<Value>() == b.template get<Value>();
230  });
231  }
232 
233  template<typename X, typename = type_in_typelist<X>>
234  X& get() {
235  if(_tag == typelist::index_of<list, X>()) {
236  return *reinterpret_cast<X*>(storage.data());
237  } else {
238  FC_THROW_EXCEPTION( fc::assert_exception, "static_variant does not contain a value of type ${t}", ("t",fc::get_typename<X>::name()) );
239  }
240  }
241  template<typename X, typename = type_in_typelist<X>>
242  const X& get() const {
243  if(_tag == typelist::index_of<list, X>()) {
244  return *reinterpret_cast<const X*>(storage.data());
245  } else {
246  FC_THROW_EXCEPTION( fc::assert_exception, "static_variant does not contain a value of type ${t}", ("t",fc::get_typename<X>::name()) );
247  }
248  }
249  template<typename visitor>
250  typename visitor::result_type visit(visitor& v) {
251  return visit( _tag, v, (void*) storage.data() );
252  }
253 
254  template<typename visitor>
255  typename visitor::result_type visit(const visitor& v) {
256  return visit( _tag, v, (void*) storage.data() );
257  }
258 
259  template<typename visitor>
260  typename visitor::result_type visit(visitor& v)const {
261  return visit( _tag, v, (const void*) storage.data() );
262  }
263 
264  template<typename visitor>
265  typename visitor::result_type visit(const visitor& v)const {
266  return visit( _tag, v, (const void*) storage.data() );
267  }
268 
269  template<typename visitor>
270  static typename visitor::result_type visit( tag_type tag, visitor& v, void* data )
271  {
272  FC_ASSERT( tag >= 0 && static_cast<size_t>(tag) < count(), "Unsupported type ${tag}!", ("tag",tag) );
273  return typelist::runtime::dispatch(list(), tag, [&v, data](auto t) {
274  return v(*reinterpret_cast<typename decltype(t)::type*>(data));
275  });
276  }
277 
278  template<typename visitor>
279  static typename visitor::result_type visit( tag_type tag, const visitor& v, void* data )
280  {
281  FC_ASSERT( tag >= 0 && static_cast<size_t>(tag) < count(), "Unsupported type ${tag}!", ("tag",tag) );
282  return typelist::runtime::dispatch(list(), tag, [&v, data](auto t) {
283  return v(*reinterpret_cast<typename decltype(t)::type*>(data));
284  });
285  }
286 
287  template<typename visitor>
288  static typename visitor::result_type visit( tag_type tag, visitor& v, const void* data )
289  {
290  FC_ASSERT( tag >= 0 && static_cast<size_t>(tag) < count(), "Unsupported type ${tag}!", ("tag",tag) );
291  return typelist::runtime::dispatch(list(), tag, [&v, data](auto t) {
292  return v(*reinterpret_cast<const typename decltype(t)::type*>(data));
293  });
294  }
295 
296  template<typename visitor>
297  static typename visitor::result_type visit( tag_type tag, const visitor& v, const void* data )
298  {
299  FC_ASSERT( tag >= 0 && static_cast<size_t>(tag) < count(), "Unsupported type ${tag}!", ("tag",tag) );
300  return typelist::runtime::dispatch(list(), tag, [&v, data](auto t) {
301  return v(*reinterpret_cast<const typename decltype(t)::type*>(data));
302  });
303  }
304 
305  static constexpr size_t count() { return typelist::length<list>(); }
306  void set_which( tag_type tag ) {
307  FC_ASSERT( tag >= 0 );
308  FC_ASSERT( static_cast<size_t>(tag) < count() );
309  clean();
310  init_from_tag(tag);
311  }
312 
313  tag_type which() const {return _tag;}
314 
315  template<typename T>
316  bool is_type() const { return _tag == tag<T>::value; }
317 };
318 template<> class static_variant<> {
319 public:
320  using tag_type = int64_t;
321  static_variant() { FC_THROW_EXCEPTION(assert_exception, "Cannot create static_variant with no types"); }
322 };
323 template<typename... Types> class static_variant<typelist::list<Types...>> : public static_variant<Types...> {};
324 
326  {
328  const uint32_t _max_depth;
329  from_static_variant( variant& dv, uint32_t max_depth ):var(dv),_max_depth(max_depth){}
330 
331  typedef void result_type;
332  template<typename T> void operator()( const T& v )const
333  {
334  to_variant( v, var, _max_depth );
335  }
336  };
337 
339  {
340  const variant& var;
341  const uint32_t _max_depth;
342  to_static_variant( const variant& dv, uint32_t max_depth ):var(dv),_max_depth(max_depth){}
343 
344  typedef void result_type;
345  template<typename T> void operator()( T& v )const
346  {
347  from_variant( var, v, _max_depth );
348  }
349  };
350 
351 
352  template<typename... T> void to_variant( const fc::static_variant<T...>& s, fc::variant& v, uint32_t max_depth )
353  {
354  FC_ASSERT( max_depth > 0 );
355  variants vars(2);
356  vars[0] = s.which();
357  s.visit( from_static_variant(vars[1], max_depth - 1) );
358  v = std::move(vars);
359  }
360  template<typename... T> void from_variant( const fc::variant& v, fc::static_variant<T...>& s, uint32_t max_depth )
361  {
362  FC_ASSERT( max_depth > 0 );
363  auto ar = v.get_array();
364  if( ar.size() < 2 ) return;
365  s.set_which( ar[0].as_uint64() );
366  s.visit( to_static_variant(ar[1], max_depth - 1) );
367  }
368 
369  template< typename... T > struct get_comma_separated_typenames;
370 
371  template<>
373  {
374  static const char* names() { return ""; }
375  };
376 
377  template< typename T >
379  {
380  static const char* names()
381  {
382  static const std::string n = get_typename<T>::name();
383  return n.c_str();
384  }
385  };
386 
387  template< typename T, typename... Ts >
389  {
390  static const char* names()
391  {
392  static const std::string n =
393  std::string( get_typename<T>::name() )+","+
395  return n.c_str();
396  }
397  };
398 
399  template< typename... T >
400  struct get_typename< static_variant< T... > >
401  {
402  static const char* name()
403  {
404  static const std::string n = std::string( "fc::static_variant<" )
406  + ">";
407  return n.c_str();
408  }
409  };
410 
411 } // namespace fc
static static_variant construct(const T &)
bool is_type() const
void operator()(const T &v) const
static_variant(static_variant &&mv)
friend bool operator==(const static_variant &a, const static_variant &b)
void init(const X &x)
static static_variant import_from(const static_variant< Other... > &other)
void init_from_tag(tag_type tag)
void operator()(T &v) const
static_variant & operator=(const X &v)
static_variant(static_variant< Other... > &&mv)
to_static_variant(const variant &dv, uint32_t max_depth)
visitor::result_type visit(const visitor &v)
static static_variant import_from(static_variant< Other... > &&other)
std::vector< variant > variants
Definition: variant.hpp:170
static visitor::result_type visit(tag_type tag, const visitor &v, void *data)
static_variant(const X &v)
typename impl::concat_unique< list<>, TypeLists... >::type concat_unique
Remove duplicate items from one or more typelists and concatenate them all together.
Definition: typelist.hpp:182
visitor::result_type visit(visitor &v)
static constexpr size_t count()
tag_type which() const
static static_variant construct(T &&)
static visitor::result_type visit(tag_type tag, const visitor &v, const void *data)
void to_variant(const flat_set< T, A... > &var, variant &vo, uint32_t _max_depth)
Definition: flat.hpp:105
static visitor::result_type visit(tag_type tag, visitor &v, void *data)
static_variant(const static_variant &cpy)
from_static_variant(variant &dv, uint32_t max_depth)
visitor::result_type visit(visitor &v) const
This namespace contains the list type, and all of the operations and queries which can be performed u...
Definition: typelist.hpp:14
typename impl::filter< Filter, list<>, List >::type filter
Get a list with all elements that do not pass a filter removed.
Definition: typelist.hpp:205
#define FC_ASSERT(TEST,...)
Checks a condition and throws an assert_exception if the test is FALSE.
Definition: exception.hpp:345
stores null, int64, uint64, double, bool, string, std::vector<variant>, and variant_object&#39;s.
Definition: variant.hpp:198
#define FC_THROW_EXCEPTION(EXCEPTION, FORMAT,...)
Definition: exception.hpp:378
The actual list type.
Definition: typelist.hpp:17
Defines exception&#39;s used by fc.
visitor::result_type visit(const visitor &v) const
object_restriction_predicate< operation > result_type
Definition: list_1.cpp:29
variants & get_array()
Definition: variant.cpp:496
const uint32_t _max_depth
void from_variant(const variant &var, flat_set< T, A... > &vo, uint32_t _max_depth)
Definition: flat.hpp:116
bool operator()(const static_variant &a, const static_variant &b) const
Definition: api.hpp:15
void set_which(tag_type tag)
impl::dynamic_storage storage
static_variant & operator=(const static_variant &v)
static visitor::result_type visit(tag_type tag, visitor &v, const void *data)
static_variant(const static_variant< Other... > &cpy)
static_variant & operator=(static_variant &&v)
Return dispatch(list< Types... >, std::size_t index, Callable c)
Index into the typelist for a type T, and invoke the callable with an argument wrapper<T>() ...
Definition: typelist.hpp:243
bool operator()(const static_variant &a, const static_variant &b) const