diff --git a/CMakeLists.txt b/CMakeLists.txt index 940ccc1..36b2b3f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -97,6 +97,7 @@ set( sources src/asio.cpp src/super_fast_hash.cpp src/file_mapping.cpp + src/reflect.cpp # src/program_options.cpp ) diff --git a/include/fc/datastream.hpp b/include/fc/datastream.hpp index c003982..d4f965c 100644 --- a/include/fc/datastream.hpp +++ b/include/fc/datastream.hpp @@ -27,7 +27,8 @@ struct datastream { return true; } FC_THROW_REPORT( "Attempt to read ${bytes_past} bytes beyond end of buffer with size ${buffer_size} ", - fc::value().set("bytes_past",int64_t(-((m_end-m_pos) - s))).set("buffer_size", int64_t(m_end-m_start)) ); + fc::value("bytes_past",int64_t(-((m_end-m_pos) - s))) + ("buffer_size", int64_t(m_end-m_start)) ); return false; } @@ -38,7 +39,8 @@ struct datastream { return true; } FC_THROW_REPORT( "Attempt to write ${bytes_past} bytes beyond end of buffer with size ${buffer_size} ", - fc::value().set("bytes_past",int64_t(-((m_end-m_pos) - s))).set("buffer_size", int64_t(m_end-m_start)) ); + fc::value("bytes_past",int64_t(-((m_end-m_pos) - s))) + ("buffer_size", int64_t(m_end-m_start)) ); return false; } @@ -49,8 +51,8 @@ struct datastream { return true; } FC_THROW_REPORT( "Attempt to write ${bytes_past} bytes beyond end of buffer with size ${buffer_size} ", - fc::value().set("bytes_past",int64_t(-((m_end-m_pos) - 1))).set("buffer_size", int64_t(m_end-m_start)) ); - return false; + fc::value("bytes_past",int64_t(-((m_end-m_pos) - 1))) + ("buffer_size", int64_t(m_end-m_start)) ); } inline bool get( unsigned char& c ) { return get( *(char*)&c ); } @@ -61,9 +63,8 @@ struct datastream { return true; } FC_THROW_REPORT( "Attempt to read ${bytes_past} bytes beyond end of buffer of size ${buffer_size} ", - fc::value().set("bytes_past",int64_t(-((m_end-m_pos) - 1))).set("buffer_size", int64_t(m_end-m_start)) ); - ++m_pos; - return false; + fc::value("bytes_past",int64_t(-((m_end-m_pos) - 1))) + ("buffer_size", int64_t(m_end-m_start)) ); } T pos()const { return m_pos; } diff --git a/include/fc/error_report.hpp b/include/fc/error_report.hpp index b7725ec..726f47d 100644 --- a/include/fc/error_report.hpp +++ b/include/fc/error_report.hpp @@ -67,9 +67,10 @@ namespace fc { FC_REFLECT( fc::error_frame, (desc)(file)(line)(method)(time)(meta)(detail) ) FC_REFLECT( fc::error_report, (stack) ) +#define FC_IDENT(...) __VA_ARGS__ #define FC_REPORT( X, ... ) fc::error_report X( __FILE__, __LINE__, __func__, __VA_ARGS__ ) -#define FC_THROW_REPORT( ... ) FC_THROW( fc::error_report( __FILE__, __LINE__, __func__, __VA_ARGS__ )) +#define FC_THROW_REPORT( ... ) FC_THROW( fc::error_report( __FILE__, __LINE__, __func__, __VA_ARGS__ )) #define FC_REPORT_CURRENT(ER, ... ) (ER).pop_frame().push_frame( __FILE__, __LINE__, __func__, __VA_ARGS__ ) #define FC_REPORT_PUSH( ER, ... ) (ER).push_frame( __FILE__, __LINE__, __func__, __VA_ARGS__ ); -#define FC_REPORT_PUSH_DETAIL( ER, ... ) (ER).push_frame( true, __FILE__, __LINE__, __func__, __VA_ARGS__ ) +#define FC_REPORT_PUSH_DETAIL( ER, ... ) (ER).push_frame( true, __FILE__, __LINE__, __func__, __VA_ARGS__ ) #define FC_REPORT_POP(ER) (ER).pop_frame() diff --git a/include/fc/filesystem.hpp b/include/fc/filesystem.hpp index 7f10516..1c3d131 100644 --- a/include/fc/filesystem.hpp +++ b/include/fc/filesystem.hpp @@ -13,6 +13,15 @@ namespace boost { namespace fc { + /** + * @brief wraps boost::filesystem::path to provide platform independent path manipulation. + * + * Most calls are simply a passthrough to boost::filesystem::path, however exceptions are + * wrapped in an fc::error_report and the additional helper method fc::path::windows_string(), + * can be used to calculate paths intended for systems different than the host. + * + * @note Serializes to a fc::value() as the result of generic_string() + */ class path { public: path(); @@ -42,6 +51,13 @@ namespace fc { fc::string string()const; fc::string generic_string()const; + /** + * @brief replaces '/' with '\' in the result of generic_string() + * + * @note not part of boost::filesystem::path + */ + fc::string windows_string()const; + bool is_relative()const; bool is_absolute()const; private: diff --git a/include/fc/reflect.hpp b/include/fc/reflect.hpp index 8358429..54c97fb 100644 --- a/include/fc/reflect.hpp +++ b/include/fc/reflect.hpp @@ -64,7 +64,9 @@ struct reflector{ #endif // DOXYGEN }; - } // namespace fc +void throw_bad_enum_cast( int64_t i, const char* e ); +void throw_bad_enum_cast( const char* k, const char* e ); +} // namespace fc #ifndef DOXYGEN @@ -113,6 +115,7 @@ void fc::reflector::visit( const Visitor& v ) { \ #define FC_REFLECT_ENUM_FROM_STRING( r, enum_type, elem ) \ if( strcmp( s, BOOST_PP_STRINGIZE(elem) ) == 0 ) return enum_type::elem; + #define FC_REFLECT_ENUM( ENUM, FIELDS ) \ namespace fc { \ template<> struct reflector { \ @@ -126,15 +129,14 @@ template<> struct reflector { \ switch( ENUM(i) ) { \ BOOST_PP_SEQ_FOR_EACH( FC_REFLECT_ENUM_TO_STRING, ENUM, FIELDS ) \ default: \ - FC_THROW_REPORT( "Unknown field ${field} not in enum ${enum}", \ - fc::value().set("field",i).set("enum",BOOST_PP_STRINGIZE(ENUM)) ); \ + fc::throw_bad_enum_cast( i, BOOST_PP_STRINGIZE(ENUM) ); \ }\ return nullptr; \ } \ static ENUM from_string( const char* s ) { \ BOOST_PP_SEQ_FOR_EACH( FC_REFLECT_ENUM_FROM_STRING, ENUM, FIELDS ) \ - FC_THROW_REPORT( "Unknown field ${field} not in enum ${enum}", \ - fc::value().set("field",s).set("enum",BOOST_PP_STRINGIZE(ENUM)) ); \ + fc::throw_bad_enum_cast( s, BOOST_PP_STRINGIZE(ENUM) ); \ + return ENUM();\ } \ }; \ } diff --git a/include/fc/thread.hpp b/include/fc/thread.hpp index 37a5b21..3fb1634 100644 --- a/include/fc/thread.hpp +++ b/include/fc/thread.hpp @@ -105,11 +105,11 @@ namespace fc { ~thread(); template - int wait_any( const fc::future& f1, const fc::future& f2) { + int wait_any( const fc::future& f1, const fc::future& f2, const microseconds& timeout_us = microseconds::max()) { fc::vector proms(2); proms[0] = fc::static_pointer_cast(f1.m_prom); proms[1] = fc::static_pointer_cast(f2.m_prom); - return wait_any_until(fc::move(proms), fc::time_point::max() ); + return wait_any_until(fc::move(proms), fc::time_point::now()+timeout_us ); } private: thread( class thread_d* ); @@ -162,8 +162,8 @@ namespace fc { * @return 0 if f1 is ready, 1 if f2 is ready or throw on error. */ template - int wait_any( const fc::future& f1, const fc::future& f2) { - return fc::thread::current().wait_any(f1,f2); + int wait_any( const fc::future& f1, const fc::future& f2, const microseconds timeout_us = microseconds::max()) { + return fc::thread::current().wait_any(f1,f2,timeout_us); } int wait_any( fc::vector&& v, const microseconds& timeout_us = microseconds::max() ); int wait_any_until( fc::vector&& v, const time_point& tp ); diff --git a/include/fc/thread_d.hpp b/include/fc/thread_d.hpp index 7f42837..8a0c245 100644 --- a/include/fc/thread_d.hpp +++ b/include/fc/thread_d.hpp @@ -217,12 +217,12 @@ namespace fc { // check to see if any other contexts are ready if( ready_head ) { cmt::context* next = ready_pop_front(); - BOOST_ASSERT( next != current ); - if( reschedule ) ready_push_back(current); - // jump to next context, saving current context cmt::context* prev = current; current = next; + if( reschedule ) ready_push_back(current); + + slog( "jump from %p to %p", prev, next ); bc::jump_fcontext( &prev->my_context, &next->my_context, 0 ); current = prev; BOOST_ASSERT( current ); @@ -241,6 +241,7 @@ namespace fc { } cmt::context* prev = current; current = next; + slog( "jump from %p to %p", prev, next ); bc::jump_fcontext( &prev->my_context, &next->my_context, (intptr_t)this ); current = prev; BOOST_ASSERT( current ); diff --git a/include/fc/value.hpp b/include/fc/value.hpp index 104c9c1..bade623 100644 --- a/include/fc/value.hpp +++ b/include/fc/value.hpp @@ -25,134 +25,138 @@ namespace fc { */ class value { public: - class key_val; - class object { - public: - typedef fc::vector::const_iterator const_iterator; - //fc::string type; - fc::vector fields; - }; - class array { - public: - array( size_t s = 0 ):fields(s){} - fc::vector fields; + enum value_type { + null_type, string_type, bool_type, + int8_type, int16_type, int32_type, int64_type, + uint8_type, uint16_type, uint32_type, uint64_type, + double_type, float_type, + array_type, object_type }; + class key_val; + class object { + public: + typedef fc::vector::const_iterator const_iterator; + fc::vector fields; + }; + typedef fc::vector array; + struct const_visitor { - virtual void operator()( const int8_t& v ){}; - virtual void operator()( const int16_t& v ){}; - virtual void operator()( const int32_t& v ){}; - virtual void operator()( const int64_t& v ){}; - virtual void operator()( const uint8_t& v ){}; - virtual void operator()( const uint16_t& v ){}; - virtual void operator()( const uint32_t& v ){}; - virtual void operator()( const uint64_t& v ){}; - virtual void operator()( const float& v ){}; - virtual void operator()( const double& v ){}; - virtual void operator()( const bool& v ){}; - virtual void operator()( const fc::string& v ){}; - virtual void operator()( const object& ){}; - virtual void operator()( const array& ){}; - virtual void operator()( ){}; + virtual ~const_visitor(){} + virtual void operator()(const int8_t& v )=0; + virtual void operator()(const int16_t& v )=0; + virtual void operator()(const int32_t& v )=0; + virtual void operator()(const int64_t& v )=0; + virtual void operator()(const uint8_t& v )=0; + virtual void operator()(const uint16_t& v )=0; + virtual void operator()(const uint32_t& v )=0; + virtual void operator()(const uint64_t& v )=0; + virtual void operator()(const float& v )=0; + virtual void operator()(const double& v )=0; + virtual void operator()(const bool& v )=0; + virtual void operator()(const fc::string& v )=0; + virtual void operator()(const object& )=0; + virtual void operator()(const fc::vector& )=0; + virtual void operator()()=0; }; value(); - value( value&& m ); - value( const value& m ); + value(value&& m ); + value(const value& m ); - value( char* c ); - value( int8_t ); - value( int16_t ); - value( int32_t ); - value( int64_t ); - value( uint8_t ); - value( uint16_t ); - value( uint32_t ); - value( uint64_t ); - value( double ); - value( float ); - value( bool ); - value( fc::string&& ); - value( fc::string& ); - value( const fc::string& ); + value(char* c ); + value(int8_t ); + value(int16_t ); + value(int32_t ); + value(int64_t ); + value(uint8_t ); + value(uint16_t ); + value(uint32_t ); + value(uint64_t ); + value(double ); + value(float ); + value(bool ); + /// initialize an object with a single key/value pair + value(const fc::string&, const value& v ); + value(fc::string&& ); + value(fc::string& ); + value(const fc::string& ); - value( object&& o ); - value( const object& o ); - value( object& o ); + value(object&& o ); + value(const object& o ); + value(object& o ); - value( array&& a ); - value( array& a ); - value( const array& a ); + value(fc::vector&& a ); + value(fc::vector& a ); + value(const fc::vector& a ); ~value(); - value& operator=( value&& v ); - value& operator=( const value& v ); + value& operator=(value&& v ); + value& operator=(const value& v ); /** * Include fc/value_cast.hpp for implementation */ template - explicit value( const T& v ); + explicit value(const T& v ); template - value& operator=( const T& v ); + value& operator=( const T& v ); template T cast()const; - /* - { - slog("operator= %p", this); - value tmp(fc::forward(v)); - slog( "swap...tmp %p this %p", &tmp, this ); - T tmp = fc::move(a); - a = fc::move(b); - b = fc::move(tmp); - slog( "return" ); - return *this; - } - */ /** used to iterate over object fields, use array index + size to iterate over array */ - object::const_iterator find( const char* key )const; + object::const_iterator find(const char* key )const; object::const_iterator begin()const; object::const_iterator end()const; /** avoid creating temporary string just for comparisons! **/ - value& operator[]( const char* key ); - const value& operator[]( const char* key )const; - value& operator[]( const fc::string& key ); - const value& operator[]( const fc::string& key )const; + value& operator[](const char* key ); + const value& operator[](const char* key )const; + value& operator[](const fc::string& key ); + const value& operator[](const fc::string& key )const; /** array & object interface **/ void clear(); size_t size()const; /** array interface **/ - void resize( size_t s ); - void reserve( size_t s ); - value& push_back( value&& v ); - value& push_back( const value& v ); - value& operator[]( int32_t idx ); - const value& operator[]( int32_t idx )const; + void resize(size_t s ); + void reserve(size_t s ); + value& push_back(value&& v ); + value& push_back(const value& v ); + const fc::vector& as_array()const; + fc::vector& as_array(); + const fc::string& as_string()const; + fc::string& as_string(); + const value::object& as_object()const; + value::object& as_object(); + + /** same as push_back(), used for short-hand construction of value()(1)(2)(3)(4) */ + value& operator()(fc::value v ); + value& operator[](int32_t idx ); + const value& operator[](int32_t idx )const; /** gets the stored type **/ - const char* type()const; + value_type type()const; bool is_null()const; bool is_string()const; bool is_object()const; bool is_array()const; - void visit( const_visitor&& v )const; + void visit(const_visitor&& v )const; - /* sets the subkey key with v and return *this */ - value& set( const char* key, fc::value v ); - value& set( const fc::string& key, fc::value v ); - value& clear( const fc::string& key ); + /** same as set(key, v ), used for short-hand construction of value()("key",1)("key2",2) */ + value& operator()(const char* key, fc::value v ); + value& set(const char* key, fc::value v ); + value& set(const fc::string& key, fc::value v ); + value& clear(const fc::string& key ); template - value& set( S&& key, T&& v ) { return set( fc::forward(key), fc::value( fc::forward(v) ) ); } + value& set(S&& key, T&& v ) { return set(fc::forward(key), fc::value(fc::forward(v) ) ); } private: /** throws exceptions on errors @@ -161,46 +165,40 @@ namespace fc { * reflection */ template - friend T value_cast( const value& v ); + friend T value_cast(const value& v ); aligned<40> holder; }; typedef fc::optional ovalue; - bool operator == ( const value& v, std::nullptr_t ); - bool operator != ( const value& v, std::nullptr_t ); + bool operator == (const value& v, std::nullptr_t ); + bool operator != (const value& v, std::nullptr_t ); class value::key_val { public: key_val(){}; - key_val( fc::string k ) + key_val(fc::string k ) :key(fc::move(k)){} - // key_val( fc::string k, value v ) - // :key(fc::move(k)),val(fc::move(v)){ - // slog("key_val(key,val)");} - - key_val( const fc::string& k, const value& v ) + key_val(const fc::string& k, const value& v ) :key(k),val(v){} - key_val( key_val&& m ) + key_val(key_val&& m ) :key(fc::move(m.key)),val(fc::move(m.val)){ } - key_val( const key_val& m ) + key_val(const key_val& m ) :key(m.key),val(m.val){} ~key_val(){ } - key_val& operator=( key_val&& k ) { - fc_swap( key, k.key ); - fc_swap( val, k.val ); + key_val& operator=(key_val&& k ) { + fc_swap(key, k.key ); + fc_swap(val, k.val ); return *this; } - key_val& operator=( const key_val& k ) { - slog( "copy key"); + key_val& operator=(const key_val& k ) { key = k.key; - slog( "copy val"); val = k.val; return *this; } @@ -211,3 +209,21 @@ namespace fc { } // namespace fc +#include +FC_REFLECT_ENUM(fc::value::value_type, + (null_type) + (string_type) + (bool_type) + (int8_type) + (int16_type) + (int32_type) + (int64_type) + (uint8_type) + (uint16_type) + (uint32_type) + (uint64_type) + (double_type) + (float_type) + (array_type) + (object_type) +) diff --git a/include/fc/value_cast.hpp b/include/fc/value_cast.hpp index 6c4968c..52aaa55 100644 --- a/include/fc/value_cast.hpp +++ b/include/fc/value_cast.hpp @@ -16,212 +16,54 @@ namespace fc { namespace detail { - template - struct cast_visitor : value::const_visitor { - cast_visitor( T& out ) - :m_out(out){} - virtual void operator()( const int8_t& v ) { m_out = fc::numeric_cast(v); } - virtual void operator()( const int16_t& v ) { m_out = fc::numeric_cast(v); } - virtual void operator()( const int32_t& v ) { m_out = fc::numeric_cast(v); } - virtual void operator()( const int64_t& v ) { m_out = fc::numeric_cast(v); } - virtual void operator()( const uint8_t& v ) { m_out = fc::numeric_cast(v); } - virtual void operator()( const uint16_t& v ) { m_out = fc::numeric_cast(v); } - virtual void operator()( const uint32_t& v ) { m_out = fc::numeric_cast(v); } - virtual void operator()( const uint64_t& v ) { m_out = fc::numeric_cast(v); } - virtual void operator()( const float& v ) { m_out = fc::numeric_cast(v); } - virtual void operator()( const double& v ) { m_out = fc::numeric_cast(v); } - virtual void operator()( const bool& v ) { m_out = v; } - virtual void operator()( const fc::string& v ) { m_out = fc::lexical_cast(v); } - virtual void operator()( const value::object& ) { FC_THROW_REPORT("bad cast to ${type} from object", - fc::value().set("type",fc::get_typename::name())); } - virtual void operator()( const value::array& ) { FC_THROW_REPORT("bad cast to ${type} from array", - fc::value().set("type",fc::get_typename::name())); } - virtual void operator()( ) { FC_THROW_REPORT("bad cast to ${type} from null", - fc::value().set("type",fc::get_typename::name())); } - private: - T& m_out; - }; - template<> - struct cast_visitor : value::const_visitor { - cast_visitor( bool& out ) - :m_out(out){} - virtual void operator()( const int8_t& v ){ m_out = v != 0; } - virtual void operator()( const int16_t& v ){ m_out = v != 0; } - virtual void operator()( const int32_t& v ){ m_out = v != 0; } - virtual void operator()( const int64_t& v ){ m_out = v != 0; } - virtual void operator()( const uint8_t& v ){ m_out = v != 0; } - virtual void operator()( const uint16_t& v ){ m_out = v != 0; } - virtual void operator()( const uint32_t& v ){ m_out = v != 0; } - virtual void operator()( const uint64_t& v ){ m_out = v != 0; } - virtual void operator()( const float& v ){ m_out = v != 0; } - virtual void operator()( const double& v ){ m_out = v != 0; } - virtual void operator()( const bool& v ){ m_out = v; } - virtual void operator()( const fc::string& v ) { m_out = !(v != "true"); } - virtual void operator()( const value::object& ) { FC_THROW_REPORT("bad cast to bool from object"); } - virtual void operator()( const value::array& ) { FC_THROW_REPORT("bad cast to bool from array"); } - virtual void operator()( ) { FC_THROW_REPORT("bad cast to bool from null"); } - private: - bool& m_out; - }; - - template<> - struct cast_visitor : value::const_visitor { - cast_visitor( fc::string& out ) - :m_out(out){} - virtual void operator()( const int8_t& v ) { m_out = fc::lexical_cast(v); } - virtual void operator()( const int16_t& v ) { m_out = fc::lexical_cast(v); } - virtual void operator()( const int32_t& v ) { m_out = fc::lexical_cast(v); } - virtual void operator()( const int64_t& v ) { m_out = fc::lexical_cast(v); } - virtual void operator()( const uint8_t& v ) { m_out = fc::lexical_cast(v); } - virtual void operator()( const uint16_t& v ) { m_out = fc::lexical_cast(v); } - virtual void operator()( const uint32_t& v ) { m_out = fc::lexical_cast(v); } - virtual void operator()( const uint64_t& v ) { m_out = fc::lexical_cast(v); } - virtual void operator()( const float& v ) { m_out = fc::lexical_cast(v); } - virtual void operator()( const double& v ) { m_out = fc::lexical_cast(v); } - virtual void operator()( const bool& v ) { m_out = v != 0 ? "true" : "false"; } - virtual void operator()( const fc::string& v ) { m_out = v; } - virtual void operator()( const value::object& ){ FC_THROW_REPORT("bad cast to string from object"); } - virtual void operator()( const value::array& ) { FC_THROW_REPORT("bad cast to string from array"); } - virtual void operator()( ) { m_out = fc::string(); } - - private: - fc::string& m_out; - }; - - template<> - struct cast_visitor : value::const_visitor { - cast_visitor( value::array& out ) - :m_out(out){} - virtual void operator()( const int8_t& v ) { FC_THROW_REPORT("bad cast to array from int8");} - virtual void operator()( const int16_t& v ) { FC_THROW_REPORT("bad cast to array from int16");} - virtual void operator()( const int32_t& v ) { FC_THROW_REPORT("bad cast to array from int32");} - virtual void operator()( const int64_t& v ) { FC_THROW_REPORT("bad cast to array from int32");} - virtual void operator()( const uint8_t& v ) { FC_THROW_REPORT("bad cast to array from uint8");} - virtual void operator()( const uint16_t& v ) { FC_THROW_REPORT("bad cast to array from uint16");} - virtual void operator()( const uint32_t& v ) { FC_THROW_REPORT("bad cast to array from uint32");} - virtual void operator()( const uint64_t& v ) { FC_THROW_REPORT("bad cast to array from uint64");} - virtual void operator()( const float& v ) { FC_THROW_REPORT("bad cast to array from float");} - virtual void operator()( const double& v ) { FC_THROW_REPORT("bad cast to array from double");} - virtual void operator()( const bool& v ) { FC_THROW_REPORT("bad cast to array from bool");} - virtual void operator()( const fc::string& v ) { FC_THROW_REPORT("bad cast to array from string");} - virtual void operator()( const value::object& ) { FC_THROW_REPORT("bad cast to array from object");} - virtual void operator()( const value::array& a ) { m_out = a; } - virtual void operator()( ) { m_out = value::array(); } - - private: - value::array& m_out; - }; - - template<> - struct cast_visitor : value::const_visitor { - cast_visitor( value::object& out ) - :m_out(out){} - virtual void operator()( const int8_t& v ){ FC_THROW_REPORT("bad cast to array from int8");} - virtual void operator()( const int16_t& v ){ FC_THROW_REPORT("bad cast to array from int16");} - virtual void operator()( const int32_t& v ){ FC_THROW_REPORT("bad cast to array from int32");} - virtual void operator()( const int64_t& v ){ FC_THROW_REPORT("bad cast to array from int32");} - virtual void operator()( const uint8_t& v ){ FC_THROW_REPORT("bad cast to array from uint8");} - virtual void operator()( const uint16_t& v ){ FC_THROW_REPORT("bad cast to array from uint16");} - virtual void operator()( const uint32_t& v ){ FC_THROW_REPORT("bad cast to array from uint32");} - virtual void operator()( const uint64_t& v ){ FC_THROW_REPORT("bad cast to array from uint64");} - virtual void operator()( const float& v ){ FC_THROW_REPORT("bad cast to array from float");} - virtual void operator()( const double& v ){ FC_THROW_REPORT("bad cast to array from double");} - virtual void operator()( const bool& v ){ FC_THROW_REPORT("bad cast to array from bool");} - virtual void operator()( const fc::string& v ) { FC_THROW_REPORT("bad cast to array from string");} - virtual void operator()( const value::object& a ) { m_out = a; } - virtual void operator()( const value::array& ) { FC_THROW_REPORT("bad cast");} - virtual void operator()( ) { m_out = value::object(); } - - private: - value::object& m_out; - }; - template<> - struct cast_visitor : value::const_visitor { - cast_visitor( value& out ) - :m_out(out){} - virtual void operator()( const int8_t& v ) { m_out = v; } - virtual void operator()( const int16_t& v ) { m_out = v; } - virtual void operator()( const int32_t& v ) { m_out = v; } - virtual void operator()( const int64_t& v ) { m_out = v; } - virtual void operator()( const uint8_t& v ) { m_out = v; } - virtual void operator()( const uint16_t& v ) { m_out = v; } - virtual void operator()( const uint32_t& v ) { m_out = v; } - virtual void operator()( const uint64_t& v ) { m_out = v; } - virtual void operator()( const float& v ) { m_out = v; } - virtual void operator()( const double& v ) { m_out = v; } - virtual void operator()( const bool& v ) { m_out = v; } - virtual void operator()( const fc::string& v ) { m_out = v; } - virtual void operator()( const value::object& a ) { m_out = a; } - virtual void operator()( const value::array& a ) { m_out = a; } - virtual void operator()( ) { m_out = value(); } - - value& m_out; - }; + void cast_value( const value& v, int8_t& ); + void cast_value( const value& v, int16_t& ); + void cast_value( const value& v, int32_t& ); + void cast_value( const value& v, int64_t& ); + void cast_value( const value& v, uint8_t& ); + void cast_value( const value& v, uint16_t& ); + void cast_value( const value& v, uint32_t& ); + void cast_value( const value& v, uint64_t& ); + void cast_value( const value& v, double& ); + void cast_value( const value& v, float& ); + void cast_value( const value& v, bool& ); + void cast_value( const value& v, fc::string& ); + void cast_value( const value& v, value& ); - template - struct cast_visitor> : value::const_visitor { - cast_visitor( fc::vector& out ) - :m_out(out){} - virtual void operator()( const int8_t& v ) { FC_THROW_REPORT("bad cast to vector from int8");} - virtual void operator()( const int16_t& v ) { FC_THROW_REPORT("bad cast to vector from int16");} - virtual void operator()( const int32_t& v ) { FC_THROW_REPORT("bad cast to vector from int32");} - virtual void operator()( const int64_t& v ) { FC_THROW_REPORT("bad cast to vector from int64");} - virtual void operator()( const uint8_t& v ) { FC_THROW_REPORT("bad cast to vector from uint8");} - virtual void operator()( const uint16_t& v ) { FC_THROW_REPORT("bad cast to vector from uint16");} - virtual void operator()( const uint32_t& v ) { FC_THROW_REPORT("bad cast to vector from uint32");} - virtual void operator()( const uint64_t& v ) { FC_THROW_REPORT("bad cast to vector from uint64");} - virtual void operator()( const float& v ) { FC_THROW_REPORT("bad cast to vector from float");} - virtual void operator()( const double& v ) { FC_THROW_REPORT("bad cast to vector from double");} - virtual void operator()( const bool& v ) { FC_THROW_REPORT("bad cast to vector from bool");} - virtual void operator()( const fc::string& v ) { FC_THROW_REPORT("bad cast to vector from string");} - virtual void operator()( const value::object& a ) { FC_THROW_REPORT("bad cast to vector from object");} - virtual void operator()( const value::array& a ) { - m_out.resize(0); - m_out.reserve( a.fields.size() ); - int idx = 0; - for( auto i = a.fields.begin(); i != a.fields.end(); ++i ) { + template + void cast_value( const value& v, T& t) { + unpack(v,t); + } + + template + void cast_value( const value& v, fc::vector& out ) { + if( v.type() != value::array_type ) { + FC_THROW_REPORT( "Error casting ${type} to array", fc::value("type", fc::reflector::to_string(v.type()) ) ); + } + out.resize(v.size()); + const fc::vector& val = v.as_array(); + auto oitr = out.begin(); + int idx = 0; + for( auto itr = val.begin(); itr != val.end(); ++itr, ++oitr, ++idx ) { try { - m_out.push_back( value_cast( *i ) ); - } catch( fc::error_report& er ) { - throw FC_REPORT_PUSH( er, "Error parsing array index ${index} to ${type}", - fc::value().set("index", idx).set("type",fc::get_typename::name()) ); + *oitr = value_cast(*itr); + // value_cast( *itr, *oitr ); + } catch ( fc::error_report& er ) { + throw FC_REPORT_PUSH( er, "Error casting value[${index}] to ${type}", + fc::value("index",idx) + ("type", fc::get_typename::name()) + ); } - ++idx; - } - } + } + } - virtual void operator()( ) { FC_THROW_REPORT("bad cast");} - - private: - fc::vector& m_out; - }; - - - - template<> - struct cast_visitor : value::const_visitor { - virtual void operator()( const int8_t& v ) { FC_THROW_REPORT("bad cast");} - virtual void operator()( const int16_t& v ) { FC_THROW_REPORT("bad cast");} - virtual void operator()( const int32_t& v ) { FC_THROW_REPORT("bad cast");} - virtual void operator()( const int64_t& v ) { FC_THROW_REPORT("bad cast");} - virtual void operator()( const uint8_t& v ) { FC_THROW_REPORT("bad cast");} - virtual void operator()( const uint16_t& v ) { FC_THROW_REPORT("bad cast");} - virtual void operator()( const uint32_t& v ) { FC_THROW_REPORT("bad cast");} - virtual void operator()( const uint64_t& v ) { FC_THROW_REPORT("bad cast");} - virtual void operator()( const float& v ) { FC_THROW_REPORT("bad cast");} - virtual void operator()( const double& v ) { FC_THROW_REPORT("bad cast");} - virtual void operator()( const bool& v ) { FC_THROW_REPORT("bad cast");} - virtual void operator()( const fc::string& v ) { FC_THROW_REPORT("bad cast");} - virtual void operator()( const value::object& a ) { FC_THROW_REPORT("bad cast");} - virtual void operator()( const value::array& ) { FC_THROW_REPORT("bad cast");} - virtual void operator()( ) { } - }; template struct cast_if_tuple { template static T cast( const value& v ) { typename fc::deduce::type out; - v.visit(cast_visitor(out)); + cast_value(v,out); + // v.visit(cast_visitor(out)); return out; } }; @@ -269,27 +111,7 @@ namespace fc { } }; - class value_visitor; - - struct value_holder { - virtual ~value_holder(); - virtual const char* type()const; - virtual void visit( value::const_visitor&& v )const; - virtual void visit( value_visitor&& v ); - - virtual void clear(); - virtual size_t size()const; - virtual void resize( size_t ); - virtual void reserve( size_t ); - virtual value& at( size_t ); - virtual const value& at( size_t )const; - virtual void push_back( value&& v ); - - virtual value_holder* move_helper( char* c ); - virtual value_holder* copy_helper( char* c )const; - }; - - void new_value_holder_void( value* v ); + void new_value_holder_void( value* v ); } // namespace detail diff --git a/include/fc/value_io.hpp b/include/fc/value_io.hpp index 3e212bc..a817a38 100644 --- a/include/fc/value_io.hpp +++ b/include/fc/value_io.hpp @@ -133,7 +133,7 @@ namespace fc { try { fc::unpack( obj[name], c.*p ); } catch ( fc::error_report& er ) { - throw FC_REPORT_PUSH( er, "Error parsing field '${field_name}'", fc::value().set("field_name",name) ); + throw FC_REPORT_PUSH( er, "Error parsing field '${field_name}'", fc::value("field_name",name) ); } } else { @@ -168,7 +168,7 @@ namespace fc { } template static inline void unpack( const fc::value& jsv, T& v ) { - if( strcmp( jsv.type(), "string" ) == 0 ) { + if( jsv.is_string() ) { v = fc::reflector::from_string( fc::value_cast(jsv).c_str() ); } else { // throw if invalid int, by attempting to convert to string @@ -183,12 +183,10 @@ namespace fc { template static inline void pack(fc::value& s, const T& v ) { v.did_not_implement_reflect_macro(); - wlog( "warning, ignoring unknown type" ); } template static inline void unpack( const fc::value& s, T& v ) { v.did_not_implement_reflect_macro(); - wlog( "warning, ignoring unknown type" ); } }; @@ -230,7 +228,7 @@ namespace fc { } template void unpack( const fc::value& jsv, fc::optional& v ) { - if( strcmp( jsv.type(), "void" ) != 0 ) { + if( !jsv.is_null() ) { T tmp; unpack( jsv, tmp ); v = fc::move(tmp); diff --git a/src/filesystem.cpp b/src/filesystem.cpp index 1fe732b..0b6978e 100644 --- a/src/filesystem.cpp +++ b/src/filesystem.cpp @@ -63,6 +63,17 @@ namespace fc { fc::string path::generic_string()const { return _p->generic_string(); } + /** + * @todo use iterators instead of indexes for + * faster performance + */ + fc::string path::windows_string()const { + auto gs = _p->generic_string(); + for( int i =0 ; i < gs.size(); ++i ) { + if( gs[i] == '/' ) gs[i] = '\\'; + } + return gs; + } fc::string path::string()const { return _p->string().c_str(); diff --git a/src/iostream.cpp b/src/iostream.cpp index f108977..c53e050 100644 --- a/src/iostream.cpp +++ b/src/iostream.cpp @@ -82,7 +82,7 @@ namespace fc { i.read( &c, 1 ); while( !i.eof() ) { if( c == delim ) { s = ss.str(); return i; } - ss.write(&c,1); + if( c != '\r' ) ss.write(&c,1); i.read( &c, 1 ); } s = ss.str(); diff --git a/src/json.cpp b/src/json.cpp index a6b93a8..c187bb9 100644 --- a/src/json.cpp +++ b/src/json.cpp @@ -455,7 +455,7 @@ void read_values( fc::value::array& a, char* in, char* end, error_collector& ec } if( v == ve ) return; // no values - { temp_set temp(ve,'\0'); a.fields.push_back( to_value( v, ve, ec ) ); } + { temp_set temp(ve,'\0'); a.push_back( to_value( v, ve, ec ) ); } char* c; char* ce = 0; @@ -470,7 +470,7 @@ void read_values( fc::value::array& a, char* in, char* end, error_collector& ec if( *c != ',' ) // we got a value when expecting ',' { wlog( "missing ," ); - temp_set temp(ce,'\0'); a.fields.push_back( to_value(c, ce, ec) ); + temp_set temp(ce,'\0'); a.push_back( to_value(c, ce, ec) ); ve = ce; continue; // start back at start } @@ -487,7 +487,7 @@ void read_values( fc::value::array& a, char* in, char* end, error_collector& ec wlog( "trailing comma at c->ce" ); } else { // got value temp_set temp(ve,'\0'); - a.fields.push_back( to_value( v, ve, ec) ); + a.push_back( to_value( v, ve, ec) ); } } while( ve < end );// expect comma + value | '' } @@ -977,9 +977,9 @@ fc::string pretty_print( fc::vector&& v, uint8_t indent ) { } virtual void operator()( const value::array& o ){ os << '['; - for( uint32_t i = 0; i < o.fields.size(); ++i ) { - if( i ) os <<','; - o.fields[i].visit( value_visitor(*this) ); + for( auto i = o.begin(); i != o.end(); ++i ) { + if( i != o.begin() ) os <<','; + i->visit( value_visitor(*this) ); } os << ']'; } diff --git a/src/reflect.cpp b/src/reflect.cpp new file mode 100644 index 0000000..b5897fe --- /dev/null +++ b/src/reflect.cpp @@ -0,0 +1,12 @@ +#include + +namespace fc { + void throw_bad_enum_cast( int64_t i, const char* e ) { + FC_THROW_REPORT( "Unknown field ${field} not in enum ${enum}", + fc::value().set("field",i).set("enum",e) ); + } + void throw_bad_enum_cast( const char* k, const char* e ){ + FC_THROW_REPORT( "Field '${field}' not in enum ${enum}", + fc::value().set("field",k).set("enum",e) ); + } +} diff --git a/src/ssh.cpp b/src/ssh.cpp index 8d7cf48..15e44c6 100644 --- a/src/ssh.cpp +++ b/src/ssh.cpp @@ -11,10 +11,12 @@ #include #include #include +#include #include #include #include #include +#include #include #include #include @@ -73,6 +75,11 @@ namespace fc { namespace ssh { class client_impl : public fc::retainable { public: + client_impl() { + sftp = nullptr; + session = nullptr; + knownhosts = nullptr; + } LIBSSH2_SESSION* session; LIBSSH2_KNOWNHOSTS* knownhosts; LIBSSH2_SFTP* sftp; @@ -104,6 +111,7 @@ namespace fc { namespace ssh { char buf[1024]; client_impl* self = (client_impl*)*abstract; + //slog( "Keyboard-interactive authentication" ); // printf("Performing keyboard-interactive authentication.\n"); // printf("Authentication name: '"); @@ -158,13 +166,25 @@ namespace fc { namespace ssh { } sock.reset( new boost::asio::ip::tcp::socket( fc::asio::default_io_service() ) ); + bool resolved = false; for( uint32_t i = 0; i < eps.size(); ++i ) { try { + boost::system::error_code ec; + std::stringstream ss; ss << eps[i]; + slog( "Attempting to connect to %s", ss.str().c_str() ); fc::asio::tcp::connect( *sock, eps[i] ); endpt = eps[i]; + resolved = true; break; - } catch ( ... ) {} + } catch ( ... ) { + wlog( "%s", fc::except_str().c_str() ); + sock->close(); + } } + if( !resolved ) { + FC_THROW_REPORT( "Unable to connect to any resolved endpoint for ${host}:${port}", + fc::value().set("host", hostname).set("port",port) ); + } session = libssh2_session_init(); *libssh2_session_abstract(session) = this; @@ -180,14 +200,20 @@ namespace fc { namespace ssh { FC_THROW_REPORT( "SSH Handshake error: ${code} - ${message}", fc::value().set("code",ec).set("message", msg) ); } - /*const char* fingerprint = */libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_SHA1); + const char* fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_SHA1); + //slog( "fingerprint: %s", fingerprint ); // try to authenticate, throw on error. authenticate(); + //slog("."); } catch ( error_report& er ) { + elog( "%s", er.to_detail_string().c_str() ); close(); throw FC_REPORT_PUSH( er, "Unable to connect to ssh server" );; - } + } catch ( ... ) { + close(); + FC_THROW_REPORT( "Unable to connect to ssh server", fc::value().set("exception", fc::except_str() ) ); + } } void close() { @@ -243,6 +269,7 @@ namespace fc { namespace ssh { } void authenticate() { + //slog( "auth" ); try { char * alist = libssh2_userauth_list(session, uname.c_str(),uname.size()); char * msg = 0; @@ -304,6 +331,7 @@ namespace fc { namespace ssh { } // authenticate() bool try_pass() { + //slog( "try pass" ); int ec = libssh2_userauth_password(session, uname.c_str(), upass.c_str() ); while( ec == LIBSSH2_ERROR_EAGAIN ) { wait_on_socket(); @@ -313,6 +341,7 @@ namespace fc { namespace ssh { return !ec; } bool try_keyboard() { + //slog( "try keyboard" ); int ec = libssh2_userauth_keyboard_interactive(session, uname.c_str(), &client_impl::kbd_callback); while( ec == LIBSSH2_ERROR_EAGAIN ) { @@ -324,6 +353,7 @@ namespace fc { namespace ssh { } bool try_pub_key() { + //slog( "try pub key" ); int ec = libssh2_userauth_publickey_fromfile(session, uname.c_str(), pubkey.c_str(), @@ -341,7 +371,13 @@ namespace fc { namespace ssh { return !ec; } + /** + * @todo figure out why this method results in deadlocks... + */ void wait_on_socket() { + fc::usleep( fc::microseconds(10000) ); + return; + auto dir = libssh2_session_block_directions(session); if( !dir ) return; @@ -384,10 +420,12 @@ namespace fc { namespace ssh { // elog( "************* Attempt to wait in either direction currently waits for both directions ****** " ); //wlog( "rprom %1% wprom %2%", rprom.get(), write_prom.get() ); // wlog( "wait on read %1% or write %2% ", rprom.get(), wprom.get() ); + wlog( "wait both dir" ); + typedef fc::future fprom; fprom fw(wprom); fprom fr(rprom); - int r = fc::wait_any( fw, fr ); + int r = fc::wait_any( fw, fr, fc::seconds(5) ); switch( r ) { case 0: break; @@ -506,6 +544,7 @@ namespace fc { namespace ssh { // memory map the file size_t fsize = file_size(local_path); if( fsize == 0 ) { + elog( "file size %d", fsize ); // TODO: handle empty file case if( progress ) progress(0,0); return; @@ -549,14 +588,32 @@ namespace fc { namespace ssh { wrote += r; pos += r; } - } catch ( ... ) { + + auto ec = libssh2_channel_send_eof( chan ); + while( ec == LIBSSH2_ERROR_EAGAIN ) { + my->wait_on_socket(); + ec = libssh2_channel_send_eof( chan ); + } + ec = libssh2_channel_wait_eof( chan ); + while( ec == LIBSSH2_ERROR_EAGAIN ) { + my->wait_on_socket(); + ec = libssh2_channel_wait_eof( chan ); + } + + ec = libssh2_channel_close( chan ); + while( ec == LIBSSH2_ERROR_EAGAIN ) { + my->wait_on_socket(); + ec = libssh2_channel_close( chan ); + } + } catch ( error_report& er ) { + wlog( "%s", er.to_detail_string().c_str() ); // clean up chan int ec = libssh2_channel_free(chan ); while( ec == LIBSSH2_ERROR_EAGAIN ) { my->wait_on_socket(); ec = libssh2_channel_free( chan ); } - throw; + throw er; } int ec = libssh2_channel_free( chan ); while( ec == LIBSSH2_ERROR_EAGAIN ) { @@ -729,7 +786,24 @@ namespace fc { namespace ssh { * Blocks until the result code of the process has been returned. */ int process::result() { - return 0; + char* msg = 0; + + int ec = libssh2_channel_wait_eof( my->chan ); + while( ec == LIBSSH2_ERROR_EAGAIN ) { + my->sshc.my->wait_on_socket(); + ec = libssh2_channel_wait_eof( my->chan ); + } + + ec = libssh2_channel_wait_closed( my->chan ); + while( ec == LIBSSH2_ERROR_EAGAIN ) { + my->sshc.my->wait_on_socket(); + ec = libssh2_channel_wait_closed( my->chan ); + } + ec = libssh2_session_last_error( my->sshc.my->session, &msg, 0, 0 ); + if( !ec ) { + FC_THROW_REPORT( "Error waiting on socket to close: ${message}", fc::value().set("message",msg) );//%ec %msg ); + } + return libssh2_channel_get_exit_status( my->chan ); } /** * @brief returns a stream that writes to the procss' stdin @@ -768,6 +842,11 @@ namespace fc { namespace ssh { sshc.my->wait_on_socket(); ec = libssh2_channel_flush_ex( chan, LIBSSH2_CHANNEL_FLUSH_EXTENDED_DATA ); } + ec = libssh2_channel_flush_ex( chan, 0 ); + while( ec == LIBSSH2_ERROR_EAGAIN ) { + sshc.my->wait_on_socket(); + ec = libssh2_channel_flush_ex( chan, 0 ); + } if( ec < 0 ) { FC_THROW_REPORT( "ssh flush failed", fc::value().set( "channel_error", ec) ); } @@ -896,17 +975,6 @@ namespace fc { namespace ssh { { chan = c.my->open_channel(pty_type); - /* - unsigned int rw_size = 0; - int ec = libssh2_channel_receive_window_adjust2(chan, 1024*64, 0, &rw_size ); - while( ec == LIBSSH2_ERROR_EAGAIN ) { - sshc->my->wait_on_socket(); - ec = libssh2_channel_receive_window_adjust2(chan, 1024*64, 0, &rw_size ); - } - elog( "rwindow size %1%", rw_size ); - */ - - int ec = libssh2_channel_handle_extended_data2(chan, LIBSSH2_CHANNEL_EXTENDED_DATA_NORMAL ); while( ec == LIBSSH2_ERROR_EAGAIN ) { sshc.my->wait_on_socket(); @@ -920,6 +988,7 @@ namespace fc { namespace ssh { ec = libssh2_channel_shell(chan); } } else { + //slog( "%s", cmd.c_str() ); ec = libssh2_channel_exec( chan, cmd.c_str() ); while( ec == LIBSSH2_ERROR_EAGAIN ) { sshc.my->wait_on_socket(); @@ -927,6 +996,7 @@ namespace fc { namespace ssh { } } if( ec ) { + elog( "error starting process" ); char* msg = 0; ec = libssh2_session_last_error( sshc.my->session, &msg, 0, 0 ); FC_THROW_REPORT( "exec failed: ${message}", fc::value().set("message",msg).set("code",ec) ); diff --git a/src/thread_d.hpp b/src/thread_d.hpp index 55c2949..5c4d852 100644 --- a/src/thread_d.hpp +++ b/src/thread_d.hpp @@ -9,6 +9,7 @@ #include #include #include +#include namespace fc { struct sleep_priority_less { @@ -33,7 +34,7 @@ namespace fc { cnt++; } ~thread_d(){ - slog( "...%p %s",this,name.c_str() ); + fc_ilog( logger::get("fc_context"), "thread ${name} exited}", ( "name", name) ); } fc::thread& self; boost::thread* boost_thread; @@ -61,6 +62,7 @@ namespace fc { void debug( const fc::string& s ) { + return; boost::unique_lock lock(log_mutex()); std::cerr<<"--------------------- "<next; if( !ready_head ) - ready_tail = 0; - tmp->next = 0; + ready_tail = nullptr; + tmp->next = nullptr; } return tmp; } void ready_push_front( const fc::context::ptr& c ) { - // c->ready_time = time_point::now(); + BOOST_ASSERT( c->next == nullptr ); + BOOST_ASSERT( c != current ); + //if( c == current ) wlog( "pushing current to ready??" ); c->next = ready_head; ready_head = c; if( !ready_tail ) ready_tail = c; } void ready_push_back( const fc::context::ptr& c ) { - // c->ready_time = time_point::now(); + BOOST_ASSERT( c->next == nullptr ); + BOOST_ASSERT( c != current ); + //if( c == current ) wlog( "pushing current to ready??" ); c->next = 0; if( ready_tail ) { ready_tail->next = c; } else { + assert( !ready_head ); ready_head = c; } ready_tail = c; @@ -228,33 +235,45 @@ namespace fc { // check to see if any other contexts are ready if( ready_head ) { fc::context* next = ready_pop_front(); + if( next == current ) { + elog( "next == current... something went wrong" ); + return false; + } BOOST_ASSERT( next != current ); - if( reschedule ) ready_push_back(current); // jump to next context, saving current context fc::context* prev = current; current = next; - bc::jump_fcontext( &prev->my_context, &next->my_context, 0 ); - current = prev; - BOOST_ASSERT( current ); + if( reschedule ) ready_push_back(prev); + // slog( "jump to %p from %p", next, prev ); + fc_dlog( logger::get("fc_context"), "from ${from} to ${to}", ( "from", int64_t(prev) )( "to", int64_t(next) ) ); + bc::jump_fcontext( &prev->my_context, &next->my_context, 0 ); + BOOST_ASSERT( current ); + BOOST_ASSERT( current == prev ); + //current = prev; } else { // all contexts are blocked, create a new context // that will process posted tasks... - if( reschedule ) ready_push_back(current); - - fc::context* next; - if( pt_head ) { + fc::context* prev = current; + + fc::context* next = nullptr; + if( pt_head ) { // grab cached context next = pt_head; pt_head = pt_head->next; next->next = 0; - } else { + } else { // create new context. next = new fc::context( &thread_d::start_process_tasks, stack_alloc, &fc::thread::current() ); } - fc::context* prev = current; + current = next; + if( reschedule ) ready_push_back(prev); + + // slog( "jump to %p from %p", next, prev ); + fc_dlog( logger::get("fc_context"), "from ${from} to ${to}", ( "from", int64_t(prev) )( "to", int64_t(next) ) ); bc::jump_fcontext( &prev->my_context, &next->my_context, (intptr_t)this ); - current = prev; BOOST_ASSERT( current ); + BOOST_ASSERT( current == prev ); + //current = prev; } if( current->canceled ) @@ -360,19 +379,20 @@ namespace fc { if( c->blocking_prom.size() ) { c->timeout_blocking_promises(); } - else { ready_push_front( c ); } + else { + if( c != current ) ready_push_front( c ); + } } return time_point::min(); } void unblock( fc::context* c ) { - if( fc::thread::current().my != this ) { - async( [=](){ unblock(c); } ); - return; - } - ready_push_front(c); + if( fc::thread::current().my != this ) { + async( [=](){ unblock(c); } ); + return; + } + if( c != current ) ready_push_front(c); } - void yield_until( const time_point& tp, bool reschedule ) { check_fiber_exceptions(); diff --git a/src/value.cpp b/src/value.cpp index bfbfa55..c358cae 100644 --- a/src/value.cpp +++ b/src/value.cpp @@ -4,6 +4,7 @@ #include #include + namespace fc { namespace detail { @@ -25,18 +26,270 @@ namespace fc { virtual void operator()( value::array& ){}; virtual void operator()( ){}; }; + template + struct cast_visitor : value::const_visitor { + cast_visitor( T& out ) + :m_out(out){} + virtual void operator()( const int8_t& v ) { m_out = fc::numeric_cast(v); } + virtual void operator()( const int16_t& v ) { m_out = fc::numeric_cast(v); } + virtual void operator()( const int32_t& v ) { m_out = fc::numeric_cast(v); } + virtual void operator()( const int64_t& v ) { m_out = fc::numeric_cast(v); } + virtual void operator()( const uint8_t& v ) { m_out = fc::numeric_cast(v); } + virtual void operator()( const uint16_t& v ) { m_out = fc::numeric_cast(v); } + virtual void operator()( const uint32_t& v ) { m_out = fc::numeric_cast(v); } + virtual void operator()( const uint64_t& v ) { m_out = fc::numeric_cast(v); } + virtual void operator()( const float& v ) { m_out = fc::numeric_cast(v); } + virtual void operator()( const double& v ) { m_out = fc::numeric_cast(v); } + virtual void operator()( const bool& v ) { m_out = v; } + virtual void operator()( const fc::string& v ) { m_out = fc::lexical_cast(v); } + virtual void operator()( const value::object& ) { FC_THROW_REPORT("bad cast to ${type} from object", + fc::value().set("type",fc::get_typename::name())); } + virtual void operator()( const value::array& ) { FC_THROW_REPORT("bad cast to ${type} from array", + fc::value().set("type",fc::get_typename::name())); } + virtual void operator()( ) { FC_THROW_REPORT("bad cast to ${type} from null", + fc::value().set("type",fc::get_typename::name())); } + private: + T& m_out; + }; + + template<> + struct cast_visitor : value::const_visitor { + cast_visitor( bool& out ) + :m_out(out){} + virtual void operator()( const int8_t& v ){ m_out = v != 0; } + virtual void operator()( const int16_t& v ){ m_out = v != 0; } + virtual void operator()( const int32_t& v ){ m_out = v != 0; } + virtual void operator()( const int64_t& v ){ m_out = v != 0; } + virtual void operator()( const uint8_t& v ){ m_out = v != 0; } + virtual void operator()( const uint16_t& v ){ m_out = v != 0; } + virtual void operator()( const uint32_t& v ){ m_out = v != 0; } + virtual void operator()( const uint64_t& v ){ m_out = v != 0; } + virtual void operator()( const float& v ){ m_out = v != 0; } + virtual void operator()( const double& v ){ m_out = v != 0; } + virtual void operator()( const bool& v ){ m_out = v; } + virtual void operator()( const fc::string& v ) { m_out = !(v != "true"); } + virtual void operator()( const value::object& ) { FC_THROW_REPORT("bad cast to bool from object"); } + virtual void operator()( const value::array& ) { FC_THROW_REPORT("bad cast to bool from array"); } + virtual void operator()( ) { FC_THROW_REPORT("bad cast to bool from null"); } + private: + bool& m_out; + }; + + template<> + struct cast_visitor : value::const_visitor { + cast_visitor( fc::string& out ) + :m_out(out){} + virtual void operator()( const int8_t& v ) { m_out = fc::lexical_cast(v); } + virtual void operator()( const int16_t& v ) { m_out = fc::lexical_cast(v); } + virtual void operator()( const int32_t& v ) { m_out = fc::lexical_cast(v); } + virtual void operator()( const int64_t& v ) { m_out = fc::lexical_cast(v); } + virtual void operator()( const uint8_t& v ) { m_out = fc::lexical_cast(v); } + virtual void operator()( const uint16_t& v ) { m_out = fc::lexical_cast(v); } + virtual void operator()( const uint32_t& v ) { m_out = fc::lexical_cast(v); } + virtual void operator()( const uint64_t& v ) { m_out = fc::lexical_cast(v); } + virtual void operator()( const float& v ) { m_out = fc::lexical_cast(v); } + virtual void operator()( const double& v ) { m_out = fc::lexical_cast(v); } + virtual void operator()( const bool& v ) { m_out = v != 0 ? "true" : "false"; } + virtual void operator()( const fc::string& v ) { m_out = v; } + virtual void operator()( const value::object& ){ FC_THROW_REPORT("bad cast to string from object"); } + virtual void operator()( const value::array& ) { FC_THROW_REPORT("bad cast to string from array"); } + virtual void operator()( ) { m_out = fc::string(); } + + private: + fc::string& m_out; + }; + + template<> + struct cast_visitor : value::const_visitor { + cast_visitor( value::array& out ) + :m_out(out){} + virtual void operator()( const int8_t& v ) { FC_THROW_REPORT("bad cast to array from int8");} + virtual void operator()( const int16_t& v ) { FC_THROW_REPORT("bad cast to array from int16");} + virtual void operator()( const int32_t& v ) { FC_THROW_REPORT("bad cast to array from int32");} + virtual void operator()( const int64_t& v ) { FC_THROW_REPORT("bad cast to array from int32");} + virtual void operator()( const uint8_t& v ) { FC_THROW_REPORT("bad cast to array from uint8");} + virtual void operator()( const uint16_t& v ) { FC_THROW_REPORT("bad cast to array from uint16");} + virtual void operator()( const uint32_t& v ) { FC_THROW_REPORT("bad cast to array from uint32");} + virtual void operator()( const uint64_t& v ) { FC_THROW_REPORT("bad cast to array from uint64");} + virtual void operator()( const float& v ) { FC_THROW_REPORT("bad cast to array from float");} + virtual void operator()( const double& v ) { FC_THROW_REPORT("bad cast to array from double");} + virtual void operator()( const bool& v ) { FC_THROW_REPORT("bad cast to array from bool");} + virtual void operator()( const fc::string& v ) { FC_THROW_REPORT("bad cast to array from string");} + virtual void operator()( const value::object& ) { FC_THROW_REPORT("bad cast to array from object");} + virtual void operator()( const value::array& a ) { m_out = a; } + virtual void operator()( ) { m_out = value::array(); } + + private: + value::array& m_out; + }; + + template<> + struct cast_visitor : value::const_visitor { + cast_visitor( value::object& out ) + :m_out(out){} + virtual void operator()( const int8_t& v ){ FC_THROW_REPORT("bad cast to array from int8");} + virtual void operator()( const int16_t& v ){ FC_THROW_REPORT("bad cast to array from int16");} + virtual void operator()( const int32_t& v ){ FC_THROW_REPORT("bad cast to array from int32");} + virtual void operator()( const int64_t& v ){ FC_THROW_REPORT("bad cast to array from int32");} + virtual void operator()( const uint8_t& v ){ FC_THROW_REPORT("bad cast to array from uint8");} + virtual void operator()( const uint16_t& v ){ FC_THROW_REPORT("bad cast to array from uint16");} + virtual void operator()( const uint32_t& v ){ FC_THROW_REPORT("bad cast to array from uint32");} + virtual void operator()( const uint64_t& v ){ FC_THROW_REPORT("bad cast to array from uint64");} + virtual void operator()( const float& v ){ FC_THROW_REPORT("bad cast to array from float");} + virtual void operator()( const double& v ){ FC_THROW_REPORT("bad cast to array from double");} + virtual void operator()( const bool& v ){ FC_THROW_REPORT("bad cast to array from bool");} + virtual void operator()( const fc::string& v ) { FC_THROW_REPORT("bad cast to array from string");} + virtual void operator()( const value::object& a ) { m_out = a; } + virtual void operator()( const value::array& ) { FC_THROW_REPORT("bad cast");} + virtual void operator()( ) { m_out = value::object(); } + + private: + value::object& m_out; + }; + template<> + struct cast_visitor : value::const_visitor { + cast_visitor( value& out ) + :m_out(out){} + virtual void operator()( const int8_t& v ) { m_out = v; } + virtual void operator()( const int16_t& v ) { m_out = v; } + virtual void operator()( const int32_t& v ) { m_out = v; } + virtual void operator()( const int64_t& v ) { m_out = v; } + virtual void operator()( const uint8_t& v ) { m_out = v; } + virtual void operator()( const uint16_t& v ) { m_out = v; } + virtual void operator()( const uint32_t& v ) { m_out = v; } + virtual void operator()( const uint64_t& v ) { m_out = v; } + virtual void operator()( const float& v ) { m_out = v; } + virtual void operator()( const double& v ) { m_out = v; } + virtual void operator()( const bool& v ) { m_out = v; } + virtual void operator()( const fc::string& v ) { m_out = v; } + virtual void operator()( const value::object& a ) { m_out = a; } + virtual void operator()( const value::array& a ) { m_out = a; } + virtual void operator()( ) { m_out = value(); } + + value& m_out; + }; + + template<> + struct cast_visitor : value::const_visitor { + virtual void operator()( const int8_t& v ) { FC_THROW_REPORT("bad cast");} + virtual void operator()( const int16_t& v ) { FC_THROW_REPORT("bad cast");} + virtual void operator()( const int32_t& v ) { FC_THROW_REPORT("bad cast");} + virtual void operator()( const int64_t& v ) { FC_THROW_REPORT("bad cast");} + virtual void operator()( const uint8_t& v ) { FC_THROW_REPORT("bad cast");} + virtual void operator()( const uint16_t& v ) { FC_THROW_REPORT("bad cast");} + virtual void operator()( const uint32_t& v ) { FC_THROW_REPORT("bad cast");} + virtual void operator()( const uint64_t& v ) { FC_THROW_REPORT("bad cast");} + virtual void operator()( const float& v ) { FC_THROW_REPORT("bad cast");} + virtual void operator()( const double& v ) { FC_THROW_REPORT("bad cast");} + virtual void operator()( const bool& v ) { FC_THROW_REPORT("bad cast");} + virtual void operator()( const fc::string& v ) { FC_THROW_REPORT("bad cast");} + virtual void operator()( const value::object& a ) { FC_THROW_REPORT("bad cast");} + virtual void operator()( const value::array& ) { FC_THROW_REPORT("bad cast");} + virtual void operator()( ) { } + }; + + void cast_value( const value& v, int8_t& out ){ + v.visit( cast_visitor(out) ); + } + + void cast_value( const value& v, int16_t& out ){ + v.visit( cast_visitor(out) ); + } + + void cast_value( const value& v, int32_t& out ){ + v.visit( cast_visitor(out) ); + } + + void cast_value( const value& v, int64_t& out ){ + v.visit( cast_visitor(out) ); + } + + void cast_value( const value& v, uint8_t& out ){ + v.visit( cast_visitor(out) ); + } + + void cast_value( const value& v, uint16_t& out ){ + v.visit( cast_visitor(out) ); + } + + void cast_value( const value& v, uint32_t& out ){ + v.visit( cast_visitor(out) ); + } + + void cast_value( const value& v, uint64_t& out ){ + v.visit( cast_visitor(out) ); + } + + void cast_value( const value& v, double& out ){ + v.visit( cast_visitor(out) ); + } + + void cast_value( const value& v, float& out ){ + v.visit( cast_visitor(out) ); + } + + void cast_value( const value& v, bool& out ){ + v.visit( cast_visitor(out) ); + } + + void cast_value( const value& v, fc::string& out ){ + v.visit( cast_visitor(out) ); + } + + void cast_value( const value& v, value& out ){ + out = v; + } + + + struct value_holder { + virtual ~value_holder(); + virtual value::value_type type()const; + const char* get_typename()const { return fc::reflector::to_string(type()); } + virtual void visit( value::const_visitor&& v )const; + virtual void visit( value_visitor&& v ); + + virtual void clear(); + virtual size_t size()const; + virtual void resize( size_t ); + virtual void reserve( size_t ); + virtual value& at( size_t ); + virtual const value& at( size_t )const; + virtual void push_back( value&& v ); + + virtual value_holder* move_helper( char* c ); + virtual value_holder* copy_helper( char* c )const; + }; void value_holder::visit( value::const_visitor&& v )const {v(); } void value_holder::visit( value_visitor&& v ) {v(); } + + template + struct get_value_type{}; + template<> struct get_value_type { static value::value_type type(){ return value::null_type; } }; + template<> struct get_value_type { static value::value_type type(){ return value::int8_type; } }; + template<> struct get_value_type{ static value::value_type type(){ return value::int16_type; } }; + template<> struct get_value_type{ static value::value_type type(){ return value::int32_type; } }; + template<> struct get_value_type{ static value::value_type type(){ return value::int64_type; } }; + template<> struct get_value_type{ static value::value_type type(){ return value::uint8_type; } }; + template<> struct get_value_type{ static value::value_type type(){ return value::uint16_type; } }; + template<> struct get_value_type{ static value::value_type type(){ return value::uint32_type; } }; + template<> struct get_value_type{ static value::value_type type(){ return value::uint64_type; } }; + template<> struct get_value_type{ static value::value_type type(){ return value::double_type; } }; + template<> struct get_value_type{ static value::value_type type(){ return value::float_type; } }; + template<> struct get_value_type{ static value::value_type type(){ return value::string_type; } }; + template<> struct get_value_type{ static value::value_type type(){ return value::bool_type; } }; + template<> struct get_value_type>{ static value::value_type type(){ return value::array_type; } }; + template<> struct get_value_type{ static value::value_type type(){ return value::object_type; } }; // fundamental values... template struct value_holder_impl : value_holder { static_assert( !fc::is_class::value, "only fundamental types can be stored without specialization" ); - value_holder_impl(){ - static_assert( sizeof(value_holder_impl) <= 40, "Validate size" ); - } - virtual const char* type()const { return fc::get_typename::name(); } + + value_holder_impl(){ + static_assert( sizeof(value_holder_impl) <= 40, "Validate size" ); + } + virtual value::value_type type()const { return get_value_type::type(); } virtual void visit( value::const_visitor&& v )const{ v(val); } virtual void visit( value_visitor&& v ) { v(val); } virtual void clear() { val = T(); } @@ -50,31 +303,26 @@ namespace fc { T val; }; + template<> struct value_holder_impl : value_holder { value_holder_impl(){}; virtual void visit( value::const_visitor&& v )const{ v(); } - virtual void visit( value_visitor&& v ) { v(); } - // typedef void_t T; - // virtual const char* type()const { return "void"; } - // virtual void clear() { } - // virtual size_t size()const { return 0; } - - virtual value_holder* move_helper( char* c ){ return new(c) value_holder_impl(); } - virtual value_holder* copy_helper( char* c )const{ return new(c) value_holder_impl();} + virtual void visit( value_visitor&& v ) { v(); } + virtual value_holder* move_helper( char* c ) { return new(c) value_holder_impl(); } + virtual value_holder* copy_helper( char* c )const{ return new(c) value_holder_impl(); } }; - template<> struct value_holder_impl : value_holder { template value_holder_impl( V&& v ):val( fc::forward(v) ){ static_assert( sizeof(value_holder_impl) <= 40, "Validate size" ); - } + } - virtual const char* type()const { return "string"; } + virtual value::value_type type()const { return value::string_type; } virtual void visit( value::const_visitor&& v )const { v(val); } virtual void visit( value_visitor&& v ) { v(val); } @@ -82,15 +330,14 @@ namespace fc { virtual value_holder* copy_helper( char* c )const{ return new(c) value_holder_impl(val); } virtual void clear() { val = fc::string(); } - virtual size_t size()const { return 0; } - + virtual size_t size()const { FC_THROW_REPORT( "Attempt to access string as array" ); } fc::string val; }; template<> struct value_holder_impl : value_holder { - virtual const char* type()const { return "object"; } + virtual value::value_type type()const { return value::object_type; } virtual void visit( value::const_visitor&& v )const; virtual void visit( value_visitor&& v ); virtual value_holder* move_helper( char* c ); @@ -108,7 +355,7 @@ namespace fc { template<> struct value_holder_impl : value_holder { - virtual const char* type()const { return "array"; } + virtual value::value_type type()const { return value::array_type; } virtual void visit( value::const_visitor&& v )const; virtual void visit( value_visitor&& v ); virtual value_holder* move_helper( char* c ); @@ -132,7 +379,7 @@ namespace fc { static_assert( sizeof( value_holder_impl ) <= 40, "sanity check" ); value_holder::~value_holder(){} - const char* value_holder::type()const { return "void"; } + value::value_type value_holder::type()const { return value::null_type; } value_holder* value_holder::move_helper( char* c ) { return new(c) value_holder_impl(); } value_holder* value_holder::copy_helper( char* c )const { return new(c) value_holder_impl(); } @@ -142,27 +389,25 @@ namespace fc { void value_holder::clear() {} size_t value_holder::size()const { return 0; } - void value_holder::resize( size_t ) { FC_THROW_MSG("value type '%s' not an array", type()); } - void value_holder::reserve( size_t ) { FC_THROW_MSG("value type '%s' not an array or object", type()); } - value& value_holder::at( size_t ) { FC_THROW_MSG("value type '%s' not an array", type()); return *((value*)0); } - const value& value_holder::at( size_t )const { FC_THROW_MSG("value type '%s' not an array", type()); return *((const value*)0); } - void value_holder::push_back( value&& v ) { FC_THROW_MSG("value type '%s' not an array", type()); } + void value_holder::resize( size_t ) { FC_THROW_MSG("value type '%s' not an array", get_typename()); } + void value_holder::reserve( size_t ) { FC_THROW_MSG("value type '%s' not an array or object", get_typename()); } + value& value_holder::at( size_t ) { FC_THROW_MSG("value type '%s' not an array", get_typename()); return *((value*)0); } + const value& value_holder::at( size_t )const { FC_THROW_MSG("value type '%s' not an array", get_typename()); return *((const value*)0); } + void value_holder::push_back( value&& v ) { FC_THROW_MSG("value type '%s' not an array", get_typename()); } - // value_holder* value_holder::move_helper( char* c ) = 0; - // value_holder* value_holder::copy_helper( char* c )const = 0; - void value_holder_impl::resize( size_t s ) { val.fields.resize(s); } - void value_holder_impl::reserve( size_t s ) { val.fields.reserve(s); } - value& value_holder_impl::at( size_t i) { return val.fields[i]; } - const value& value_holder_impl::at( size_t i)const { return val.fields[i]; } + void value_holder_impl::resize( size_t s ) { val.resize(s); } + void value_holder_impl::reserve( size_t s ) { val.reserve(s); } + value& value_holder_impl::at( size_t i) { return val[i]; } + const value& value_holder_impl::at( size_t i)const { return val[i]; } value_holder* value_holder_impl::move_helper( char* c ){ return new(c) value_holder_impl( fc::move(val) ); } value_holder* value_holder_impl::copy_helper( char* c )const{ return new(c) value_holder_impl(val); } - void value_holder_impl::clear() { val.fields.clear(); } - size_t value_holder_impl::size()const { return static_cast(val.fields.size()); } + void value_holder_impl::clear() { val.clear(); } + size_t value_holder_impl::size()const { return static_cast(val.size()); } void value_holder_impl::visit( value::const_visitor&& v )const { v(val); } void value_holder_impl::visit( value_visitor&& v ) { v(val); } - void value_holder_impl::push_back( value&& v ) { val.fields.push_back( fc::move(v) ); } + void value_holder_impl::push_back( value&& v ) { val.push_back( fc::move(v) ); } void value_holder_impl::visit( value::const_visitor&& v )const { v(val); } @@ -244,6 +489,11 @@ value::value( const fc::string& v){ static_assert( sizeof(holder) >= sizeof( detail::value_holder_impl ), "size check" ); new (holder) detail::value_holder_impl(v); } +value::value( const fc::string& v, const value& val ) { + static_assert( sizeof(holder) >= sizeof( detail::value_holder_impl ), "size check" ); + new (holder) detail::value_holder_impl(value::object()); + set( v, val ); +} value::value( value::object&& o ){ static_assert( sizeof(holder) >= sizeof( detail::value_holder_impl ), "size check" ); new (holder) detail::value_holder_impl(fc::move(o)); @@ -289,21 +539,64 @@ value& value::operator=( const value& v ){ return *this; } bool value::is_null()const { - return strcmp(gh(holder)->type(), "void") == 0; + return gh(holder)->type() == null_type; } bool value::is_object()const { - return strcmp(gh(holder)->type(), "object") == 0; + return gh(holder)->type() == object_type; } bool value::is_array()const { - return strcmp(gh(holder)->type(), "array") == 0; + return gh(holder)->type() == array_type; } bool value::is_string()const { - return strcmp(gh(holder)->type(), "string") == 0; + return gh(holder)->type() == string_type; +} + +const fc::vector& value::as_array()const { + if( gh(holder)->type() != array_type ) { + FC_THROW_REPORT( "Attempt to dereference value of type ${type} as value array", value("type",gh(holder)->get_typename() ) ); + } + const detail::value_holder_impl* o = static_cast*>(gh(holder)); + return o->val; +} +fc::vector& value::as_array(){ + if( gh(holder)->type() != array_type ) { + FC_THROW_REPORT( "Attempt to dereference value of type ${type} as value array", value("type",gh(holder)->get_typename() ) ); + } + detail::value_holder_impl* o = static_cast*>(gh(holder)); + return o->val; +} +const value::object& value::as_object()const { + if( gh(holder)->type() != object_type ) { + FC_THROW_REPORT( "Attempt to dereference value of type ${type} as value object", value("type",gh(holder)->get_typename() ) ); + } + const detail::value_holder_impl* o = static_cast*>(gh(holder)); + return o->val; +} +value::object& value::as_object(){ + if( gh(holder)->type() != object_type ) { + FC_THROW_REPORT( "Attempt to dereference value of type ${type} as value object", value("type",gh(holder)->get_typename() ) ); + } + detail::value_holder_impl* o = static_cast*>(gh(holder)); + return o->val; +} +const fc::string& value::as_string()const { + if( gh(holder)->type() != string_type ) { + FC_THROW_REPORT( "Attempt to dereference value of type ${type} as value string", value("type",gh(holder)->get_typename() ) ); + } + const detail::value_holder_impl* o = static_cast*>(gh(holder)); + return o->val; +} +fc::string& value::as_string(){ + if( gh(holder)->type() != string_type ) { + FC_THROW_REPORT( "Attempt to dereference value of type ${type} as value string", value("type",gh(holder)->get_typename() ) ); + } + detail::value_holder_impl* o = static_cast*>(gh(holder)); + return o->val; } value::object::const_iterator value::find( const char* key )const { - if( strcmp(gh(holder)->type(), "object") == 0) { + if( gh(holder)->type() == object_type ) { const detail::value_holder_impl* o = static_cast*>(gh(holder)); for( auto i = o->val.fields.begin(); i != o->val.fields.end(); ++i ) { @@ -316,7 +609,7 @@ value::object::const_iterator value::find( const char* key )const { return value::object::const_iterator(); } value::object::const_iterator value::begin()const { - if( strcmp(gh(holder)->type(), "object") == 0 ) { + if( gh(holder)->type() == object_type ) { const detail::value_holder_impl* o = static_cast*>(gh(holder)); return o->val.fields.begin(); } @@ -325,7 +618,7 @@ value::object::const_iterator value::begin()const { //return nullptr; } value::object::const_iterator value::end()const { - if( strcmp(gh(holder)->type(), "object" ) == 0 ) { + if( gh(holder)->type()== object_type ) { const detail::value_holder_impl* o = static_cast*>(gh(holder)); return o->val.fields.end(); } @@ -339,7 +632,7 @@ value::object::const_iterator value::end()const { * @return *this; */ value& value::clear( const fc::string& key ) { - if( strcmp(gh(holder)->type(), "object") == 0) { + if( gh(holder)->type()== object_type ) { detail::value_holder_impl* o = dynamic_cast*>(gh(holder)); for( auto i = o->val.fields.begin(); i != o->val.fields.end(); ++i ) { @@ -352,7 +645,7 @@ value& value::clear( const fc::string& key ) { return *this; } value& value::operator[]( const char* key ) { - if( strcmp(gh(holder)->type(), "object") == 0) { + if( gh(holder)->type()== object_type ) { detail::value_holder_impl* o = dynamic_cast*>(gh(holder)); for( auto i = o->val.fields.begin(); i != o->val.fields.end(); ++i ) { @@ -362,11 +655,11 @@ value& value::operator[]( const char* key ) { o->val.fields.reserve(o->val.fields.size()+1); o->val.fields.push_back( key_val(key) ); return o->val.fields.back().val; - } else if (strcmp(gh(holder)->type(), "void" ) == 0 ) { + } else if (gh(holder)->type() == null_type ) { new (gh(holder)) detail::value_holder_impl(value::object()); return (*this)[key]; } - FC_THROW_REPORT( "Bad cast of ${type} to object", fc::value().set("type",gh(holder)->type()) ); + FC_THROW_REPORT( "Bad cast of ${type} to object", fc::value().set("type", gh(holder)->get_typename()) ); return *((value*)0); } value& value::operator[]( const fc::string& key ) { return (*this)[key.c_str()]; } @@ -392,7 +685,7 @@ void value::reserve( size_t s ) { gh(holder)->reserve(s); } value& value::push_back( value&& v ) { - if (strcmp(gh(holder)->type(), "void" ) == 0 ) { + if (gh(holder)->type() == null_type ) { new (gh(holder)) detail::value_holder_impl(value::array()); return push_back( fc::move(v) ); } @@ -400,7 +693,7 @@ value& value::push_back( value&& v ) { return *this; } value& value::push_back( const value& v ) { - if (strcmp(gh(holder)->type(), "void" ) == 0 ) { + if (gh(holder)->type() == null_type ) { new (gh(holder)) detail::value_holder_impl(value::array()); return push_back( v ); } @@ -414,7 +707,7 @@ const value& value::operator[]( int32_t idx )const { return gh(holder)->at(idx); } -const char* value::type()const { return gh(holder)->type(); } +value::value_type value::type()const { return gh(holder)->type(); } void value::visit( value::const_visitor&& v )const { auto h = ((detail::value_holder*)&holder[0]); @@ -425,6 +718,10 @@ value& value::set( const char* key, fc::value v ) { (*this)[key] = fc::move(v); return *this; } +value& value::operator()( const char* key, fc::value v ) { + (*this)[key] = fc::move(v); + return *this; +} value& value::set( const fc::string& key, fc::value v ) { (*this)[key.c_str()] = fc::move(v); return *this;