adding blob type to variant

This commit is contained in:
Daniel Larimer 2014-10-15 23:32:37 -04:00
parent ec9e85d268
commit dfe67a4494
4 changed files with 254 additions and 4 deletions

View file

@ -3,6 +3,7 @@
namespace fc {
std::string base64_encode(unsigned char const* bytes_to_encode, unsigned int in_len);
inline std::string base64_encode(char const* bytes_to_encode, unsigned int in_len) { return base64_encode( (unsigned char const*)bytes_to_encode, in_len); }
std::string base64_encode( const std::string& enc );
std::string base64_decode( const std::string& encoded_string);
} // namespace fc

View file

@ -31,6 +31,11 @@ namespace fc
class time_point_sec;
class microseconds;
struct blob { std::vector<char> data; };
void to_variant( const blob& var, variant& vo );
void from_variant( const variant& var, blob& vo );
void to_variant( const uint8_t& var, variant& vo );
void from_variant( const variant& var, uint8_t& vo );
void to_variant( const int8_t& var, variant& vo );
@ -105,6 +110,7 @@ namespace fc
template<typename A, typename B>
void from_variant( const variant& v, std::pair<A,B>& p );
/**
* @brief stores null, int64, uint64, double, bool, string, std::vector<variant>,
* and variant_object's.
@ -126,7 +132,8 @@ namespace fc
bool_type = 4,
string_type = 5,
array_type = 6,
object_type = 7
object_type = 7,
blob_type = 8
};
/// Constructs a null_type variant
@ -150,6 +157,7 @@ namespace fc
variant( int64_t val );
variant( double val );
variant( bool val );
variant( blob val );
variant( fc::string val );
variant( variant_object );
variant( mutable_variant_object );
@ -188,16 +196,25 @@ namespace fc
bool is_double()const;
bool is_object()const;
bool is_array()const;
bool is_blob()const;
/**
* int64, uint64, double,bool
*/
bool is_numeric()const;
/**
* int64, uint64, bool
*/
bool is_integer()const;
int64_t as_int64()const;
uint64_t as_uint64()const;
bool as_bool()const;
double as_double()const;
blob& get_blob();
const blob& get_blob()const;
blob as_blob()const;
/** Convert's double, ints, bools, etc to a string
* @throw if get_type() == array_type | get_type() == object_type
*/
@ -464,8 +481,18 @@ namespace fc
}
}
variant operator + ( const variant& a, const variant& b );
variant operator - ( const variant& a, const variant& b );
variant operator * ( const variant& a, const variant& b );
variant operator / ( const variant& a, const variant& b );
variant operator == ( const variant& a, const variant& b );
variant operator != ( const variant& a, const variant& b );
variant operator < ( const variant& a, const variant& b );
variant operator > ( const variant& a, const variant& b );
variant operator ! ( const variant& a );
} // namespace fc
#include <fc/reflect/reflect.hpp>
FC_REFLECT_TYPENAME( fc::variant )
FC_REFLECT_ENUM( fc::variant::type_id, (null_type)(int64_type)(uint64_type)(double_type)(bool_type)(string_type)(array_type)(object_type) )
FC_REFLECT_ENUM( fc::variant::type_id, (null_type)(int64_type)(uint64_type)(double_type)(bool_type)(string_type)(array_type)(object_type)(blob_type) )
FC_REFLECT( fc::blob, (data) );

View file

@ -534,6 +534,9 @@ namespace fc
case variant::string_type:
escape_string( v.get_string(), os );
return;
case variant::blob_type:
escape_string( v.as_string(), os );
return;
case variant::array_type:
{
const variants& a = v.get_array();

View file

@ -5,7 +5,7 @@
#include <fc/io/json.hpp>
#include <fc/io/stdio.hpp>
#include <string.h>
//#include <fc/crypto/base64.hpp>
#include <fc/crypto/base64.hpp>
#include <fc/crypto/hex.hpp>
#include <boost/scoped_array.hpp>
#include <fc/reflect/variant.hpp>
@ -136,6 +136,11 @@ variant::variant( fc::string val )
*reinterpret_cast<string**>(this) = new string( fc::move(val) );
set_variant_type( this, string_type );
}
variant::variant( blob val )
{
*reinterpret_cast<blob**>(this) = new blob( fc::move(val) );
set_variant_type( this, blob_type );
}
variant::variant( variant_object obj)
{
@ -157,6 +162,7 @@ variant::variant( variants arr )
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()
@ -313,6 +319,19 @@ 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() )
@ -337,6 +356,10 @@ 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
{
@ -437,6 +460,10 @@ string variant::as_string()const
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:
@ -453,6 +480,45 @@ variants& variant::get_array()
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
@ -579,7 +645,6 @@ void from_variant( const variant& var, string& vo )
void to_variant( const std::vector<char>& var, variant& vo )
{
if( var.size() )
//vo = variant(base64_encode((unsigned char*)var.data(),var.size()));
vo = variant(to_hex(var.data(),var.size()));
else vo = "";
}
@ -662,4 +727,158 @@ string format_string( const string& format, const variant_object& args )
void to_variant( unsigned long long int s, variant& v ) { v = variant( uint16_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( uint64_t 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( uint64_t 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( uint64_t 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( uint64_t 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