BitShares-Core  6.1.0
BitShares blockchain implementation and command-line interface 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
static static_variant construct(const T &)
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)
visitor::result_type visit(const visitor &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)
void operator()(T &v) const
static constexpr size_t count()
tag_type which() const
static static_variant construct(T &&)
bool operator()(const static_variant &a, const static_variant &b) const
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)
void operator()(const T &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:379
The actual list type.
Definition: typelist.hpp:17
Defines exception&#39;s used by fc.
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
Definition: api.hpp:15
void set_which(tag_type tag)
impl::dynamic_storage storage
static_variant & operator=(const static_variant &v)
bool operator()(const static_variant &a, const static_variant &b) const
visitor::result_type visit(visitor &v) const
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