866 lines
26 KiB
C++
866 lines
26 KiB
C++
#include <fc/variant.hpp>
|
|
#include <fc/variant_object.hpp>
|
|
#include <fc/exception/exception.hpp>
|
|
#include <fc/io/sstream.hpp>
|
|
#include <fc/io/json.hpp>
|
|
#include <fc/io/stdio.hpp>
|
|
#include <string.h>
|
|
#include <fc/crypto/base64.hpp>
|
|
#include <fc/crypto/hex.hpp>
|
|
#include <boost/scoped_array.hpp>
|
|
#include <fc/reflect/variant.hpp>
|
|
#include <algorithm>
|
|
|
|
#if defined(__APPLE__) or defined(__OpenBSD__)
|
|
#include <boost/multiprecision/integer.hpp>
|
|
#endif
|
|
|
|
namespace fc
|
|
{
|
|
|
|
/**
|
|
* The TypeID is stored in the 'last byte' of the variant.
|
|
*/
|
|
void set_variant_type( variant* v, variant::type_id t)
|
|
{
|
|
char* data = reinterpret_cast<char*>(v);
|
|
data[ sizeof(variant) -1 ] = t;
|
|
}
|
|
|
|
variant::variant()
|
|
{
|
|
set_variant_type( this, null_type );
|
|
}
|
|
|
|
variant::variant( std::nullptr_t, uint32_t max_depth )
|
|
{
|
|
set_variant_type( this, null_type );
|
|
}
|
|
|
|
variant::variant( uint8_t val, uint32_t max_depth )
|
|
{
|
|
*reinterpret_cast<uint64_t*>(this) = val;
|
|
set_variant_type( this, uint64_type );
|
|
}
|
|
|
|
variant::variant( int8_t val, uint32_t max_depth )
|
|
{
|
|
*reinterpret_cast<int64_t*>(this) = val;
|
|
set_variant_type( this, int64_type );
|
|
}
|
|
|
|
variant::variant( uint16_t val, uint32_t max_depth )
|
|
{
|
|
*reinterpret_cast<uint64_t*>(this) = val;
|
|
set_variant_type( this, uint64_type );
|
|
}
|
|
|
|
variant::variant( int16_t val, uint32_t max_depth )
|
|
{
|
|
*reinterpret_cast<int64_t*>(this) = val;
|
|
set_variant_type( this, int64_type );
|
|
}
|
|
|
|
variant::variant( uint32_t val, uint32_t max_depth )
|
|
{
|
|
*reinterpret_cast<uint64_t*>(this) = val;
|
|
set_variant_type( this, uint64_type );
|
|
}
|
|
|
|
variant::variant( int32_t val, uint32_t max_depth )
|
|
{
|
|
*reinterpret_cast<int64_t*>(this) = val;
|
|
set_variant_type( this, int64_type );
|
|
}
|
|
|
|
variant::variant( uint64_t val, uint32_t max_depth )
|
|
{
|
|
*reinterpret_cast<uint64_t*>(this) = val;
|
|
set_variant_type( this, uint64_type );
|
|
}
|
|
|
|
#if defined(__APPLE__) or defined(__OpenBSD__)
|
|
variant::variant( size_t val, uint32_t max_depth )
|
|
{
|
|
*reinterpret_cast<uint64_t*>(this) = val;
|
|
set_variant_type( this, uint64_type );
|
|
}
|
|
#endif
|
|
|
|
variant::variant( int64_t val, uint32_t max_depth )
|
|
{
|
|
*reinterpret_cast<int64_t*>(this) = val;
|
|
set_variant_type( this, int64_type );
|
|
}
|
|
|
|
variant::variant( float val, uint32_t max_depth )
|
|
{
|
|
*reinterpret_cast<double*>(this) = val;
|
|
set_variant_type( this, double_type );
|
|
}
|
|
|
|
variant::variant( double val, uint32_t max_depth )
|
|
{
|
|
*reinterpret_cast<double*>(this) = val;
|
|
set_variant_type( this, double_type );
|
|
}
|
|
|
|
variant::variant( bool val, uint32_t max_depth )
|
|
{
|
|
*reinterpret_cast<bool*>(this) = val;
|
|
set_variant_type( this, bool_type );
|
|
}
|
|
|
|
variant::variant( char* str, uint32_t max_depth )
|
|
{
|
|
*reinterpret_cast<string**>(this) = new string( str );
|
|
set_variant_type( this, string_type );
|
|
}
|
|
|
|
variant::variant( const char* str, uint32_t max_depth )
|
|
{
|
|
*reinterpret_cast<string**>(this) = new string( str );
|
|
set_variant_type( this, string_type );
|
|
}
|
|
|
|
// TODO: do a proper conversion to utf8
|
|
variant::variant( wchar_t* str, uint32_t max_depth )
|
|
{
|
|
size_t len = wcslen(str);
|
|
boost::scoped_array<char> buffer(new char[len]);
|
|
for (unsigned i = 0; i < len; ++i)
|
|
buffer[i] = (char)str[i];
|
|
*reinterpret_cast<string**>(this) = new string(buffer.get(), len);
|
|
set_variant_type( this, string_type );
|
|
}
|
|
|
|
// TODO: do a proper conversion to utf8
|
|
variant::variant( const wchar_t* str, uint32_t max_depth )
|
|
{
|
|
size_t len = wcslen(str);
|
|
boost::scoped_array<char> buffer(new char[len]);
|
|
for (unsigned i = 0; i < len; ++i)
|
|
buffer[i] = (char)str[i];
|
|
*reinterpret_cast<string**>(this) = new string(buffer.get(), len);
|
|
set_variant_type( this, string_type );
|
|
}
|
|
|
|
variant::variant( std::string val, uint32_t max_depth )
|
|
{
|
|
*reinterpret_cast<string**>(this) = new string( std::move(val) );
|
|
set_variant_type( this, string_type );
|
|
}
|
|
variant::variant( blob val, uint32_t max_depth )
|
|
{
|
|
*reinterpret_cast<blob**>(this) = new blob( std::move(val) );
|
|
set_variant_type( this, blob_type );
|
|
}
|
|
|
|
variant::variant( variant_object obj, uint32_t max_depth )
|
|
{
|
|
*reinterpret_cast<variant_object**>(this) = new variant_object(std::move(obj));
|
|
set_variant_type(this, object_type );
|
|
}
|
|
variant::variant( mutable_variant_object obj, uint32_t max_depth )
|
|
{
|
|
*reinterpret_cast<variant_object**>(this) = new variant_object(std::move(obj));
|
|
set_variant_type(this, object_type );
|
|
}
|
|
|
|
variant::variant( variants arr, uint32_t max_depth )
|
|
{
|
|
*reinterpret_cast<variants**>(this) = new variants(std::move(arr));
|
|
set_variant_type(this, array_type );
|
|
}
|
|
|
|
typedef const variant_object* const_variant_object_ptr;
|
|
typedef const variants* const_variants_ptr;
|
|
typedef const blob* const_blob_ptr;
|
|
typedef const string* const_string_ptr;
|
|
|
|
void variant::clear()
|
|
{
|
|
switch( get_type() )
|
|
{
|
|
case object_type:
|
|
delete *reinterpret_cast<variant_object**>(this);
|
|
break;
|
|
case array_type:
|
|
delete *reinterpret_cast<variants**>(this);
|
|
break;
|
|
case string_type:
|
|
delete *reinterpret_cast<string**>(this);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
set_variant_type( this, null_type );
|
|
}
|
|
|
|
variant::variant( const variant& v, uint32_t max_depth )
|
|
{
|
|
switch( v.get_type() )
|
|
{
|
|
case object_type:
|
|
*reinterpret_cast<variant_object**>(this) =
|
|
new variant_object(**reinterpret_cast<const const_variant_object_ptr*>(&v));
|
|
set_variant_type( this, object_type );
|
|
return;
|
|
case array_type:
|
|
*reinterpret_cast<variants**>(this) =
|
|
new variants(**reinterpret_cast<const const_variants_ptr*>(&v));
|
|
set_variant_type( this, array_type );
|
|
return;
|
|
case string_type:
|
|
*reinterpret_cast<string**>(this) =
|
|
new string(**reinterpret_cast<const const_string_ptr*>(&v) );
|
|
set_variant_type( this, string_type );
|
|
return;
|
|
default:
|
|
memcpy( this, &v, sizeof(v) );
|
|
}
|
|
}
|
|
|
|
variant::variant( variant&& v, uint32_t max_depth )
|
|
{
|
|
memcpy( this, &v, sizeof(v) );
|
|
set_variant_type( &v, null_type );
|
|
}
|
|
|
|
variant::~variant()
|
|
{
|
|
clear();
|
|
}
|
|
|
|
variant& variant::operator=( variant&& v )
|
|
{
|
|
if( this == &v ) return *this;
|
|
clear();
|
|
memcpy( (char*)this, (char*)&v, sizeof(v) );
|
|
set_variant_type( &v, null_type );
|
|
return *this;
|
|
}
|
|
|
|
variant& variant::operator=( const variant& v )
|
|
{
|
|
if( this == &v )
|
|
return *this;
|
|
|
|
clear();
|
|
switch( v.get_type() )
|
|
{
|
|
case object_type:
|
|
*reinterpret_cast<variant_object**>(this) =
|
|
new variant_object((**reinterpret_cast<const const_variant_object_ptr*>(&v)));
|
|
break;
|
|
case array_type:
|
|
*reinterpret_cast<variants**>(this) =
|
|
new variants((**reinterpret_cast<const const_variants_ptr*>(&v)));
|
|
break;
|
|
case string_type:
|
|
*reinterpret_cast<string**>(this) = new string((**reinterpret_cast<const const_string_ptr*>(&v)) );
|
|
break;
|
|
|
|
default:
|
|
memcpy( this, &v, sizeof(v) );
|
|
}
|
|
set_variant_type( this, v.get_type() );
|
|
return *this;
|
|
}
|
|
|
|
void variant::visit( const visitor& v )const
|
|
{
|
|
switch( get_type() )
|
|
{
|
|
case null_type:
|
|
v.handle();
|
|
return;
|
|
case int64_type:
|
|
v.handle( *reinterpret_cast<const int64_t*>(this) );
|
|
return;
|
|
case uint64_type:
|
|
v.handle( *reinterpret_cast<const uint64_t*>(this) );
|
|
return;
|
|
case double_type:
|
|
v.handle( *reinterpret_cast<const double*>(this) );
|
|
return;
|
|
case bool_type:
|
|
v.handle( *reinterpret_cast<const bool*>(this) );
|
|
return;
|
|
case string_type:
|
|
v.handle( **reinterpret_cast<const const_string_ptr*>(this) );
|
|
return;
|
|
case array_type:
|
|
v.handle( **reinterpret_cast<const const_variants_ptr*>(this) );
|
|
return;
|
|
case object_type:
|
|
v.handle( **reinterpret_cast<const const_variant_object_ptr*>(this) );
|
|
return;
|
|
default:
|
|
FC_THROW_EXCEPTION( assert_exception, "Invalid Type / Corrupted Memory" );
|
|
}
|
|
}
|
|
|
|
variant::type_id variant::get_type()const
|
|
{
|
|
return (type_id)reinterpret_cast<const char*>(this)[sizeof(*this)-1];
|
|
}
|
|
|
|
bool variant::is_null()const
|
|
{
|
|
return get_type() == null_type;
|
|
}
|
|
|
|
bool variant::is_string()const
|
|
{
|
|
return get_type() == string_type;
|
|
}
|
|
bool variant::is_bool()const
|
|
{
|
|
return get_type() == bool_type;
|
|
}
|
|
bool variant::is_double()const
|
|
{
|
|
return get_type() == double_type;
|
|
}
|
|
bool variant::is_uint64()const
|
|
{
|
|
return get_type() == uint64_type;
|
|
}
|
|
bool variant::is_int64()const
|
|
{
|
|
return get_type() == int64_type;
|
|
}
|
|
|
|
bool variant::is_integer()const
|
|
{
|
|
switch( get_type() )
|
|
{
|
|
case int64_type:
|
|
case uint64_type:
|
|
case bool_type:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
return false;
|
|
}
|
|
bool variant::is_numeric()const
|
|
{
|
|
switch( get_type() )
|
|
{
|
|
case int64_type:
|
|
case uint64_type:
|
|
case double_type:
|
|
case bool_type:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool variant::is_object()const
|
|
{
|
|
return get_type() == object_type;
|
|
}
|
|
|
|
bool variant::is_array()const
|
|
{
|
|
return get_type() == array_type;
|
|
}
|
|
bool variant::is_blob()const
|
|
{
|
|
return get_type() == blob_type;
|
|
}
|
|
|
|
int64_t variant::as_int64()const
|
|
{
|
|
switch( get_type() )
|
|
{
|
|
case string_type:
|
|
return to_int64(**reinterpret_cast<const const_string_ptr*>(this));
|
|
case double_type:
|
|
return int64_t(*reinterpret_cast<const double*>(this));
|
|
case int64_type:
|
|
return *reinterpret_cast<const int64_t*>(this);
|
|
case uint64_type:
|
|
return int64_t(*reinterpret_cast<const uint64_t*>(this));
|
|
case bool_type:
|
|
return *reinterpret_cast<const bool*>(this);
|
|
case null_type:
|
|
return 0;
|
|
default:
|
|
FC_THROW_EXCEPTION( bad_cast_exception, "Invalid cast from ${type} to int64", ("type", get_type()) );
|
|
}
|
|
}
|
|
|
|
uint64_t variant::as_uint64()const
|
|
{ try {
|
|
switch( get_type() )
|
|
{
|
|
case string_type:
|
|
return to_uint64(**reinterpret_cast<const const_string_ptr*>(this));
|
|
case double_type:
|
|
return static_cast<uint64_t>(*reinterpret_cast<const double*>(this));
|
|
case int64_type:
|
|
return static_cast<uint64_t>(*reinterpret_cast<const int64_t*>(this));
|
|
case uint64_type:
|
|
return *reinterpret_cast<const uint64_t*>(this);
|
|
case bool_type:
|
|
return static_cast<uint64_t>(*reinterpret_cast<const bool*>(this));
|
|
case null_type:
|
|
return 0;
|
|
default:
|
|
FC_THROW_EXCEPTION( bad_cast_exception,"Invalid cast from ${type} to uint64", ("type",get_type()));
|
|
}
|
|
} FC_CAPTURE_AND_RETHROW( (*this) ) }
|
|
|
|
|
|
double variant::as_double()const
|
|
{
|
|
switch( get_type() )
|
|
{
|
|
case string_type:
|
|
return to_double(**reinterpret_cast<const const_string_ptr*>(this));
|
|
case double_type:
|
|
return *reinterpret_cast<const double*>(this);
|
|
case int64_type:
|
|
return static_cast<double>(*reinterpret_cast<const int64_t*>(this));
|
|
case uint64_type:
|
|
return static_cast<double>(*reinterpret_cast<const uint64_t*>(this));
|
|
case bool_type:
|
|
return *reinterpret_cast<const bool*>(this);
|
|
case null_type:
|
|
return 0;
|
|
default:
|
|
FC_THROW_EXCEPTION( bad_cast_exception, "Invalid cast from ${type} to double", ("type",get_type()) );
|
|
}
|
|
}
|
|
|
|
bool variant::as_bool()const
|
|
{
|
|
switch( get_type() )
|
|
{
|
|
case string_type:
|
|
{
|
|
const string& s = **reinterpret_cast<const const_string_ptr*>(this);
|
|
if( s == "true" )
|
|
return true;
|
|
if( s == "false" )
|
|
return false;
|
|
FC_THROW_EXCEPTION( bad_cast_exception, "Cannot convert string to bool (only \"true\" or \"false\" can be converted)" );
|
|
}
|
|
case double_type:
|
|
return *reinterpret_cast<const double*>(this) != 0.0;
|
|
case int64_type:
|
|
return *reinterpret_cast<const int64_t*>(this) != 0;
|
|
case uint64_type:
|
|
return *reinterpret_cast<const uint64_t*>(this) != 0;
|
|
case bool_type:
|
|
return *reinterpret_cast<const bool*>(this);
|
|
case null_type:
|
|
return false;
|
|
default:
|
|
FC_THROW_EXCEPTION( bad_cast_exception, "Invalid cast from ${type} to bool" , ("type",get_type()));
|
|
}
|
|
}
|
|
|
|
string variant::as_string()const
|
|
{
|
|
switch( get_type() )
|
|
{
|
|
case string_type:
|
|
return **reinterpret_cast<const const_string_ptr*>(this);
|
|
case double_type:
|
|
return to_string(*reinterpret_cast<const double*>(this));
|
|
case int64_type:
|
|
return to_string(*reinterpret_cast<const int64_t*>(this));
|
|
case uint64_type:
|
|
return to_string(*reinterpret_cast<const uint64_t*>(this));
|
|
case bool_type:
|
|
return *reinterpret_cast<const bool*>(this) ? "true" : "false";
|
|
case blob_type:
|
|
if( get_blob().data.size() )
|
|
return base64_encode( get_blob().data.data(), get_blob().data.size() ) + "=";
|
|
return string();
|
|
case null_type:
|
|
return string();
|
|
default:
|
|
FC_THROW_EXCEPTION( bad_cast_exception, "Invalid cast from ${type} to string", ("type", get_type() ) );
|
|
}
|
|
}
|
|
|
|
|
|
/// @throw if get_type() != array_type | null_type
|
|
variants& variant::get_array()
|
|
{
|
|
if( get_type() == array_type )
|
|
return **reinterpret_cast<variants**>(this);
|
|
|
|
FC_THROW_EXCEPTION( bad_cast_exception, "Invalid cast from ${type} to Array", ("type",get_type()) );
|
|
}
|
|
blob& variant::get_blob()
|
|
{
|
|
if( get_type() == blob_type )
|
|
return **reinterpret_cast<blob**>(this);
|
|
|
|
FC_THROW_EXCEPTION( bad_cast_exception, "Invalid cast from ${type} to Blob", ("type",get_type()) );
|
|
}
|
|
const blob& variant::get_blob()const
|
|
{
|
|
if( get_type() == blob_type )
|
|
return **reinterpret_cast<const const_blob_ptr*>(this);
|
|
|
|
FC_THROW_EXCEPTION( bad_cast_exception, "Invalid cast from ${type} to Blob", ("type",get_type()) );
|
|
}
|
|
|
|
blob variant::as_blob()const
|
|
{
|
|
switch( get_type() )
|
|
{
|
|
case null_type: return blob();
|
|
case blob_type: return get_blob();
|
|
case string_type:
|
|
{
|
|
const string& str = get_string();
|
|
if( str.size() == 0 ) return blob();
|
|
if( str.back() == '=' )
|
|
{
|
|
std::string b64 = base64_decode( get_string() );
|
|
return blob( { std::vector<char>( b64.begin(), b64.end() ) } );
|
|
}
|
|
return blob( { std::vector<char>( str.begin(), str.end() ) } );
|
|
}
|
|
case object_type:
|
|
case array_type:
|
|
FC_THROW_EXCEPTION( bad_cast_exception, "Invalid cast from ${type} to Blob", ("type",get_type()) );
|
|
default:
|
|
return blob( { std::vector<char>( (char*)&_data, (char*)&_data + sizeof(_data) ) } );
|
|
}
|
|
}
|
|
|
|
|
|
/// @throw if get_type() != array_type
|
|
const variants& variant::get_array()const
|
|
{
|
|
if( get_type() == array_type )
|
|
return **reinterpret_cast<const const_variants_ptr*>(this);
|
|
FC_THROW_EXCEPTION( bad_cast_exception, "Invalid cast from ${type} to Array", ("type",get_type()) );
|
|
}
|
|
|
|
|
|
/// @throw if get_type() != object_type | null_type
|
|
variant_object& variant::get_object()
|
|
{
|
|
if( get_type() == object_type )
|
|
return **reinterpret_cast<variant_object**>(this);
|
|
FC_THROW_EXCEPTION( bad_cast_exception, "Invalid cast from ${type} to Object", ("type",get_type()) );
|
|
}
|
|
|
|
const variant& variant::operator[]( const char* key )const
|
|
{
|
|
return get_object()[key];
|
|
}
|
|
const variant& variant::operator[]( size_t pos )const
|
|
{
|
|
return get_array()[pos];
|
|
}
|
|
/// @pre is_array()
|
|
size_t variant::size()const
|
|
{
|
|
return get_array().size();
|
|
}
|
|
|
|
const string& variant::get_string()const
|
|
{
|
|
if( get_type() == string_type )
|
|
return **reinterpret_cast<const const_string_ptr*>(this);
|
|
FC_THROW_EXCEPTION( bad_cast_exception, "Invalid cast from type '${type}' to Object", ("type",get_type()) );
|
|
}
|
|
|
|
/// @throw if get_type() != object_type
|
|
const variant_object& variant::get_object()const
|
|
{
|
|
if( get_type() == object_type )
|
|
return **reinterpret_cast<const const_variant_object_ptr*>(this);
|
|
FC_THROW_EXCEPTION( bad_cast_exception, "Invalid cast from type '${type}' to Object", ("type",get_type()) );
|
|
}
|
|
|
|
void from_variant( const variant& var, variants& vo, uint32_t max_depth )
|
|
{
|
|
vo = var.get_array();
|
|
}
|
|
|
|
void from_variant( const variant& var, variant& vo, uint32_t max_depth ) { vo = var; }
|
|
|
|
void to_variant( const uint8_t& var, variant& vo, uint32_t max_depth ) { vo = uint64_t(var); }
|
|
// TODO: warn on overflow?
|
|
void from_variant( const variant& var, uint8_t& vo, uint32_t max_depth ){ vo = static_cast<uint8_t>(var.as_uint64()); }
|
|
|
|
void to_variant( const int8_t& var, variant& vo, uint32_t max_depth ) { vo = int64_t(var); }
|
|
// TODO: warn on overflow?
|
|
void from_variant( const variant& var, int8_t& vo, uint32_t max_depth ) { vo = static_cast<int8_t>(var.as_int64()); }
|
|
|
|
void to_variant( const uint16_t& var, variant& vo, uint32_t max_depth ) { vo = uint64_t(var); }
|
|
// TODO: warn on overflow?
|
|
void from_variant( const variant& var, uint16_t& vo, uint32_t max_depth ){ vo = static_cast<uint16_t>(var.as_uint64()); }
|
|
|
|
void to_variant( const int16_t& var, variant& vo, uint32_t max_depth ) { vo = int64_t(var); }
|
|
// TODO: warn on overflow?
|
|
void from_variant( const variant& var, int16_t& vo, uint32_t max_depth ){ vo = static_cast<int16_t>(var.as_int64()); }
|
|
|
|
void to_variant( const uint32_t& var, variant& vo, uint32_t max_depth ) { vo = uint64_t(var); }
|
|
void from_variant( const variant& var, uint32_t& vo, uint32_t max_depth )
|
|
{
|
|
vo = static_cast<uint32_t>(var.as_uint64());
|
|
}
|
|
|
|
void to_variant( const int32_t& var, variant& vo, uint32_t max_depth ) { vo = int64_t(var); }
|
|
void from_variant( const variant& var,int32_t& vo, uint32_t max_depth )
|
|
{
|
|
vo = static_cast<int32_t>(var.as_int64());
|
|
}
|
|
|
|
void to_variant( const int64_t& var, variant& vo, uint32_t max_depth ) { vo = var; }
|
|
void from_variant( const variant& var, int64_t& vo, uint32_t max_depth )
|
|
{
|
|
vo = var.as_int64();
|
|
}
|
|
|
|
void to_variant( const uint64_t& var, variant& vo, uint32_t max_depth ) { vo = var; }
|
|
void from_variant( const variant& var, uint64_t& vo, uint32_t max_depth )
|
|
{
|
|
vo = var.as_uint64();
|
|
}
|
|
|
|
void to_variant( const bool& var, variant& vo, uint32_t max_depth ) { vo = uint64_t(var); }
|
|
void from_variant( const variant& var, bool& vo, uint32_t max_depth )
|
|
{
|
|
vo = var.as_bool();
|
|
}
|
|
|
|
void from_variant( const variant& var, double& vo, uint32_t max_depth )
|
|
{
|
|
vo = var.as_double();
|
|
}
|
|
|
|
void from_variant( const variant& var, float& vo, uint32_t max_depth )
|
|
{
|
|
vo = static_cast<float>(var.as_double());
|
|
}
|
|
|
|
void to_variant( const std::string& s, variant& v, uint32_t max_depth )
|
|
{
|
|
v = variant( std::string(s), max_depth );
|
|
}
|
|
|
|
void from_variant( const variant& var, string& vo, uint32_t max_depth )
|
|
{
|
|
vo = var.as_string();
|
|
}
|
|
|
|
void to_variant( const std::vector<char>& var, variant& vo, uint32_t max_depth )
|
|
{
|
|
if( var.size() )
|
|
vo = variant(to_hex(var.data(),var.size()));
|
|
else vo = "";
|
|
}
|
|
void from_variant( const variant& var, std::vector<char>& vo, uint32_t max_depth )
|
|
{
|
|
auto str = var.as_string();
|
|
vo.resize( str.size() / 2 );
|
|
if( vo.size() )
|
|
{
|
|
size_t r = from_hex( str, vo.data(), vo.size() );
|
|
FC_ASSERT( r == vo.size() );
|
|
}
|
|
}
|
|
|
|
void to_variant( const uint128_t& var, variant& vo, uint32_t max_depth )
|
|
{
|
|
#if defined(__APPLE__) or defined(__OpenBSD__)
|
|
boost::multiprecision::uint128_t helper = uint128_hi64( var );
|
|
helper <<= 64;
|
|
helper += uint128_lo64( var );
|
|
vo = boost::lexical_cast<std::string>( helper );
|
|
#else
|
|
vo = boost::lexical_cast<std::string>( var );
|
|
#endif
|
|
}
|
|
|
|
void from_variant( const variant& var, uint128_t& vo, uint32_t max_depth )
|
|
{
|
|
#if defined(__APPLE__) or defined(__OpenBSD__)
|
|
boost::multiprecision::uint128_t helper = boost::lexical_cast<boost::multiprecision::uint128_t>( var.as_string() );
|
|
vo = static_cast<uint64_t>( helper >> 64 );
|
|
vo <<= 64;
|
|
vo += static_cast<uint64_t>( helper & 0xffffffffffffffffULL );
|
|
#else
|
|
vo = boost::lexical_cast<uint128_t>( var.as_string() );
|
|
#endif
|
|
}
|
|
|
|
#if defined(__APPLE__)
|
|
#elif defined(__OpenBSD__)
|
|
void to_variant( size_t s, variant& v, uint32_t max_depth ) { v = variant( int64_t(s) ); }
|
|
#elif !defined(_WIN32)
|
|
void to_variant( long long int s, variant& v, uint32_t max_depth ) { v = variant( int64_t(s) ); }
|
|
void to_variant( unsigned long long int s, variant& v, uint32_t max_depth ) { v = variant( uint64_t(s)); }
|
|
#endif
|
|
|
|
bool operator == ( const variant& a, const variant& b )
|
|
{
|
|
if( a.is_string() || b.is_string() ) return a.as_string() == b.as_string();
|
|
if( a.is_double() || b.is_double() ) return a.as_double() == b.as_double();
|
|
if( a.is_int64() || b.is_int64() ) return a.as_int64() == b.as_int64();
|
|
if( a.is_uint64() || b.is_uint64() ) return a.as_uint64() == b.as_uint64();
|
|
return false;
|
|
}
|
|
|
|
bool operator != ( const variant& a, const variant& b )
|
|
{
|
|
if( a.is_string() || b.is_string() ) return a.as_string() != b.as_string();
|
|
if( a.is_double() || b.is_double() ) return a.as_double() != b.as_double();
|
|
if( a.is_int64() || b.is_int64() ) return a.as_int64() != b.as_int64();
|
|
if( a.is_uint64() || b.is_uint64() ) return a.as_uint64() != b.as_uint64();
|
|
return false;
|
|
}
|
|
|
|
bool operator ! ( const variant& a )
|
|
{
|
|
return !a.as_bool();
|
|
}
|
|
|
|
bool operator < ( const variant& a, const variant& b )
|
|
{
|
|
if( a.is_string() || b.is_string() ) return a.as_string() < b.as_string();
|
|
if( a.is_double() || b.is_double() ) return a.as_double() < b.as_double();
|
|
if( a.is_int64() || b.is_int64() ) return a.as_int64() < b.as_int64();
|
|
if( a.is_uint64() || b.is_uint64() ) return a.as_uint64() < b.as_uint64();
|
|
FC_ASSERT( false, "Invalid operation" );
|
|
}
|
|
|
|
bool operator > ( const variant& a, const variant& b )
|
|
{
|
|
if( a.is_string() || b.is_string() ) return a.as_string() > b.as_string();
|
|
if( a.is_double() || b.is_double() ) return a.as_double() > b.as_double();
|
|
if( a.is_int64() || b.is_int64() ) return a.as_int64() > b.as_int64();
|
|
if( a.is_uint64() || b.is_uint64() ) return a.as_uint64() > b.as_uint64();
|
|
FC_ASSERT( false, "Invalid operation" );
|
|
}
|
|
|
|
bool operator <= ( const variant& a, const variant& b )
|
|
{
|
|
if( a.is_string() || b.is_string() ) return a.as_string() <= b.as_string();
|
|
if( a.is_double() || b.is_double() ) return a.as_double() <= b.as_double();
|
|
if( a.is_int64() || b.is_int64() ) return a.as_int64() <= b.as_int64();
|
|
if( a.is_uint64() || b.is_uint64() ) return a.as_uint64() <= b.as_uint64();
|
|
FC_ASSERT( false, "Invalid operation" );
|
|
}
|
|
|
|
|
|
variant operator + ( const variant& a, const variant& b )
|
|
{
|
|
if( a.is_array() && b.is_array() )
|
|
{
|
|
const variants& aa = a.get_array();
|
|
const variants& ba = b.get_array();
|
|
variants result;
|
|
result.reserve( std::max(aa.size(),ba.size()) );
|
|
auto num = std::max(aa.size(),ba.size());
|
|
for( unsigned i = 0; i < num; ++i )
|
|
{
|
|
if( aa.size() > i && ba.size() > i )
|
|
result[i] = aa[i] + ba[i];
|
|
else if( aa.size() > i )
|
|
result[i] = aa[i];
|
|
else
|
|
result[i] = ba[i];
|
|
}
|
|
return result;
|
|
}
|
|
if( a.is_string() || b.is_string() ) return a.as_string() + b.as_string();
|
|
if( a.is_double() || b.is_double() ) return a.as_double() + b.as_double();
|
|
if( a.is_int64() || b.is_int64() ) return a.as_int64() + b.as_int64();
|
|
if( a.is_uint64() || b.is_uint64() ) return a.as_uint64() + b.as_uint64();
|
|
FC_ASSERT( false, "invalid operation ${a} + ${b}", ("a",a)("b",b) );
|
|
}
|
|
|
|
variant operator - ( const variant& a, const variant& b )
|
|
{
|
|
if( a.is_array() && b.is_array() )
|
|
{
|
|
const variants& aa = a.get_array();
|
|
const variants& ba = b.get_array();
|
|
variants result;
|
|
result.reserve( std::max(aa.size(),ba.size()) );
|
|
auto num = std::max(aa.size(),ba.size());
|
|
for( unsigned i = 0; i < num; --i )
|
|
{
|
|
if( aa.size() > i && ba.size() > i )
|
|
result[i] = aa[i] - ba[i];
|
|
else if( aa.size() > i )
|
|
result[i] = aa[i];
|
|
else
|
|
result[i] = ba[i];
|
|
}
|
|
return result;
|
|
}
|
|
if( a.is_string() || b.is_string() ) return a.as_string() - b.as_string();
|
|
if( a.is_double() || b.is_double() ) return a.as_double() - b.as_double();
|
|
if( a.is_int64() || b.is_int64() ) return a.as_int64() - b.as_int64();
|
|
if( a.is_uint64() || b.is_uint64() ) return a.as_uint64() - b.as_uint64();
|
|
FC_ASSERT( false, "invalid operation ${a} + ${b}", ("a",a)("b",b) );
|
|
}
|
|
variant operator * ( const variant& a, const variant& b )
|
|
{
|
|
if( a.is_double() || b.is_double() ) return a.as_double() * b.as_double();
|
|
if( a.is_int64() || b.is_int64() ) return a.as_int64() * b.as_int64();
|
|
if( a.is_uint64() || b.is_uint64() ) return a.as_uint64() * b.as_uint64();
|
|
if( a.is_array() && b.is_array() )
|
|
{
|
|
const variants& aa = a.get_array();
|
|
const variants& ba = b.get_array();
|
|
variants result;
|
|
result.reserve( std::max(aa.size(),ba.size()) );
|
|
auto num = std::max(aa.size(),ba.size());
|
|
for( unsigned i = 0; i < num; ++i )
|
|
{
|
|
if( aa.size() > i && ba.size() > i )
|
|
result[i] = aa[i] * ba[i];
|
|
else if( aa.size() > i )
|
|
result[i] = aa[i];
|
|
else
|
|
result[i] = ba[i];
|
|
}
|
|
return result;
|
|
}
|
|
FC_ASSERT( false, "invalid operation ${a} * ${b}", ("a",a)("b",b) );
|
|
}
|
|
variant operator / ( const variant& a, const variant& b )
|
|
{
|
|
if( a.is_double() || b.is_double() ) return a.as_double() / b.as_double();
|
|
if( a.is_int64() || b.is_int64() ) return a.as_int64() / b.as_int64();
|
|
if( a.is_uint64() || b.is_uint64() ) return a.as_uint64() / b.as_uint64();
|
|
if( a.is_array() && b.is_array() )
|
|
{
|
|
const variants& aa = a.get_array();
|
|
const variants& ba = b.get_array();
|
|
variants result;
|
|
result.reserve( std::max(aa.size(),ba.size()) );
|
|
auto num = std::max(aa.size(),ba.size());
|
|
for( unsigned i = 0; i < num; ++i )
|
|
{
|
|
if( aa.size() > i && ba.size() > i )
|
|
result[i] = aa[i] / ba[i];
|
|
else if( aa.size() > i )
|
|
result[i] = aa[i];
|
|
else
|
|
result[i] = ba[i];
|
|
}
|
|
return result;
|
|
}
|
|
FC_ASSERT( false, "invalid operation ${a} / ${b}", ("a",a)("b",b) );
|
|
}
|
|
} // namespace fc
|