BitShares-Core  7.0.2
BitShares blockchain node software and command-line wallet software
static_variant.hpp
Go to the documentation of this file.
1 /* This source is adapted from https://github.com/kmicklas/variadic-variant .
2  *
3  * Copyright (C) 2013 Kenneth Micklas
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6  *
7  * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
10  *
11  **/
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, "Unable to init with a negative tag '${tag}'", ("tag",tag) );
78  FC_ASSERT( static_cast<size_t>(tag) < count(),
79  "Unable to init with tag '${tag}' when the number of supported tags is ${count}",
80  ("tag",tag) ("count",count()) );
81  _tag = tag;
82  typelist::runtime::dispatch(list(), tag, [this](auto t) {
83  using T = typename decltype(t)::type;
84  storage.alloc(sizeof(T));
85  new(reinterpret_cast<T*>(storage.data())) T();
86  });
87  }
88 
89  void clean()
90  {
91  typelist::runtime::dispatch(list(), _tag, [data=storage.data()](auto t) {
92  using T = typename decltype(t)::type;
93  reinterpret_cast<T*>(data)->~T();
94  });
95  storage.release();
96  }
97 
98  template<typename T, typename = void>
99  struct import_helper {
100  static static_variant construct(const T&) {
101  FC_THROW_EXCEPTION(assert_exception, "Cannot import unsupported type ${T} into static_variant",
102  ("T", get_typename<T>::name()));
103  }
104  static static_variant construct(T&&) {
105  FC_THROW_EXCEPTION(assert_exception, "Cannot import unsupported type ${T} into static_variant",
106  ("T", get_typename<T>::name()));
107  }
108  };
109  template<typename T>
111  static static_variant construct(const T& t) {
112  return static_variant(t);
113  }
114  static static_variant construct(T&& t) {
115  return static_variant(std::move(t));
116  }
117  };
118 
119 public:
120  template<typename X, typename = type_in_typelist<X>>
121  struct tag
122  {
123  static constexpr tag_type value = typelist::index_of<list, X>();
124  };
125 
126  struct type_lt {
127  bool operator()(const static_variant& a, const static_variant& b) const { return a.which() < b.which(); }
128  };
129  struct type_eq {
130  bool operator()(const static_variant& a, const static_variant& b) const { return a.which() == b.which(); }
131  };
132  using flat_set_type = flat_set<static_variant, type_lt>;
133 
136  template<typename... Other>
138  return typelist::runtime::dispatch(typelist::list<Other...>(), other.which(), [&other](auto t) {
139  using other_type = typename decltype(t)::type;
140  return import_helper<other_type>::construct(other.template get<other_type>());
141  });
142  }
145  template<typename... Other>
147  return typelist::runtime::dispatch(typelist::list<Other...>(), other.which(), [&other](auto t) {
148  using other_type = typename decltype(t)::type;
149  return import_helper<other_type>::construct(std::move(other.template get<other_type>()));
150  });
151  }
152 
154  {
155  init_from_tag(0);
156  }
157 
158  template<typename... Other>
160  {
161  typelist::runtime::dispatch(typelist::list<Other...>(), cpy.which(), [this, &cpy](auto t) mutable {
162  this->init(cpy.template get<typename decltype(t)::type>());
163  });
164  }
165 
167  {
168  typelist::runtime::dispatch(list(), cpy.which(), [this, &cpy](auto t) mutable {
169  this->init(cpy.template get<typename decltype(t)::type>());
170  });
171  }
172 
174  {
175  typelist::runtime::dispatch(list(), mv.which(), [this, &mv](auto t) mutable {
176  this->init(std::move(mv.template get<typename decltype(t)::type>()));
177  });
178  }
179 
180  template<typename... Other>
182  {
183  typelist::runtime::dispatch(typelist::list<Other...>(), mv.which(), [this, &mv](auto t) mutable {
184  this->init(std::move(mv.template get<typename decltype(t)::type>()));
185  });
186  }
187 
188  template<typename X, typename = type_in_typelist<X>>
189  static_variant(const X& v) {
190  init(v);
191  }
192  template<typename X, typename = type_in_typelist<X>>
193  static_variant(X&& v) {
194  init(std::move(v));
195  }
196 
198  clean();
199  }
200 
201  template<typename X, typename = type_in_typelist<X>>
202  static_variant& operator=(const X& v) {
203  clean();
204  init(v);
205  return *this;
206  }
208  {
209  if( this == &v ) return *this;
210  clean();
211  typelist::runtime::dispatch(list(), v.which(), [this, &v](auto t)mutable {
212  this->init(v.template get<typename decltype(t)::type>());
213  });
214  return *this;
215  }
217  {
218  if( this == &v ) return *this;
219  clean();
220  typelist::runtime::dispatch(list(), v.which(), [this, &v](auto t)mutable {
221  this->init(std::move(v.template get<typename decltype(t)::type>()));
222  });
223  return *this;
224  }
225 
226  friend bool operator==( const static_variant& a, const static_variant& b ) {
227  if (a.which() != b.which())
228  return false;
229  return typelist::runtime::dispatch(list(), a.which(), [&a, &b](auto t) {
230  using Value = typename decltype(t)::type;
231  return a.template get<Value>() == b.template get<Value>();
232  });
233  }
234 
235  template<typename X, typename = type_in_typelist<X>>
236  X& get() {
237  if(_tag == typelist::index_of<list, X>()) {
238  return *reinterpret_cast<X*>(storage.data());
239  } else {
240  FC_THROW_EXCEPTION( fc::assert_exception,
241  "static_variant does not contain a value of type ${t}",
242  ("t",fc::get_typename<X>::name()) );
243  }
244  }
245  template<typename X, typename = type_in_typelist<X>>
246  const X& get() const {
247  if(_tag == typelist::index_of<list, X>()) {
248  return *reinterpret_cast<const X*>(storage.data());
249  } else {
250  FC_THROW_EXCEPTION( fc::assert_exception,
251  "static_variant does not contain a value of type ${t}",
252  ("t",fc::get_typename<X>::name()) );
253  }
254  }
255  template<typename visitor>
256  typename visitor::result_type visit(visitor& v) {
257  return visit( _tag, v, (void*) storage.data() );
258  }
259 
260  template<typename visitor>
261  typename visitor::result_type visit(const visitor& v) {
262  return visit( _tag, v, (void*) storage.data() );
263  }
264 
265  template<typename visitor>
266  typename visitor::result_type visit(visitor& v)const {
267  return visit( _tag, v, (const void*) storage.data() );
268  }
269 
270  template<typename visitor>
271  typename visitor::result_type visit(const visitor& v)const {
272  return visit( _tag, v, (const void*) storage.data() );
273  }
274 
275  template<typename visitor>
276  static typename visitor::result_type visit( tag_type tag, visitor& v, void* data )
277  {
278  FC_ASSERT( tag >= 0 && static_cast<size_t>(tag) < count(),
279  "Unsupported type '${tag}', the number of supported types is ${count}! ",
280  ("tag",tag) ("count",count()) );
281  return typelist::runtime::dispatch(list(), tag, [&v, data](auto t) {
282  return v(*reinterpret_cast<typename decltype(t)::type*>(data));
283  });
284  }
285 
286  template<typename visitor>
287  static typename visitor::result_type visit( tag_type tag, const visitor& v, void* data )
288  {
289  FC_ASSERT( tag >= 0 && static_cast<size_t>(tag) < count(),
290  "Unsupported type '${tag}', the number of supported types is ${count}! ",
291  ("tag",tag) ("count",count()) );
292  return typelist::runtime::dispatch(list(), tag, [&v, data](auto t) {
293  return v(*reinterpret_cast<typename decltype(t)::type*>(data));
294  });
295  }
296 
297  template<typename visitor>
298  static typename visitor::result_type visit( tag_type tag, visitor& v, const void* data )
299  {
300  FC_ASSERT( tag >= 0 && static_cast<size_t>(tag) < count(),
301  "Unsupported type '${tag}', the number of supported types is ${count}! ",
302  ("tag",tag) ("count",count()) );
303  return typelist::runtime::dispatch(list(), tag, [&v, data](auto t) {
304  return v(*reinterpret_cast<const typename decltype(t)::type*>(data));
305  });
306  }
307 
308  template<typename visitor>
309  static typename visitor::result_type visit( tag_type tag, const visitor& v, const void* data )
310  {
311  FC_ASSERT( tag >= 0 && static_cast<size_t>(tag) < count(),
312  "Unsupported type '${tag}', the number of supported types is ${count}! ",
313  ("tag",tag) ("count",count()) );
314  return typelist::runtime::dispatch(list(), tag, [&v, data](auto t) {
315  return v(*reinterpret_cast<const typename decltype(t)::type*>(data));
316  });
317  }
318 
319  static constexpr size_t count() { return typelist::length<list>(); }
320  void set_which( tag_type tag ) {
321  FC_ASSERT( tag >= 0, "Unable to set a negative tag '${tag}'", ("tag",tag) );
322  FC_ASSERT( static_cast<size_t>(tag) < count(),
323  "Unable to set tag '${tag}' when the number of supported tags is ${count}",
324  ("tag",tag) ("count",count()) );
325  clean();
326  init_from_tag(tag);
327  }
328 
329  tag_type which() const {return _tag;}
330 
331  template<typename T>
332  bool is_type() const { return _tag == tag<T>::value; }
333 };
334 template<> class static_variant<> {
335 public:
336  using tag_type = int64_t;
337  static_variant() { FC_THROW_EXCEPTION(assert_exception, "Cannot create static_variant with no types"); }
338 };
339 template<typename... Types> class static_variant<typelist::list<Types...>> : public static_variant<Types...> {};
340 
342  {
344  const uint32_t _max_depth;
345  from_static_variant( variant& dv, uint32_t max_depth ):var(dv),_max_depth(max_depth){}
346 
347  typedef void result_type;
348  template<typename T> void operator()( const T& v )const
349  {
350  to_variant( v, var, _max_depth );
351  }
352  };
353 
355  {
356  const variant& var;
357  const uint32_t _max_depth;
358  to_static_variant( const variant& dv, uint32_t max_depth ):var(dv),_max_depth(max_depth){}
359 
360  typedef void result_type;
361  template<typename T> void operator()( T& v )const
362  {
363  from_variant( var, v, _max_depth );
364  }
365  };
366 
367 
368  template<typename... T> void to_variant( const fc::static_variant<T...>& s, fc::variant& v, uint32_t max_depth )
369  {
370  FC_ASSERT( max_depth > 0 );
371  variants vars(2);
372  vars[0] = s.which();
373  s.visit( from_static_variant(vars[1], max_depth - 1) );
374  v = std::move(vars);
375  }
376  template<typename... T> void from_variant( const fc::variant& v, fc::static_variant<T...>& s, uint32_t max_depth )
377  {
378  FC_ASSERT( max_depth > 0 );
379  auto ar = v.get_array();
380  if( ar.size() < 2 ) return;
381  s.set_which( ar[0].as_uint64() );
382  s.visit( to_static_variant(ar[1], max_depth - 1) );
383  }
384 
385  template< typename... T > struct get_comma_separated_typenames;
386 
387  template<>
389  {
390  static const char* names() { return ""; }
391  };
392 
393  template< typename T >
395  {
396  static const char* names()
397  {
398  static const std::string n = get_typename<T>::name();
399  return n.c_str();
400  }
401  };
402 
403  template< typename T, typename... Ts >
405  {
406  static const char* names()
407  {
408  static const std::string n =
409  std::string( get_typename<T>::name() )+","+
411  return n.c_str();
412  }
413  };
414 
415  template< typename... T >
416  struct get_typename< static_variant< T... > >
417  {
418  static const char* name()
419  {
420  static const std::string n = std::string( "fc::static_variant<" )
422  + ">";
423  return n.c_str();
424  }
425  };
426 
427 } // namespace fc
fc::get_comma_separated_typenames< T, Ts... >::names
static const char * names()
Definition: static_variant.hpp:406
fc::static_variant::import_from
static static_variant import_from(const static_variant< Other... > &other)
Definition: static_variant.hpp:137
fc::static_variant< void_result, object_id_type, asset, generic_operation_result, generic_exchange_operation_result, extendable_operation_result >::tag_type
int64_t tag_type
Definition: static_variant.hpp:46
fc::get_comma_separated_typenames<>::names
static const char * names()
Definition: static_variant.hpp:390
fc::variant::get_array
variants & get_array()
Definition: variant.cpp:496
fc::typelist::list
The actual list type.
Definition: typelist.hpp:17
fc::static_variant::import_helper
Definition: static_variant.hpp:99
fc::typelist::concat_unique
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
fc::static_variant::operator=
static_variant & operator=(const static_variant &v)
Definition: static_variant.hpp:207
fc::to_static_variant::_max_depth
const uint32_t _max_depth
Definition: static_variant.hpp:357
fc::static_variant::visit
static visitor::result_type visit(tag_type tag, const visitor &v, void *data)
Definition: static_variant.hpp:287
fc::static_variant
Definition: raw_fwd.hpp:27
fc::static_variant::operator=
static_variant & operator=(const X &v)
Definition: static_variant.hpp:202
fc::static_variant::list
typelist::list< Types... > list
Definition: static_variant.hpp:47
fc::static_variant::import_helper< T, type_in_typelist< T > >::construct
static static_variant construct(T &&t)
Definition: static_variant.hpp:114
fc
Definition: api.hpp:15
fc::static_variant::_tag
tag_type _tag
Definition: static_variant.hpp:58
fc::static_variant::count
static constexpr size_t count()
Definition: static_variant.hpp:319
fc::static_variant::static_variant
static_variant(const static_variant &cpy)
Definition: static_variant.hpp:166
fc::static_variant::~static_variant
~static_variant()
Definition: static_variant.hpp:197
fc::static_variant::import_helper::construct
static static_variant construct(const T &)
Definition: static_variant.hpp:100
fc::static_variant::type_lt
Definition: static_variant.hpp:126
graphene::protocol::result_type
object_restriction_predicate< operation > result_type
Definition: list_1.cpp:29
fc::static_variant<>::tag_type
int64_t tag_type
Definition: static_variant.hpp:336
fc::static_variant::visit
visitor::result_type visit(const visitor &v) const
Definition: static_variant.hpp:271
fc::static_variant::visit
visitor::result_type visit(const visitor &v)
Definition: static_variant.hpp:261
fc::from_variant
void from_variant(const variant &var, flat_set< T, A... > &vo, uint32_t _max_depth)
Definition: flat.hpp:116
fc::static_variant::static_variant
static_variant(static_variant &&mv)
Definition: static_variant.hpp:173
fc::static_variant::static_variant
static_variant()
Definition: static_variant.hpp:153
fc::static_variant::type_lt::operator()
bool operator()(const static_variant &a, const static_variant &b) const
Definition: static_variant.hpp:127
fc::typelist
This namespace contains the list type, and all of the operations and queries which can be performed u...
Definition: typelist.hpp:14
fc::static_variant::tag::value
static constexpr tag_type value
Definition: static_variant.hpp:123
fc::get_comma_separated_typenames
Definition: static_variant.hpp:385
fc::static_variant::clean
void clean()
Definition: static_variant.hpp:89
fc::variants
std::vector< variant > variants
Definition: variant.hpp:170
fc::static_variant::import_helper::construct
static static_variant construct(T &&)
Definition: static_variant.hpp:104
fc::get_typename< static_variant< T... > >::name
static const char * name()
Definition: static_variant.hpp:418
fc::get_typename
Definition: typename.hpp:20
fc::from_static_variant::result_type
void result_type
Definition: static_variant.hpp:347
fc::from_static_variant
Definition: static_variant.hpp:341
fc::static_variant::visit
static visitor::result_type visit(tag_type tag, const visitor &v, const void *data)
Definition: static_variant.hpp:309
fc::impl::dynamic_storage::release
void release()
Definition: static_variant.cpp:25
fc::from_static_variant::from_static_variant
from_static_variant(variant &dv, uint32_t max_depth)
Definition: static_variant.hpp:345
fc::static_variant::import_from
static static_variant import_from(static_variant< Other... > &&other)
Definition: static_variant.hpp:146
fc::from_static_variant::_max_depth
const uint32_t _max_depth
Definition: static_variant.hpp:344
fc::to_variant
void to_variant(const flat_set< T, A... > &var, variant &vo, uint32_t _max_depth)
Definition: flat.hpp:105
fc::to_static_variant
Definition: static_variant.hpp:354
fc::static_variant::operator=
static_variant & operator=(static_variant &&v)
Definition: static_variant.hpp:216
fc::static_variant::operator==
friend bool operator==(const static_variant &a, const static_variant &b)
Definition: static_variant.hpp:226
fc::get_comma_separated_typenames< T >::names
static const char * names()
Definition: static_variant.hpp:396
fc::static_variant::init_from_tag
void init_from_tag(tag_type tag)
Definition: static_variant.hpp:75
fc::impl::dynamic_storage::dynamic_storage
dynamic_storage()
Definition: static_variant.cpp:6
fc::impl::dynamic_storage::~dynamic_storage
~dynamic_storage()
Definition: static_variant.cpp:8
fc::static_variant::tag
Definition: static_variant.hpp:121
fc::static_variant::get
const X & get() const
Definition: static_variant.hpp:246
fc::static_variant::import_helper< T, type_in_typelist< T > >::construct
static static_variant construct(const T &t)
Definition: static_variant.hpp:111
FC_ASSERT
#define FC_ASSERT(TEST,...)
Checks a condition and throws an assert_exception if the test is FALSE.
Definition: exception.hpp:345
fc::impl::dynamic_storage::data
void * data() const
Definition: static_variant.cpp:13
fc::from_static_variant::operator()
void operator()(const T &v) const
Definition: static_variant.hpp:348
fc::static_variant::static_variant
static_variant(static_variant< Other... > &&mv)
Definition: static_variant.hpp:181
fc::static_variant::is_type
bool is_type() const
Definition: static_variant.hpp:332
fc::variant
stores null, int64, uint64, double, bool, string, std::vector<variant>, and variant_object's.
Definition: variant.hpp:198
fc::static_variant::visit
visitor::result_type visit(visitor &v) const
Definition: static_variant.hpp:266
fc::impl::dynamic_storage
Definition: static_variant.hpp:26
exception.hpp
Defines exception's used by fc.
fc::static_variant::get
X & get()
Definition: static_variant.hpp:236
fc::to_static_variant::var
const variant & var
Definition: static_variant.hpp:356
fc::static_variant::which
tag_type which() const
Definition: static_variant.hpp:329
fc::to_static_variant::to_static_variant
to_static_variant(const variant &dv, uint32_t max_depth)
Definition: static_variant.hpp:358
fc::static_variant::static_variant
static_variant(const X &v)
Definition: static_variant.hpp:189
fc::static_variant::visit
static visitor::result_type visit(tag_type tag, visitor &v, void *data)
Definition: static_variant.hpp:276
fc::static_variant::init
void init(const X &x)
Definition: static_variant.hpp:62
fc::static_variant<>::static_variant
static_variant()
Definition: static_variant.hpp:337
fc::static_variant< void_result, object_id_type, asset, generic_operation_result, generic_exchange_operation_result, extendable_operation_result >::type_in_typelist
std::enable_if_t< typelist::index_of< list, X >() !=-1 > type_in_typelist
Definition: static_variant.hpp:56
fc::to_static_variant::result_type
void result_type
Definition: static_variant.hpp:360
fc::static_variant::init
void init(X &&x)
Definition: static_variant.hpp:69
fc::static_variant::set_which
void set_which(tag_type tag)
Definition: static_variant.hpp:320
fc::static_variant::static_variant
static_variant(X &&v)
Definition: static_variant.hpp:193
fc::static_variant::visit
visitor::result_type visit(visitor &v)
Definition: static_variant.hpp:256
fc::static_variant::static_variant
static_variant(const static_variant< Other... > &cpy)
Definition: static_variant.hpp:159
fc::typelist::runtime::dispatch
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
fc::static_variant< void_result, object_id_type, asset, generic_operation_result, generic_exchange_operation_result, extendable_operation_result >::flat_set_type
flat_set< static_variant, type_lt > flat_set_type
Definition: static_variant.hpp:132
fc::static_variant::type_eq
Definition: static_variant.hpp:129
FC_THROW_EXCEPTION
#define FC_THROW_EXCEPTION(EXCEPTION, FORMAT,...)
Definition: exception.hpp:379
fc::from_static_variant::var
variant & var
Definition: static_variant.hpp:343
fc::static_variant::storage
impl::dynamic_storage storage
Definition: static_variant.hpp:59
fc::typelist::filter
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
fc::to_static_variant::operator()
void operator()(T &v) const
Definition: static_variant.hpp:361
fc::static_variant::visit
static visitor::result_type visit(tag_type tag, visitor &v, const void *data)
Definition: static_variant.hpp:298
fc::impl::dynamic_storage::alloc
void alloc(size_t size)
Definition: static_variant.cpp:19
fc::static_variant::type_eq::operator()
bool operator()(const static_variant &a, const static_variant &b) const
Definition: static_variant.hpp:130