#include #include #include #include #include #include #include #include #include #include #include #include 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(v); data[ sizeof(variant) -1 ] = t; } variant::variant() { set_variant_type( this, null_type ); } variant::variant( fc::nullptr_t, uint32_t max_depth ) { set_variant_type( this, null_type ); } variant::variant( uint8_t val, uint32_t max_depth ) { *reinterpret_cast(this) = val; set_variant_type( this, uint64_type ); } variant::variant( int8_t val, uint32_t max_depth ) { *reinterpret_cast(this) = val; set_variant_type( this, int64_type ); } variant::variant( uint16_t val, uint32_t max_depth ) { *reinterpret_cast(this) = val; set_variant_type( this, uint64_type ); } variant::variant( int16_t val, uint32_t max_depth ) { *reinterpret_cast(this) = val; set_variant_type( this, int64_type ); } variant::variant( uint32_t val, uint32_t max_depth ) { *reinterpret_cast(this) = val; set_variant_type( this, uint64_type ); } variant::variant( int32_t val, uint32_t max_depth ) { *reinterpret_cast(this) = val; set_variant_type( this, int64_type ); } variant::variant( uint64_t val, uint32_t max_depth ) { *reinterpret_cast(this) = val; set_variant_type( this, uint64_type ); } variant::variant( int64_t val, uint32_t max_depth ) { *reinterpret_cast(this) = val; set_variant_type( this, int64_type ); } variant::variant( float val, uint32_t max_depth ) { *reinterpret_cast(this) = val; set_variant_type( this, double_type ); } variant::variant( double val, uint32_t max_depth ) { *reinterpret_cast(this) = val; set_variant_type( this, double_type ); } variant::variant( bool val, uint32_t max_depth ) { *reinterpret_cast(this) = val; set_variant_type( this, bool_type ); } variant::variant( char* str, uint32_t max_depth ) { *reinterpret_cast(this) = new string( str ); set_variant_type( this, string_type ); } variant::variant( const char* str, uint32_t max_depth ) { *reinterpret_cast(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 buffer(new char[len]); for (unsigned i = 0; i < len; ++i) buffer[i] = (char)str[i]; *reinterpret_cast(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 buffer(new char[len]); for (unsigned i = 0; i < len; ++i) buffer[i] = (char)str[i]; *reinterpret_cast(this) = new string(buffer.get(), len); set_variant_type( this, string_type ); } variant::variant( fc::string val, uint32_t max_depth ) { *reinterpret_cast(this) = new string( fc::move(val) ); set_variant_type( this, string_type ); } variant::variant( blob val, uint32_t max_depth ) { *reinterpret_cast(this) = new blob( fc::move(val) ); set_variant_type( this, blob_type ); } variant::variant( variant_object obj, uint32_t max_depth ) { *reinterpret_cast(this) = new variant_object(fc::move(obj)); set_variant_type(this, object_type ); } variant::variant( mutable_variant_object obj, uint32_t max_depth ) { *reinterpret_cast(this) = new variant_object(fc::move(obj)); set_variant_type(this, object_type ); } variant::variant( variants arr, uint32_t max_depth ) { *reinterpret_cast(this) = new variants(fc::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(this); break; case array_type: delete *reinterpret_cast(this); break; case string_type: delete *reinterpret_cast(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(this) = new variant_object(**reinterpret_cast(&v)); set_variant_type( this, object_type ); return; case array_type: *reinterpret_cast(this) = new variants(**reinterpret_cast(&v)); set_variant_type( this, array_type ); return; case string_type: *reinterpret_cast(this) = new string(**reinterpret_cast(&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(this) = new variant_object((**reinterpret_cast(&v))); break; case array_type: *reinterpret_cast(this) = new variants((**reinterpret_cast(&v))); break; case string_type: *reinterpret_cast(this) = new string((**reinterpret_cast(&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(this) ); return; case uint64_type: v.handle( *reinterpret_cast(this) ); return; case double_type: v.handle( *reinterpret_cast(this) ); return; case bool_type: v.handle( *reinterpret_cast(this) ); return; case string_type: v.handle( **reinterpret_cast(this) ); return; case array_type: v.handle( **reinterpret_cast(this) ); return; case object_type: v.handle( **reinterpret_cast(this) ); return; default: FC_THROW_EXCEPTION( assert_exception, "Invalid Type / Corrupted Memory" ); } } variant::type_id variant::get_type()const { return (type_id)reinterpret_cast(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(this)); case double_type: return int64_t(*reinterpret_cast(this)); case int64_type: return *reinterpret_cast(this); case uint64_type: return int64_t(*reinterpret_cast(this)); case bool_type: return *reinterpret_cast(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(this)); case double_type: return static_cast(*reinterpret_cast(this)); case int64_type: return static_cast(*reinterpret_cast(this)); case uint64_type: return *reinterpret_cast(this); case bool_type: return static_cast(*reinterpret_cast(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(this)); case double_type: return *reinterpret_cast(this); case int64_type: return static_cast(*reinterpret_cast(this)); case uint64_type: return static_cast(*reinterpret_cast(this)); case bool_type: return *reinterpret_cast(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(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(this) != 0.0; case int64_type: return *reinterpret_cast(this) != 0; case uint64_type: return *reinterpret_cast(this) != 0; case bool_type: return *reinterpret_cast(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(this); case double_type: return to_string(*reinterpret_cast(this)); case int64_type: return to_string(*reinterpret_cast(this)); case uint64_type: return to_string(*reinterpret_cast(this)); case bool_type: return *reinterpret_cast(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(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(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(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( b64.begin(), b64.end() ) } ); } return blob( { std::vector( 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*)&_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(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(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(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(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(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(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(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(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(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(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 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(var.as_double()); } void to_variant( const std::string& s, variant& v, uint32_t max_depth ) { v = variant( fc::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& 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& 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() ); } } #ifdef __APPLE__ #elif !defined(_MSC_VER) 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 variant 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; } variant 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; } variant operator ! ( const variant& a ) { return !a.as_bool(); } variant 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_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_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