BitShares-Core  4.0.0
BitShares blockchain implementation and command-line interface software
variant.cpp
Go to the documentation of this file.
1 #include <fc/variant.hpp>
2 #include <fc/variant_object.hpp>
4 #include <fc/io/sstream.hpp>
5 #include <fc/io/json.hpp>
6 #include <fc/io/stdio.hpp>
7 #include <string.h>
8 #include <fc/crypto/base64.hpp>
9 #include <fc/crypto/hex.hpp>
10 #include <boost/scoped_array.hpp>
11 #include <fc/reflect/variant.hpp>
12 #include <algorithm>
13 
14 #if defined(__APPLE__) or defined(__OpenBSD__)
15 #include <boost/multiprecision/integer.hpp>
16 #endif
17 
18 namespace fc
19 {
20 
25 {
26  char* data = reinterpret_cast<char*>(v);
27  data[ sizeof(variant) -1 ] = t;
28 }
29 
31 {
32  set_variant_type( this, null_type );
33 }
34 
35 variant::variant( std::nullptr_t, uint32_t max_depth )
36 {
37  set_variant_type( this, null_type );
38 }
39 
40 variant::variant( uint8_t val, uint32_t max_depth )
41 {
42  *reinterpret_cast<uint64_t*>(this) = val;
44 }
45 
46 variant::variant( int8_t val, uint32_t max_depth )
47 {
48  *reinterpret_cast<int64_t*>(this) = val;
50 }
51 
52 variant::variant( uint16_t val, uint32_t max_depth )
53 {
54  *reinterpret_cast<uint64_t*>(this) = val;
56 }
57 
58 variant::variant( int16_t val, uint32_t max_depth )
59 {
60  *reinterpret_cast<int64_t*>(this) = val;
62 }
63 
64 variant::variant( uint32_t val, uint32_t max_depth )
65 {
66  *reinterpret_cast<uint64_t*>(this) = val;
68 }
69 
70 variant::variant( int32_t val, uint32_t max_depth )
71 {
72  *reinterpret_cast<int64_t*>(this) = val;
74 }
75 
76 variant::variant( uint64_t val, uint32_t max_depth )
77 {
78  *reinterpret_cast<uint64_t*>(this) = val;
80 }
81 
82 #if defined(__APPLE__) or defined(__OpenBSD__)
83 variant::variant( size_t val, uint32_t max_depth )
84 {
85  *reinterpret_cast<uint64_t*>(this) = val;
87 }
88 #endif
89 
90 variant::variant( int64_t val, uint32_t max_depth )
91 {
92  *reinterpret_cast<int64_t*>(this) = val;
94 }
95 
96 variant::variant( float val, uint32_t max_depth )
97 {
98  *reinterpret_cast<double*>(this) = val;
100 }
101 
102 variant::variant( double val, uint32_t max_depth )
103 {
104  *reinterpret_cast<double*>(this) = val;
105  set_variant_type( this, double_type );
106 }
107 
108 variant::variant( bool val, uint32_t max_depth )
109 {
110  *reinterpret_cast<bool*>(this) = val;
111  set_variant_type( this, bool_type );
112 }
113 
114 variant::variant( char* str, uint32_t max_depth )
115 {
116  *reinterpret_cast<string**>(this) = new string( str );
117  set_variant_type( this, string_type );
118 }
119 
120 variant::variant( const char* str, uint32_t max_depth )
121 {
122  *reinterpret_cast<string**>(this) = new string( str );
123  set_variant_type( this, string_type );
124 }
125 
126 // TODO: do a proper conversion to utf8
127 variant::variant( wchar_t* str, uint32_t max_depth )
128 {
129  size_t len = wcslen(str);
130  boost::scoped_array<char> buffer(new char[len]);
131  for (unsigned i = 0; i < len; ++i)
132  buffer[i] = (char)str[i];
133  *reinterpret_cast<string**>(this) = new string(buffer.get(), len);
134  set_variant_type( this, string_type );
135 }
136 
137 // TODO: do a proper conversion to utf8
138 variant::variant( const wchar_t* str, uint32_t max_depth )
139 {
140  size_t len = wcslen(str);
141  boost::scoped_array<char> buffer(new char[len]);
142  for (unsigned i = 0; i < len; ++i)
143  buffer[i] = (char)str[i];
144  *reinterpret_cast<string**>(this) = new string(buffer.get(), len);
145  set_variant_type( this, string_type );
146 }
147 
148 variant::variant( std::string val, uint32_t max_depth )
149 {
150  *reinterpret_cast<string**>(this) = new string( std::move(val) );
151  set_variant_type( this, string_type );
152 }
153 variant::variant( blob val, uint32_t max_depth )
154 {
155  *reinterpret_cast<blob**>(this) = new blob( std::move(val) );
156  set_variant_type( this, blob_type );
157 }
158 
159 variant::variant( variant_object obj, uint32_t max_depth )
160 {
161  *reinterpret_cast<variant_object**>(this) = new variant_object(std::move(obj));
163 }
164 variant::variant( mutable_variant_object obj, uint32_t max_depth )
165 {
166  *reinterpret_cast<variant_object**>(this) = new variant_object(std::move(obj));
168 }
169 
170 variant::variant( variants arr, uint32_t max_depth )
171 {
172  *reinterpret_cast<variants**>(this) = new variants(std::move(arr));
174 }
175 
177 typedef const variants* const_variants_ptr;
178 typedef const blob* const_blob_ptr;
179 typedef const string* const_string_ptr;
180 
182 {
183  switch( get_type() )
184  {
185  case object_type:
186  delete *reinterpret_cast<variant_object**>(this);
187  break;
188  case array_type:
189  delete *reinterpret_cast<variants**>(this);
190  break;
191  case string_type:
192  delete *reinterpret_cast<string**>(this);
193  break;
194  default:
195  break;
196  }
197  set_variant_type( this, null_type );
198 }
199 
200 variant::variant( const variant& v, uint32_t max_depth )
201 {
202  switch( v.get_type() )
203  {
204  case object_type:
205  *reinterpret_cast<variant_object**>(this) =
206  new variant_object(**reinterpret_cast<const const_variant_object_ptr*>(&v));
207  set_variant_type( this, object_type );
208  return;
209  case array_type:
210  *reinterpret_cast<variants**>(this) =
211  new variants(**reinterpret_cast<const const_variants_ptr*>(&v));
212  set_variant_type( this, array_type );
213  return;
214  case string_type:
215  *reinterpret_cast<string**>(this) =
216  new string(**reinterpret_cast<const const_string_ptr*>(&v) );
217  set_variant_type( this, string_type );
218  return;
219  default:
220  memcpy( this, &v, sizeof(v) );
221  }
222 }
223 
224 variant::variant( variant&& v, uint32_t max_depth )
225 {
226  memcpy( this, &v, sizeof(v) );
228 }
229 
231 {
232  clear();
233 }
234 
236 {
237  if( this == &v ) return *this;
238  clear();
239  memcpy( (char*)this, (char*)&v, sizeof(v) );
240  set_variant_type( &v, null_type );
241  return *this;
242 }
243 
245 {
246  if( this == &v )
247  return *this;
248 
249  clear();
250  switch( v.get_type() )
251  {
252  case object_type:
253  *reinterpret_cast<variant_object**>(this) =
254  new variant_object((**reinterpret_cast<const const_variant_object_ptr*>(&v)));
255  break;
256  case array_type:
257  *reinterpret_cast<variants**>(this) =
258  new variants((**reinterpret_cast<const const_variants_ptr*>(&v)));
259  break;
260  case string_type:
261  *reinterpret_cast<string**>(this) = new string((**reinterpret_cast<const const_string_ptr*>(&v)) );
262  break;
263 
264  default:
265  memcpy( this, &v, sizeof(v) );
266  }
267  set_variant_type( this, v.get_type() );
268  return *this;
269 }
270 
271 void variant::visit( const visitor& v )const
272 {
273  switch( get_type() )
274  {
275  case null_type:
276  v.handle();
277  return;
278  case int64_type:
279  v.handle( *reinterpret_cast<const int64_t*>(this) );
280  return;
281  case uint64_type:
282  v.handle( *reinterpret_cast<const uint64_t*>(this) );
283  return;
284  case double_type:
285  v.handle( *reinterpret_cast<const double*>(this) );
286  return;
287  case bool_type:
288  v.handle( *reinterpret_cast<const bool*>(this) );
289  return;
290  case string_type:
291  v.handle( **reinterpret_cast<const const_string_ptr*>(this) );
292  return;
293  case array_type:
294  v.handle( **reinterpret_cast<const const_variants_ptr*>(this) );
295  return;
296  case object_type:
297  v.handle( **reinterpret_cast<const const_variant_object_ptr*>(this) );
298  return;
299  default:
300  FC_THROW_EXCEPTION( assert_exception, "Invalid Type / Corrupted Memory" );
301  }
302 }
303 
305 {
306  return (type_id)reinterpret_cast<const char*>(this)[sizeof(*this)-1];
307 }
308 
309 bool variant::is_null()const
310 {
311  return get_type() == null_type;
312 }
313 
315 {
316  return get_type() == string_type;
317 }
318 bool variant::is_bool()const
319 {
320  return get_type() == bool_type;
321 }
323 {
324  return get_type() == double_type;
325 }
327 {
328  return get_type() == uint64_type;
329 }
330 bool variant::is_int64()const
331 {
332  return get_type() == int64_type;
333 }
334 
336 {
337  switch( get_type() )
338  {
339  case int64_type:
340  case uint64_type:
341  case bool_type:
342  return true;
343  default:
344  return false;
345  }
346  return false;
347 }
349 {
350  switch( get_type() )
351  {
352  case int64_type:
353  case uint64_type:
354  case double_type:
355  case bool_type:
356  return true;
357  default:
358  return false;
359  }
360  return false;
361 }
362 
364 {
365  return get_type() == object_type;
366 }
367 
368 bool variant::is_array()const
369 {
370  return get_type() == array_type;
371 }
372 bool variant::is_blob()const
373 {
374  return get_type() == blob_type;
375 }
376 
377 int64_t variant::as_int64()const
378 {
379  switch( get_type() )
380  {
381  case string_type:
382  return to_int64(**reinterpret_cast<const const_string_ptr*>(this));
383  case double_type:
384  return int64_t(*reinterpret_cast<const double*>(this));
385  case int64_type:
386  return *reinterpret_cast<const int64_t*>(this);
387  case uint64_type:
388  return int64_t(*reinterpret_cast<const uint64_t*>(this));
389  case bool_type:
390  return *reinterpret_cast<const bool*>(this);
391  case null_type:
392  return 0;
393  default:
394  FC_THROW_EXCEPTION( bad_cast_exception, "Invalid cast from ${type} to int64", ("type", get_type()) );
395  }
396 }
397 
398 uint64_t variant::as_uint64()const
399 { try {
400  switch( get_type() )
401  {
402  case string_type:
403  return to_uint64(**reinterpret_cast<const const_string_ptr*>(this));
404  case double_type:
405  return static_cast<uint64_t>(*reinterpret_cast<const double*>(this));
406  case int64_type:
407  return static_cast<uint64_t>(*reinterpret_cast<const int64_t*>(this));
408  case uint64_type:
409  return *reinterpret_cast<const uint64_t*>(this);
410  case bool_type:
411  return static_cast<uint64_t>(*reinterpret_cast<const bool*>(this));
412  case null_type:
413  return 0;
414  default:
415  FC_THROW_EXCEPTION( bad_cast_exception,"Invalid cast from ${type} to uint64", ("type",get_type()));
416  }
417 } FC_CAPTURE_AND_RETHROW( (*this) ) }
418 
419 
420 double variant::as_double()const
421 {
422  switch( get_type() )
423  {
424  case string_type:
425  return to_double(**reinterpret_cast<const const_string_ptr*>(this));
426  case double_type:
427  return *reinterpret_cast<const double*>(this);
428  case int64_type:
429  return static_cast<double>(*reinterpret_cast<const int64_t*>(this));
430  case uint64_type:
431  return static_cast<double>(*reinterpret_cast<const uint64_t*>(this));
432  case bool_type:
433  return *reinterpret_cast<const bool*>(this);
434  case null_type:
435  return 0;
436  default:
437  FC_THROW_EXCEPTION( bad_cast_exception, "Invalid cast from ${type} to double", ("type",get_type()) );
438  }
439 }
440 
441 bool variant::as_bool()const
442 {
443  switch( get_type() )
444  {
445  case string_type:
446  {
447  const string& s = **reinterpret_cast<const const_string_ptr*>(this);
448  if( s == "true" )
449  return true;
450  if( s == "false" )
451  return false;
452  FC_THROW_EXCEPTION( bad_cast_exception, "Cannot convert string to bool (only \"true\" or \"false\" can be converted)" );
453  }
454  case double_type:
455  return *reinterpret_cast<const double*>(this) != 0.0;
456  case int64_type:
457  return *reinterpret_cast<const int64_t*>(this) != 0;
458  case uint64_type:
459  return *reinterpret_cast<const uint64_t*>(this) != 0;
460  case bool_type:
461  return *reinterpret_cast<const bool*>(this);
462  case null_type:
463  return false;
464  default:
465  FC_THROW_EXCEPTION( bad_cast_exception, "Invalid cast from ${type} to bool" , ("type",get_type()));
466  }
467 }
468 
469 string variant::as_string()const
470 {
471  switch( get_type() )
472  {
473  case string_type:
474  return **reinterpret_cast<const const_string_ptr*>(this);
475  case double_type:
476  return to_string(*reinterpret_cast<const double*>(this));
477  case int64_type:
478  return to_string(*reinterpret_cast<const int64_t*>(this));
479  case uint64_type:
480  return to_string(*reinterpret_cast<const uint64_t*>(this));
481  case bool_type:
482  return *reinterpret_cast<const bool*>(this) ? "true" : "false";
483  case blob_type:
484  if( get_blob().data.size() )
485  return base64_encode( get_blob().data.data(), get_blob().data.size() ) + "=";
486  return string();
487  case null_type:
488  return string();
489  default:
490  FC_THROW_EXCEPTION( bad_cast_exception, "Invalid cast from ${type} to string", ("type", get_type() ) );
491  }
492 }
493 
494 
497 {
498  if( get_type() == array_type )
499  return **reinterpret_cast<variants**>(this);
500 
501  FC_THROW_EXCEPTION( bad_cast_exception, "Invalid cast from ${type} to Array", ("type",get_type()) );
502 }
504 {
505  if( get_type() == blob_type )
506  return **reinterpret_cast<blob**>(this);
507 
508  FC_THROW_EXCEPTION( bad_cast_exception, "Invalid cast from ${type} to Blob", ("type",get_type()) );
509 }
510 const blob& variant::get_blob()const
511 {
512  if( get_type() == blob_type )
513  return **reinterpret_cast<const const_blob_ptr*>(this);
514 
515  FC_THROW_EXCEPTION( bad_cast_exception, "Invalid cast from ${type} to Blob", ("type",get_type()) );
516 }
517 
519 {
520  switch( get_type() )
521  {
522  case null_type: return blob();
523  case blob_type: return get_blob();
524  case string_type:
525  {
526  const string& str = get_string();
527  if( str.size() == 0 ) return blob();
528  if( str.back() == '=' )
529  {
530  std::string b64 = base64_decode( get_string() );
531  return blob( { std::vector<char>( b64.begin(), b64.end() ) } );
532  }
533  return blob( { std::vector<char>( str.begin(), str.end() ) } );
534  }
535  case object_type:
536  case array_type:
537  FC_THROW_EXCEPTION( bad_cast_exception, "Invalid cast from ${type} to Blob", ("type",get_type()) );
538  default:
539  return blob( { std::vector<char>( (char*)&_data, (char*)&_data + sizeof(_data) ) } );
540  }
541 }
542 
543 
546 {
547  if( get_type() == array_type )
548  return **reinterpret_cast<const const_variants_ptr*>(this);
549  FC_THROW_EXCEPTION( bad_cast_exception, "Invalid cast from ${type} to Array", ("type",get_type()) );
550 }
551 
552 
555 {
556  if( get_type() == object_type )
557  return **reinterpret_cast<variant_object**>(this);
558  FC_THROW_EXCEPTION( bad_cast_exception, "Invalid cast from ${type} to Object", ("type",get_type()) );
559 }
560 
561 const variant& variant::operator[]( const char* key )const
562 {
563  return get_object()[key];
564 }
565 const variant& variant::operator[]( size_t pos )const
566 {
567  return get_array()[pos];
568 }
570 size_t variant::size()const
571 {
572  return get_array().size();
573 }
574 
575 const string& variant::get_string()const
576 {
577  if( get_type() == string_type )
578  return **reinterpret_cast<const const_string_ptr*>(this);
579  FC_THROW_EXCEPTION( bad_cast_exception, "Invalid cast from type '${type}' to Object", ("type",get_type()) );
580 }
581 
584 {
585  if( get_type() == object_type )
586  return **reinterpret_cast<const const_variant_object_ptr*>(this);
587  FC_THROW_EXCEPTION( bad_cast_exception, "Invalid cast from type '${type}' to Object", ("type",get_type()) );
588 }
589 
590 void from_variant( const variant& var, variants& vo, uint32_t max_depth )
591 {
592  vo = var.get_array();
593 }
594 
595 void from_variant( const variant& var, variant& vo, uint32_t max_depth ) { vo = var; }
596 
597 void to_variant( const uint8_t& var, variant& vo, uint32_t max_depth ) { vo = uint64_t(var); }
598 // TODO: warn on overflow?
599 void from_variant( const variant& var, uint8_t& vo, uint32_t max_depth ){ vo = static_cast<uint8_t>(var.as_uint64()); }
600 
601 void to_variant( const int8_t& var, variant& vo, uint32_t max_depth ) { vo = int64_t(var); }
602 // TODO: warn on overflow?
603 void from_variant( const variant& var, int8_t& vo, uint32_t max_depth ) { vo = static_cast<int8_t>(var.as_int64()); }
604 
605 void to_variant( const uint16_t& var, variant& vo, uint32_t max_depth ) { vo = uint64_t(var); }
606 // TODO: warn on overflow?
607 void from_variant( const variant& var, uint16_t& vo, uint32_t max_depth ){ vo = static_cast<uint16_t>(var.as_uint64()); }
608 
609 void to_variant( const int16_t& var, variant& vo, uint32_t max_depth ) { vo = int64_t(var); }
610 // TODO: warn on overflow?
611 void from_variant( const variant& var, int16_t& vo, uint32_t max_depth ){ vo = static_cast<int16_t>(var.as_int64()); }
612 
613 void to_variant( const uint32_t& var, variant& vo, uint32_t max_depth ) { vo = uint64_t(var); }
614 void from_variant( const variant& var, uint32_t& vo, uint32_t max_depth )
615 {
616  vo = static_cast<uint32_t>(var.as_uint64());
617 }
618 
619 void to_variant( const int32_t& var, variant& vo, uint32_t max_depth ) { vo = int64_t(var); }
620 void from_variant( const variant& var,int32_t& vo, uint32_t max_depth )
621 {
622  vo = static_cast<int32_t>(var.as_int64());
623 }
624 
625 void to_variant( const int64_t& var, variant& vo, uint32_t max_depth ) { vo = var; }
626 void from_variant( const variant& var, int64_t& vo, uint32_t max_depth )
627 {
628  vo = var.as_int64();
629 }
630 
631 void to_variant( const uint64_t& var, variant& vo, uint32_t max_depth ) { vo = var; }
632 void from_variant( const variant& var, uint64_t& vo, uint32_t max_depth )
633 {
634  vo = var.as_uint64();
635 }
636 
637 void to_variant( const bool& var, variant& vo, uint32_t max_depth ) { vo = uint64_t(var); }
638 void from_variant( const variant& var, bool& vo, uint32_t max_depth )
639 {
640  vo = var.as_bool();
641 }
642 
643 void from_variant( const variant& var, double& vo, uint32_t max_depth )
644 {
645  vo = var.as_double();
646 }
647 
648 void from_variant( const variant& var, float& vo, uint32_t max_depth )
649 {
650  vo = static_cast<float>(var.as_double());
651 }
652 
653 void to_variant( const std::string& s, variant& v, uint32_t max_depth )
654 {
655  v = variant( std::string(s), max_depth );
656 }
657 
658 void from_variant( const variant& var, string& vo, uint32_t max_depth )
659 {
660  vo = var.as_string();
661 }
662 
663 void to_variant( const std::vector<char>& var, variant& vo, uint32_t max_depth )
664 {
665  if( var.size() )
666  vo = variant(to_hex(var.data(),var.size()));
667  else vo = "";
668 }
669 void from_variant( const variant& var, std::vector<char>& vo, uint32_t max_depth )
670 {
671  auto str = var.as_string();
672  vo.resize( str.size() / 2 );
673  if( vo.size() )
674  {
675  size_t r = from_hex( str, vo.data(), vo.size() );
676  FC_ASSERT( r == vo.size() );
677  }
678 }
679 
680 void to_variant( const uint128_t& var, variant& vo, uint32_t max_depth )
681 {
682 #if defined(__APPLE__) or defined(__OpenBSD__)
683  boost::multiprecision::uint128_t helper = uint128_hi64( var );
684  helper <<= 64;
685  helper += uint128_lo64( var );
686  vo = boost::lexical_cast<std::string>( helper );
687 #else
688  vo = boost::lexical_cast<std::string>( var );
689 #endif
690 }
691 
692 void from_variant( const variant& var, uint128_t& vo, uint32_t max_depth )
693 {
694 #if defined(__APPLE__) or defined(__OpenBSD__)
695  boost::multiprecision::uint128_t helper = boost::lexical_cast<boost::multiprecision::uint128_t>( var.as_string() );
696  vo = static_cast<uint64_t>( helper >> 64 );
697  vo <<= 64;
698  vo += static_cast<uint64_t>( helper & 0xffffffffffffffffULL );
699 #else
700  vo = boost::lexical_cast<uint128_t>( var.as_string() );
701 #endif
702 }
703 
704 #if defined(__APPLE__) or defined(__OpenBSD__)
705  void to_variant( size_t s, variant& v, uint32_t max_depth ) { v = variant( uint64_t(s) ); }
706 #elif !defined(_WIN32)
707  void to_variant( long long int s, variant& v, uint32_t max_depth ) { v = variant( int64_t(s) ); }
708  void to_variant( unsigned long long int s, variant& v, uint32_t max_depth ) { v = variant( uint64_t(s)); }
709 #endif
710 
711  bool operator == ( const variant& a, const variant& b )
712  {
713  if( a.is_string() || b.is_string() ) return a.as_string() == b.as_string();
714  if( a.is_double() || b.is_double() ) return a.as_double() == b.as_double();
715  if( a.is_int64() || b.is_int64() ) return a.as_int64() == b.as_int64();
716  if( a.is_uint64() || b.is_uint64() ) return a.as_uint64() == b.as_uint64();
717  return false;
718  }
719 
720  bool operator != ( const variant& a, const variant& b )
721  {
722  if( a.is_string() || b.is_string() ) return a.as_string() != b.as_string();
723  if( a.is_double() || b.is_double() ) return a.as_double() != b.as_double();
724  if( a.is_int64() || b.is_int64() ) return a.as_int64() != b.as_int64();
725  if( a.is_uint64() || b.is_uint64() ) return a.as_uint64() != b.as_uint64();
726  return false;
727  }
728 
729  bool operator ! ( const variant& a )
730  {
731  return !a.as_bool();
732  }
733 
734  bool operator < ( const variant& a, const variant& b )
735  {
736  if( a.is_string() || b.is_string() ) return a.as_string() < b.as_string();
737  if( a.is_double() || b.is_double() ) return a.as_double() < b.as_double();
738  if( a.is_int64() || b.is_int64() ) return a.as_int64() < b.as_int64();
739  if( a.is_uint64() || b.is_uint64() ) return a.as_uint64() < b.as_uint64();
740  FC_ASSERT( false, "Invalid operation" );
741  }
742 
743  bool operator > ( const variant& a, const variant& b )
744  {
745  if( a.is_string() || b.is_string() ) return a.as_string() > b.as_string();
746  if( a.is_double() || b.is_double() ) return a.as_double() > b.as_double();
747  if( a.is_int64() || b.is_int64() ) return a.as_int64() > b.as_int64();
748  if( a.is_uint64() || b.is_uint64() ) return a.as_uint64() > b.as_uint64();
749  FC_ASSERT( false, "Invalid operation" );
750  }
751 
752  bool operator <= ( const variant& a, const variant& b )
753  {
754  if( a.is_string() || b.is_string() ) return a.as_string() <= b.as_string();
755  if( a.is_double() || b.is_double() ) return a.as_double() <= b.as_double();
756  if( a.is_int64() || b.is_int64() ) return a.as_int64() <= b.as_int64();
757  if( a.is_uint64() || b.is_uint64() ) return a.as_uint64() <= b.as_uint64();
758  FC_ASSERT( false, "Invalid operation" );
759  }
760 
761 
762  variant operator + ( const variant& a, const variant& b )
763  {
764  if( a.is_array() && b.is_array() )
765  {
766  const variants& aa = a.get_array();
767  const variants& ba = b.get_array();
768  variants result;
769  result.reserve( std::max(aa.size(),ba.size()) );
770  auto num = std::max(aa.size(),ba.size());
771  for( unsigned i = 0; i < num; ++i )
772  {
773  if( aa.size() > i && ba.size() > i )
774  result[i] = aa[i] + ba[i];
775  else if( aa.size() > i )
776  result[i] = aa[i];
777  else
778  result[i] = ba[i];
779  }
780  return result;
781  }
782  if( a.is_string() || b.is_string() ) return a.as_string() + b.as_string();
783  if( a.is_double() || b.is_double() ) return a.as_double() + b.as_double();
784  if( a.is_int64() || b.is_int64() ) return a.as_int64() + b.as_int64();
785  if( a.is_uint64() || b.is_uint64() ) return a.as_uint64() + b.as_uint64();
786  FC_ASSERT( false, "invalid operation ${a} + ${b}", ("a",a)("b",b) );
787  }
788 
789  variant operator - ( const variant& a, const variant& b )
790  {
791  if( a.is_array() && b.is_array() )
792  {
793  const variants& aa = a.get_array();
794  const variants& ba = b.get_array();
795  variants result;
796  result.reserve( std::max(aa.size(),ba.size()) );
797  auto num = std::max(aa.size(),ba.size());
798  for( unsigned i = 0; i < num; --i )
799  {
800  if( aa.size() > i && ba.size() > i )
801  result[i] = aa[i] - ba[i];
802  else if( aa.size() > i )
803  result[i] = aa[i];
804  else
805  result[i] = ba[i];
806  }
807  return result;
808  }
809  if( a.is_string() || b.is_string() ) return a.as_string() - b.as_string();
810  if( a.is_double() || b.is_double() ) return a.as_double() - b.as_double();
811  if( a.is_int64() || b.is_int64() ) return a.as_int64() - b.as_int64();
812  if( a.is_uint64() || b.is_uint64() ) return a.as_uint64() - b.as_uint64();
813  FC_ASSERT( false, "invalid operation ${a} + ${b}", ("a",a)("b",b) );
814  }
815  variant operator * ( const variant& a, const variant& b )
816  {
817  if( a.is_double() || b.is_double() ) return a.as_double() * b.as_double();
818  if( a.is_int64() || b.is_int64() ) return a.as_int64() * b.as_int64();
819  if( a.is_uint64() || b.is_uint64() ) return a.as_uint64() * b.as_uint64();
820  if( a.is_array() && b.is_array() )
821  {
822  const variants& aa = a.get_array();
823  const variants& ba = b.get_array();
824  variants result;
825  result.reserve( std::max(aa.size(),ba.size()) );
826  auto num = std::max(aa.size(),ba.size());
827  for( unsigned i = 0; i < num; ++i )
828  {
829  if( aa.size() > i && ba.size() > i )
830  result[i] = aa[i] * ba[i];
831  else if( aa.size() > i )
832  result[i] = aa[i];
833  else
834  result[i] = ba[i];
835  }
836  return result;
837  }
838  FC_ASSERT( false, "invalid operation ${a} * ${b}", ("a",a)("b",b) );
839  }
840  variant operator / ( const variant& a, const variant& b )
841  {
842  if( a.is_double() || b.is_double() ) return a.as_double() / b.as_double();
843  if( a.is_int64() || b.is_int64() ) return a.as_int64() / b.as_int64();
844  if( a.is_uint64() || b.is_uint64() ) return a.as_uint64() / b.as_uint64();
845  if( a.is_array() && b.is_array() )
846  {
847  const variants& aa = a.get_array();
848  const variants& ba = b.get_array();
849  variants result;
850  result.reserve( std::max(aa.size(),ba.size()) );
851  auto num = std::max(aa.size(),ba.size());
852  for( unsigned i = 0; i < num; ++i )
853  {
854  if( aa.size() > i && ba.size() > i )
855  result[i] = aa[i] / ba[i];
856  else if( aa.size() > i )
857  result[i] = aa[i];
858  else
859  result[i] = ba[i];
860  }
861  return result;
862  }
863  FC_ASSERT( false, "invalid operation ${a} / ${b}", ("a",a)("b",b) );
864  }
865 } // namespace fc
const variants * const_variants_ptr
Definition: variant.cpp:177
double as_double() const
Definition: variant.cpp:420
const std::string & get_string() const
Definition: variant.cpp:575
uint8_t from_hex(char c)
Definition: hex.cpp:6
bool operator<=(const variant &a, const variant &b)
Definition: variant.cpp:752
bool is_bool() const
Definition: variant.cpp:318
bool is_numeric() const
Definition: variant.cpp:348
bool is_double() const
Definition: variant.cpp:322
An order-perserving dictionary of variant&#39;s.
bool is_array() const
Definition: variant.cpp:368
bool is_null() const
Definition: variant.cpp:309
bool is_blob() const
Definition: variant.cpp:372
std::vector< variant > variants
Definition: variant.hpp:170
auto operator+(const fwd< T, S, A > &x, U &&u) -> typename detail::add< T, U >::type
Definition: fwd_impl.hpp:44
bool operator!(const variant &a)
Definition: variant.cpp:729
bool is_int64() const
Definition: variant.cpp:330
const variant_object * const_variant_object_ptr
Definition: variant.cpp:176
int64_t to_int64(const std::string &)
Definition: string.cpp:34
size_t size() const
Definition: variant.cpp:570
std::string base64_encode(unsigned char const *bytes_to_encode, unsigned int in_len)
Definition: base64.cpp:51
uint64_t as_uint64() const
Definition: variant.cpp:398
bool as_bool() const
Definition: variant.cpp:441
blob & get_blob()
Definition: variant.cpp:503
uint64_t uint128_hi64(const uint128_t &x)
Definition: uint128.hpp:57
variant()
Constructs a null_type variant.
Definition: variant.cpp:30
bool operator!=(const optional< T > &left, const optional< T > &right)
Definition: optional.hpp:253
type_id get_type() const
Definition: variant.cpp:304
virtual void handle() const =0
handles null_type variants
variant_object & get_object()
Definition: variant.cpp:554
bool operator==(const optional< T > &left, const optional< T > &right)
Definition: optional.hpp:245
void to_variant(const flat_set< T, A... > &var, variant &vo, uint32_t _max_depth)
Definition: flat.hpp:105
variant & operator=(variant &&v)
Definition: variant.cpp:235
const variant & operator[](const char *) const
Definition: variant.cpp:561
double to_double(const std::string &)
Definition: string.cpp:60
auto operator-(const fwd< T, S, A > &x, U &&u) -> typename detail::sub< T, U >::type
Definition: fwd_impl.hpp:47
#define FC_CAPTURE_AND_RETHROW(...)
Definition: exception.hpp:478
#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
bool is_object() const
Definition: variant.cpp:363
void visit(const visitor &v) const
Definition: variant.cpp:271
uint64_t to_uint64(const std::string &)
Definition: string.cpp:47
variant operator/(const variant &a, const variant &b)
Definition: variant.cpp:840
Defines exception&#39;s used by fc.
bool operator>(const variant &a, const variant &b)
Definition: variant.cpp:743
std::vector< char > data
Definition: variant.hpp:58
variants & get_array()
Definition: variant.cpp:496
int64_t as_int64() const
Definition: variant.cpp:377
void from_variant(const variant &var, flat_set< T, A... > &vo, uint32_t _max_depth)
Definition: flat.hpp:116
const string * const_string_ptr
Definition: variant.cpp:179
blob as_blob() const
Definition: variant.cpp:518
std::string to_string(double)
Definition: string.cpp:73
bool is_integer() const
Definition: variant.cpp:335
bool is_string() const
Definition: variant.cpp:314
uint64_t uint128_lo64(const uint128_t &x)
Definition: uint128.hpp:54
Definition: api.hpp:15
std::string base64_decode(const std::string &encoded_string)
Definition: base64.cpp:96
void clear()
Definition: variant.cpp:181
bool operator<(const variant &a, const variant &b)
Definition: variant.cpp:734
std::string to_hex(const char *d, uint32_t s)
Definition: hex.cpp:17
bool is_uint64() const
Definition: variant.cpp:326
variant operator*(const variant &a, const variant &b)
Definition: variant.cpp:815
const blob * const_blob_ptr
Definition: variant.cpp:178
std::string as_string() const
Definition: variant.cpp:469
An order-perserving dictionary of variant&#39;s.
void set_variant_type(variant *v, variant::type_id t)
Definition: variant.cpp:24