#pragma once #include #include #include #include #include #include #include #include // memset #include #include #include #include #include #include namespace fc { /** * @defgroup serializable Serializable _types * @brief Clas_ses that may be converted to/from an variant * * To make a class 'serializable' the following methods must be available * for your Serializable_type * * @code * void to_variant( const Serializable_type& e, variant& v ); * void from_variant( const variant& e, Serializable_type& ll ); * @endcode */ class variant; class variant_object; class mutable_variant_object; class time_point; class time_point_sec; class microseconds; template struct safe; template class static_variant; struct blob { std::vector data; }; void to_variant( const blob& var, variant& vo ); void from_variant( const variant& var, blob& vo ); template void to_variant( const boost::multi_index_container& s, variant& v ); template void from_variant( const variant& v, boost::multi_index_container& s ); template void to_variant( const smart_ref& s, variant& v ); template void from_variant( const variant& v, smart_ref& s ); template void to_variant( const safe& s, variant& v ); template void from_variant( const variant& v, safe& s ); template void to_variant( const std::unique_ptr& s, variant& v ); template void from_variant( const variant& v, std::unique_ptr& s ); template void to_variant( const static_variant& s, variant& v ); template void from_variant( const variant& v, static_variant& s ); 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 ); void from_variant( const variant& var, int8_t& vo ); void to_variant( const uint16_t& var, variant& vo ); void from_variant( const variant& var, uint16_t& vo ); void to_variant( const int16_t& var, variant& vo ); void from_variant( const variant& var, int16_t& vo ); void to_variant( const uint32_t& var, variant& vo ); void from_variant( const variant& var, uint32_t& vo ); void to_variant( const int32_t& var, variant& vo ); void from_variant( const variant& var, int32_t& vo ); void to_variant( const variant_object& var, variant& vo ); void from_variant( const variant& var, variant_object& vo ); void to_variant( const mutable_variant_object& var, variant& vo ); void from_variant( const variant& var, mutable_variant_object& vo ); void to_variant( const std::vector& var, variant& vo ); void from_variant( const variant& var, std::vector& vo ); template void to_variant( const std::unordered_map& var, variant& vo ); template void from_variant( const variant& var, std::unordered_map& vo ); template void to_variant( const fc::flat_map& var, variant& vo ); template void from_variant( const variant& var, fc::flat_map& vo ); template void to_variant( const std::map& var, variant& vo ); template void from_variant( const variant& var, std::map& vo ); template void to_variant( const std::map& var, variant& vo ); template void from_variant( const variant& var, std::map& vo ); template void to_variant( const std::multimap& var, variant& vo ); template void from_variant( const variant& var, std::multimap& vo ); template void to_variant( const std::unordered_set& var, variant& vo ); template void from_variant( const variant& var, std::unordered_set& vo ); template void to_variant( const std::deque& var, variant& vo ); template void from_variant( const variant& var, std::deque& vo ); template void to_variant( const fc::flat_set& var, variant& vo ); template void from_variant( const variant& var, fc::flat_set& vo ); template void to_variant( const std::set& var, variant& vo ); template void from_variant( const variant& var, std::set& vo ); void to_variant( const time_point& var, variant& vo ); void from_variant( const variant& var, time_point& vo ); void to_variant( const time_point_sec& var, variant& vo ); void from_variant( const variant& var, time_point_sec& vo ); void to_variant( const microseconds& input_microseconds, variant& output_variant ); void from_variant( const variant& input_variant, microseconds& output_microseconds ); #ifdef __APPLE__ void to_variant( size_t s, variant& v ); #elif !defined(_MSC_VER) void to_variant( long long int s, variant& v ); void to_variant( unsigned long long int s, variant& v ); #endif void to_variant( const std::string& s, variant& v ); template void to_variant( const std::shared_ptr& var, variant& vo ); template void from_variant( const variant& var, std::shared_ptr& vo ); typedef std::vector variants; template void to_variant( const std::pair& t, variant& v ); template void from_variant( const variant& v, std::pair& p ); /** * @brief stores null, int64, uint64, double, bool, string, std::vector, * and variant_object's. * * variant's allocate everything but strings, arrays, and objects on the * stack and are 'move aware' for values allcoated on the heap. * * Memory usage on 64 bit systems is 16 bytes and 12 bytes on 32 bit systems. */ class variant { public: enum type_id { null_type = 0, int64_type = 1, uint64_type = 2, double_type = 3, bool_type = 4, string_type = 5, array_type = 6, object_type = 7, blob_type = 8 }; /// Constructs a null_type variant variant(); /// Constructs a null_type variant variant( nullptr_t ); /// @param str - UTF8 string variant( const char* str ); variant( char* str ); variant( wchar_t* str ); variant( const wchar_t* str ); variant( float val ); variant( uint8_t val ); variant( int8_t val ); variant( uint16_t val ); variant( int16_t val ); variant( uint32_t val ); variant( int32_t val ); variant( uint64_t val ); variant( int64_t val ); variant( double val ); variant( bool val ); variant( blob val ); variant( fc::string val ); variant( variant_object ); variant( mutable_variant_object ); variant( variants ); variant( const variant& ); variant( variant&& ); ~variant(); /** * Read-only access to the content of the variant. */ class visitor { public: virtual ~visitor(){} /// handles null_type variants virtual void handle()const = 0; virtual void handle( const int64_t& v )const = 0; virtual void handle( const uint64_t& v )const = 0; virtual void handle( const double& v )const = 0; virtual void handle( const bool& v )const = 0; virtual void handle( const string& v )const = 0; virtual void handle( const variant_object& v)const = 0; virtual void handle( const variants& v)const = 0; }; void visit( const visitor& v )const; type_id get_type()const; bool is_null()const; bool is_string()const; bool is_bool()const; bool is_int64()const; bool is_uint64()const; 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 */ string as_string()const; /// @pre get_type() == string_type const string& get_string()const; /// @throw if get_type() != array_type | null_type variants& get_array(); /// @throw if get_type() != array_type const variants& get_array()const; /// @throw if get_type() != object_type | null_type variant_object& get_object(); /// @throw if get_type() != object_type const variant_object& get_object()const; /// @pre is_object() const variant& operator[]( const char* )const; /// @pre is_array() const variant& operator[]( size_t pos )const; /// @pre is_array() size_t size()const; /** * _types that use non-intrusive variant conversion can implement the * following method to implement conversion from variant to T. * * * void from_variant( const Variant& var, T& val ) * * * The above form is not always convienant, so the this templated * method is used to enable conversion from Variants to other * types. */ template T as()const { T tmp; from_variant( *this, tmp ); return tmp; } variant& operator=( variant&& v ); variant& operator=( const variant& v ); template variant& operator=( T&& v ) { return *this = variant( fc::forward(v) ); } template variant( const optional& v ) { memset( this, 0, sizeof(*this) ); if( v.valid() ) *this = variant(*v); } template explicit variant( const T& val ); void clear(); private: void init(); double _data; ///< Alligned according to double requirements char _type[sizeof(void*)]; ///< pad to void* size }; typedef optional ovariant; /** @ingroup Serializable */ void from_variant( const variant& var, string& vo ); /** @ingroup Serializable */ void from_variant( const variant& var, variants& vo ); void from_variant( const variant& var, variant& vo ); /** @ingroup Serializable */ void from_variant( const variant& var, int64_t& vo ); /** @ingroup Serializable */ void from_variant( const variant& var, uint64_t& vo ); /** @ingroup Serializable */ void from_variant( const variant& var, bool& vo ); /** @ingroup Serializable */ void from_variant( const variant& var, double& vo ); /** @ingroup Serializable */ void from_variant( const variant& var, float& vo ); /** @ingroup Serializable */ void from_variant( const variant& var, int32_t& vo ); /** @ingroup Serializable */ void from_variant( const variant& var, uint32_t& vo ); /** @ingroup Serializable */ template void from_variant( const variant& var, optional& vo ) { if( var.is_null() ) vo = optional(); else { vo = T(); from_variant( var, *vo ); } } template void to_variant( const std::unordered_set& var, variant& vo ) { std::vector vars(var.size()); size_t i = 0; for( auto itr = var.begin(); itr != var.end(); ++itr, ++i ) vars[i] = variant(*itr); vo = vars; } template void from_variant( const variant& var, std::unordered_set& vo ) { const variants& vars = var.get_array(); vo.clear(); vo.reserve( vars.size() ); for( auto itr = vars.begin(); itr != vars.end(); ++itr ) vo.insert( itr->as() ); } template void to_variant( const std::unordered_map& var, variant& vo ) { std::vector< variant > vars(var.size()); size_t i = 0; for( auto itr = var.begin(); itr != var.end(); ++itr, ++i ) vars[i] = fc::variant(*itr); vo = vars; } template void from_variant( const variant& var, std::unordered_map& vo ) { const variants& vars = var.get_array(); vo.clear(); for( auto itr = vars.begin(); itr != vars.end(); ++itr ) vo.insert( itr->as< std::pair >() ); } template void to_variant( const std::map& var, variant& vo ) { std::vector< variant > vars(var.size()); size_t i = 0; for( auto itr = var.begin(); itr != var.end(); ++itr, ++i ) vars[i] = fc::variant(*itr); vo = vars; } template void from_variant( const variant& var, std::map& vo ) { const variants& vars = var.get_array(); vo.clear(); for( auto itr = vars.begin(); itr != vars.end(); ++itr ) vo.insert( itr->as< std::pair >() ); } template void to_variant( const std::multimap& var, variant& vo ) { std::vector< variant > vars(var.size()); size_t i = 0; for( auto itr = var.begin(); itr != var.end(); ++itr, ++i ) vars[i] = fc::variant(*itr); vo = vars; } template void from_variant( const variant& var, std::multimap& vo ) { const variants& vars = var.get_array(); vo.clear(); for( auto itr = vars.begin(); itr != vars.end(); ++itr ) vo.insert( itr->as< std::pair >() ); } template void to_variant( const std::set& var, variant& vo ) { std::vector vars(var.size()); size_t i = 0; for( auto itr = var.begin(); itr != var.end(); ++itr, ++i ) vars[i] = variant(*itr); vo = vars; } template void from_variant( const variant& var, std::set& vo ) { const variants& vars = var.get_array(); vo.clear(); //vo.reserve( vars.size() ); for( auto itr = vars.begin(); itr != vars.end(); ++itr ) vo.insert( itr->as() ); } /** @ingroup Serializable */ template void from_variant( const variant& var, std::deque& tmp ) { const variants& vars = var.get_array(); tmp.clear(); for( auto itr = vars.begin(); itr != vars.end(); ++itr ) tmp.push_back( itr->as() ); } /** @ingroup Serializable */ template void to_variant( const std::deque& t, variant& v ) { std::vector vars(t.size()); for( size_t i = 0; i < t.size(); ++i ) vars[i] = variant(t[i]); v = std::move(vars); } /** @ingroup Serializable */ template void from_variant( const variant& var, std::vector& tmp ) { const variants& vars = var.get_array(); tmp.clear(); tmp.reserve( vars.size() ); for( auto itr = vars.begin(); itr != vars.end(); ++itr ) tmp.push_back( itr->as() ); } /** @ingroup Serializable */ template void to_variant( const std::vector& t, variant& v ) { std::vector vars(t.size()); for( size_t i = 0; i < t.size(); ++i ) vars[i] = variant(t[i]); v = std::move(vars); } /** @ingroup Serializable */ template void to_variant( const std::pair& t, variant& v ) { std::vector vars(2); vars[0] = variant(t.first); vars[1] = variant(t.second); v = vars; } template void from_variant( const variant& v, std::pair& p ) { const variants& vars = v.get_array(); if( vars.size() > 0 ) p.first = vars[0].as(); if( vars.size() > 1 ) p.second = vars[1].as(); } template variant::variant( const T& val ) { memset( this, 0, sizeof(*this) ); to_variant( val, *this ); } #ifdef __APPLE__ inline void to_variant( size_t s, variant& v ) { v = variant(uint64_t(s)); } #endif template void to_variant( const std::shared_ptr& var, variant& vo ) { if( var ) to_variant( *var, vo ); else vo = nullptr; } template void from_variant( const variant& var, std::shared_ptr& vo ) { if( var.is_null() ) vo = nullptr; else if( vo ) from_variant( var, *vo ); else { vo = std::make_shared(); from_variant( var, *vo ); } } template void to_variant( const std::unique_ptr& var, variant& vo ) { if( var ) to_variant( *var, vo ); else vo = nullptr; } template void from_variant( const variant& var, std::unique_ptr& vo ) { if( var.is_null() ) vo.reset(); else if( vo ) from_variant( var, *vo ); else { vo.reset( new T() ); from_variant( var, *vo ); } } template void to_variant( const safe& s, variant& v ) { v = s.value; } template void from_variant( const variant& v, safe& s ) { s.value = v.as_uint64(); } template void to_variant( const smart_ref& s, variant& v ) { v = *s; } template void from_variant( const variant& v, smart_ref& s ) { from_variant( v, *s ); } template void to_variant( const boost::multi_index_container& c, variant& v ) { std::vector vars; vars.reserve( c.size() ); for( const auto& item : c ) vars.emplace_back( variant(item) ); v = std::move(vars); } template void from_variant( const variant& v, boost::multi_index_container& c ) { const variants& vars = v.get_array(); c.clear(); for( const auto& item : vars ) c.insert( item.as() ); } 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_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)(blob_type) ) FC_REFLECT( fc::blob, (data) );