Updated fc::value implementation
Improved fc::value to use enum types instead of strings. Moved code from header to cpp file Added extra utility method to simplify syntax for generating key-value pairs for errors/logs. Removed need to create copies when casting strings, arrays, or objects from values
This commit is contained in:
parent
b527bbbab6
commit
25872b11b8
17 changed files with 709 additions and 441 deletions
|
|
@ -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
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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<TYPE>::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<ENUM> { \
|
||||
|
|
@ -126,15 +129,14 @@ template<> struct reflector<ENUM> { \
|
|||
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();\
|
||||
} \
|
||||
}; \
|
||||
}
|
||||
|
|
|
|||
|
|
@ -105,11 +105,11 @@ namespace fc {
|
|||
~thread();
|
||||
|
||||
template<typename T1, typename T2>
|
||||
int wait_any( const fc::future<T1>& f1, const fc::future<T2>& f2) {
|
||||
int wait_any( const fc::future<T1>& f1, const fc::future<T2>& f2, const microseconds& timeout_us = microseconds::max()) {
|
||||
fc::vector<fc::promise_base::ptr> proms(2);
|
||||
proms[0] = fc::static_pointer_cast<fc::promise_base>(f1.m_prom);
|
||||
proms[1] = fc::static_pointer_cast<fc::promise_base>(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<typename T1, typename T2>
|
||||
int wait_any( const fc::future<T1>& f1, const fc::future<T2>& f2) {
|
||||
return fc::thread::current().wait_any(f1,f2);
|
||||
int wait_any( const fc::future<T1>& f1, const fc::future<T2>& f2, const microseconds timeout_us = microseconds::max()) {
|
||||
return fc::thread::current().wait_any(f1,f2,timeout_us);
|
||||
}
|
||||
int wait_any( fc::vector<promise_base::ptr>&& v, const microseconds& timeout_us = microseconds::max() );
|
||||
int wait_any_until( fc::vector<promise_base::ptr>&& v, const time_point& tp );
|
||||
|
|
|
|||
|
|
@ -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 );
|
||||
|
|
|
|||
|
|
@ -25,134 +25,138 @@ namespace fc {
|
|||
*/
|
||||
class value {
|
||||
public:
|
||||
class key_val;
|
||||
class object {
|
||||
public:
|
||||
typedef fc::vector<key_val>::const_iterator const_iterator;
|
||||
//fc::string type;
|
||||
fc::vector<key_val> fields;
|
||||
};
|
||||
class array {
|
||||
public:
|
||||
array( size_t s = 0 ):fields(s){}
|
||||
fc::vector<value> 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<key_val>::const_iterator const_iterator;
|
||||
fc::vector<key_val> fields;
|
||||
};
|
||||
typedef fc::vector<value> 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<value>& )=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<value>&& a );
|
||||
value(fc::vector<value>& a );
|
||||
value(const fc::vector<value>& 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<typename T>
|
||||
explicit value( const T& v );
|
||||
explicit value(const T& v );
|
||||
|
||||
template<typename T>
|
||||
value& operator=( const T& v );
|
||||
value& operator=( const T& v );
|
||||
|
||||
template<typename T>
|
||||
T cast()const;
|
||||
/*
|
||||
{
|
||||
slog("operator= %p", this);
|
||||
value tmp(fc::forward<T>(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<value>& as_array()const;
|
||||
fc::vector<value>& 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<typename S, typename T>
|
||||
value& set( S&& key, T&& v ) { return set( fc::forward<S>(key), fc::value( fc::forward<T>(v) ) ); }
|
||||
value& set(S&& key, T&& v ) { return set(fc::forward<S>(key), fc::value(fc::forward<T>(v) ) ); }
|
||||
|
||||
private:
|
||||
/** throws exceptions on errors
|
||||
|
|
@ -161,46 +165,40 @@ namespace fc {
|
|||
* reflection
|
||||
*/
|
||||
template<typename T>
|
||||
friend T value_cast( const value& v );
|
||||
friend T value_cast(const value& v );
|
||||
|
||||
aligned<40> holder;
|
||||
};
|
||||
typedef fc::optional<value> 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.hpp>
|
||||
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)
|
||||
)
|
||||
|
|
|
|||
|
|
@ -16,212 +16,54 @@ namespace fc {
|
|||
|
||||
namespace detail {
|
||||
|
||||
template<typename T>
|
||||
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<T>(v); }
|
||||
virtual void operator()( const int16_t& v ) { m_out = fc::numeric_cast<T>(v); }
|
||||
virtual void operator()( const int32_t& v ) { m_out = fc::numeric_cast<T>(v); }
|
||||
virtual void operator()( const int64_t& v ) { m_out = fc::numeric_cast<T>(v); }
|
||||
virtual void operator()( const uint8_t& v ) { m_out = fc::numeric_cast<T>(v); }
|
||||
virtual void operator()( const uint16_t& v ) { m_out = fc::numeric_cast<T>(v); }
|
||||
virtual void operator()( const uint32_t& v ) { m_out = fc::numeric_cast<T>(v); }
|
||||
virtual void operator()( const uint64_t& v ) { m_out = fc::numeric_cast<T>(v); }
|
||||
virtual void operator()( const float& v ) { m_out = fc::numeric_cast<T>(v); }
|
||||
virtual void operator()( const double& v ) { m_out = fc::numeric_cast<T>(v); }
|
||||
virtual void operator()( const bool& v ) { m_out = v; }
|
||||
virtual void operator()( const fc::string& v ) { m_out = fc::lexical_cast<T>(v); }
|
||||
virtual void operator()( const value::object& ) { FC_THROW_REPORT("bad cast to ${type} from object",
|
||||
fc::value().set("type",fc::get_typename<T>::name())); }
|
||||
virtual void operator()( const value::array& ) { FC_THROW_REPORT("bad cast to ${type} from array",
|
||||
fc::value().set("type",fc::get_typename<T>::name())); }
|
||||
virtual void operator()( ) { FC_THROW_REPORT("bad cast to ${type} from null",
|
||||
fc::value().set("type",fc::get_typename<T>::name())); }
|
||||
private:
|
||||
T& m_out;
|
||||
};
|
||||
template<>
|
||||
struct cast_visitor<bool> : 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<fc::string> : value::const_visitor {
|
||||
cast_visitor( fc::string& out )
|
||||
:m_out(out){}
|
||||
virtual void operator()( const int8_t& v ) { m_out = fc::lexical_cast<fc::string>(v); }
|
||||
virtual void operator()( const int16_t& v ) { m_out = fc::lexical_cast<fc::string>(v); }
|
||||
virtual void operator()( const int32_t& v ) { m_out = fc::lexical_cast<fc::string>(v); }
|
||||
virtual void operator()( const int64_t& v ) { m_out = fc::lexical_cast<fc::string>(v); }
|
||||
virtual void operator()( const uint8_t& v ) { m_out = fc::lexical_cast<fc::string>(v); }
|
||||
virtual void operator()( const uint16_t& v ) { m_out = fc::lexical_cast<fc::string>(v); }
|
||||
virtual void operator()( const uint32_t& v ) { m_out = fc::lexical_cast<fc::string>(v); }
|
||||
virtual void operator()( const uint64_t& v ) { m_out = fc::lexical_cast<fc::string>(v); }
|
||||
virtual void operator()( const float& v ) { m_out = fc::lexical_cast<fc::string>(v); }
|
||||
virtual void operator()( const double& v ) { m_out = fc::lexical_cast<fc::string>(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::array> : 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::object> : 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<fc::value> : 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<typename T>
|
||||
struct cast_visitor<fc::vector<T>> : value::const_visitor {
|
||||
cast_visitor( fc::vector<T>& out )
|
||||
:m_out(out){}
|
||||
virtual void operator()( const int8_t& v ) { FC_THROW_REPORT("bad cast to vector<T> from int8");}
|
||||
virtual void operator()( const int16_t& v ) { FC_THROW_REPORT("bad cast to vector<T> from int16");}
|
||||
virtual void operator()( const int32_t& v ) { FC_THROW_REPORT("bad cast to vector<T> from int32");}
|
||||
virtual void operator()( const int64_t& v ) { FC_THROW_REPORT("bad cast to vector<T> from int64");}
|
||||
virtual void operator()( const uint8_t& v ) { FC_THROW_REPORT("bad cast to vector<T> from uint8");}
|
||||
virtual void operator()( const uint16_t& v ) { FC_THROW_REPORT("bad cast to vector<T> from uint16");}
|
||||
virtual void operator()( const uint32_t& v ) { FC_THROW_REPORT("bad cast to vector<T> from uint32");}
|
||||
virtual void operator()( const uint64_t& v ) { FC_THROW_REPORT("bad cast to vector<T> from uint64");}
|
||||
virtual void operator()( const float& v ) { FC_THROW_REPORT("bad cast to vector<T> from float");}
|
||||
virtual void operator()( const double& v ) { FC_THROW_REPORT("bad cast to vector<T> from double");}
|
||||
virtual void operator()( const bool& v ) { FC_THROW_REPORT("bad cast to vector<T> from bool");}
|
||||
virtual void operator()( const fc::string& v ) { FC_THROW_REPORT("bad cast to vector<T> from string");}
|
||||
virtual void operator()( const value::object& a ) { FC_THROW_REPORT("bad cast to vector<T> 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<typename T>
|
||||
void cast_value( const value& v, T& t) {
|
||||
unpack(v,t);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void cast_value( const value& v, fc::vector<T>& out ) {
|
||||
if( v.type() != value::array_type ) {
|
||||
FC_THROW_REPORT( "Error casting ${type} to array", fc::value("type", fc::reflector<value::value_type>::to_string(v.type()) ) );
|
||||
}
|
||||
out.resize(v.size());
|
||||
const fc::vector<value>& 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<T>( *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<T>::name()) );
|
||||
*oitr = value_cast<T>(*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<T>::name())
|
||||
);
|
||||
}
|
||||
++idx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual void operator()( ) { FC_THROW_REPORT("bad cast");}
|
||||
|
||||
private:
|
||||
fc::vector<T>& m_out;
|
||||
};
|
||||
|
||||
|
||||
|
||||
template<>
|
||||
struct cast_visitor<void> : 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<typename IsTuple=fc::false_type>
|
||||
struct cast_if_tuple {
|
||||
template<typename T>
|
||||
static T cast( const value& v ) {
|
||||
typename fc::deduce<T>::type out;
|
||||
v.visit(cast_visitor<decltype(out)>(out));
|
||||
cast_value(v,out);
|
||||
// v.visit(cast_visitor<decltype(out)>(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
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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<typename T>
|
||||
static inline void unpack( const fc::value& jsv, T& v ) {
|
||||
if( strcmp( jsv.type(), "string" ) == 0 ) {
|
||||
if( jsv.is_string() ) {
|
||||
v = fc::reflector<T>::from_string( fc::value_cast<fc::string>(jsv).c_str() );
|
||||
} else {
|
||||
// throw if invalid int, by attempting to convert to string
|
||||
|
|
@ -183,12 +183,10 @@ namespace fc {
|
|||
template<typename T>
|
||||
static inline void pack(fc::value& s, const T& v ) {
|
||||
v.did_not_implement_reflect_macro();
|
||||
wlog( "warning, ignoring unknown type" );
|
||||
}
|
||||
template<typename T>
|
||||
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<typename T>
|
||||
void unpack( const fc::value& jsv, fc::optional<T>& v ) {
|
||||
if( strcmp( jsv.type(), "void" ) != 0 ) {
|
||||
if( !jsv.is_null() ) {
|
||||
T tmp;
|
||||
unpack( jsv, tmp );
|
||||
v = fc::move(tmp);
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
12
src/json.cpp
12
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<char>&& 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 << ']';
|
||||
}
|
||||
|
|
|
|||
12
src/reflect.cpp
Normal file
12
src/reflect.cpp
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
#include <fc/error_report.hpp>
|
||||
|
||||
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) );
|
||||
}
|
||||
}
|
||||
106
src/ssh.cpp
106
src/ssh.cpp
|
|
@ -11,10 +11,12 @@
|
|||
#include <fc/interprocess/file_mapping.hpp>
|
||||
#include <fc/unique_lock.hpp>
|
||||
#include <fc/mutex.hpp>
|
||||
#include <fc/ip.hpp>
|
||||
#include <fc/error_report.hpp>
|
||||
#include <libssh2.h>
|
||||
#include <libssh2_sftp.h>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include <fc/asio.hpp>
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
|
@ -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<boost::system::error_code> 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) );
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
#include <boost/atomic.hpp>
|
||||
#include <vector>
|
||||
#include <fc/log.hpp>
|
||||
#include <fc/logger.hpp>
|
||||
|
||||
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<boost::mutex> lock(log_mutex());
|
||||
|
||||
std::cerr<<"--------------------- "<<s.c_str()<<" - "<<current;
|
||||
|
|
@ -123,29 +125,34 @@ namespace fc {
|
|||
*/
|
||||
}
|
||||
fc::context::ptr ready_pop_front() {
|
||||
fc::context::ptr tmp = 0;
|
||||
fc::context::ptr tmp = nullptr;
|
||||
if( ready_head ) {
|
||||
tmp = ready_head;
|
||||
ready_head = tmp->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();
|
||||
|
||||
|
|
|
|||
393
src/value.cpp
393
src/value.cpp
|
|
@ -4,6 +4,7 @@
|
|||
#include <string.h>
|
||||
#include <fc/error_report.hpp>
|
||||
|
||||
|
||||
namespace fc {
|
||||
|
||||
namespace detail {
|
||||
|
|
@ -25,18 +26,270 @@ namespace fc {
|
|||
virtual void operator()( value::array& ){};
|
||||
virtual void operator()( ){};
|
||||
};
|
||||
template<typename T>
|
||||
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<T>(v); }
|
||||
virtual void operator()( const int16_t& v ) { m_out = fc::numeric_cast<T>(v); }
|
||||
virtual void operator()( const int32_t& v ) { m_out = fc::numeric_cast<T>(v); }
|
||||
virtual void operator()( const int64_t& v ) { m_out = fc::numeric_cast<T>(v); }
|
||||
virtual void operator()( const uint8_t& v ) { m_out = fc::numeric_cast<T>(v); }
|
||||
virtual void operator()( const uint16_t& v ) { m_out = fc::numeric_cast<T>(v); }
|
||||
virtual void operator()( const uint32_t& v ) { m_out = fc::numeric_cast<T>(v); }
|
||||
virtual void operator()( const uint64_t& v ) { m_out = fc::numeric_cast<T>(v); }
|
||||
virtual void operator()( const float& v ) { m_out = fc::numeric_cast<T>(v); }
|
||||
virtual void operator()( const double& v ) { m_out = fc::numeric_cast<T>(v); }
|
||||
virtual void operator()( const bool& v ) { m_out = v; }
|
||||
virtual void operator()( const fc::string& v ) { m_out = fc::lexical_cast<T>(v); }
|
||||
virtual void operator()( const value::object& ) { FC_THROW_REPORT("bad cast to ${type} from object",
|
||||
fc::value().set("type",fc::get_typename<T>::name())); }
|
||||
virtual void operator()( const value::array& ) { FC_THROW_REPORT("bad cast to ${type} from array",
|
||||
fc::value().set("type",fc::get_typename<T>::name())); }
|
||||
virtual void operator()( ) { FC_THROW_REPORT("bad cast to ${type} from null",
|
||||
fc::value().set("type",fc::get_typename<T>::name())); }
|
||||
private:
|
||||
T& m_out;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct cast_visitor<bool> : 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<fc::string> : value::const_visitor {
|
||||
cast_visitor( fc::string& out )
|
||||
:m_out(out){}
|
||||
virtual void operator()( const int8_t& v ) { m_out = fc::lexical_cast<fc::string>(v); }
|
||||
virtual void operator()( const int16_t& v ) { m_out = fc::lexical_cast<fc::string>(v); }
|
||||
virtual void operator()( const int32_t& v ) { m_out = fc::lexical_cast<fc::string>(v); }
|
||||
virtual void operator()( const int64_t& v ) { m_out = fc::lexical_cast<fc::string>(v); }
|
||||
virtual void operator()( const uint8_t& v ) { m_out = fc::lexical_cast<fc::string>(v); }
|
||||
virtual void operator()( const uint16_t& v ) { m_out = fc::lexical_cast<fc::string>(v); }
|
||||
virtual void operator()( const uint32_t& v ) { m_out = fc::lexical_cast<fc::string>(v); }
|
||||
virtual void operator()( const uint64_t& v ) { m_out = fc::lexical_cast<fc::string>(v); }
|
||||
virtual void operator()( const float& v ) { m_out = fc::lexical_cast<fc::string>(v); }
|
||||
virtual void operator()( const double& v ) { m_out = fc::lexical_cast<fc::string>(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::array> : 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::object> : 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<fc::value> : 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<void> : 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<int8_t>(out) );
|
||||
}
|
||||
|
||||
void cast_value( const value& v, int16_t& out ){
|
||||
v.visit( cast_visitor<int16_t>(out) );
|
||||
}
|
||||
|
||||
void cast_value( const value& v, int32_t& out ){
|
||||
v.visit( cast_visitor<int32_t>(out) );
|
||||
}
|
||||
|
||||
void cast_value( const value& v, int64_t& out ){
|
||||
v.visit( cast_visitor<int64_t>(out) );
|
||||
}
|
||||
|
||||
void cast_value( const value& v, uint8_t& out ){
|
||||
v.visit( cast_visitor<uint8_t>(out) );
|
||||
}
|
||||
|
||||
void cast_value( const value& v, uint16_t& out ){
|
||||
v.visit( cast_visitor<uint16_t>(out) );
|
||||
}
|
||||
|
||||
void cast_value( const value& v, uint32_t& out ){
|
||||
v.visit( cast_visitor<uint32_t>(out) );
|
||||
}
|
||||
|
||||
void cast_value( const value& v, uint64_t& out ){
|
||||
v.visit( cast_visitor<uint64_t>(out) );
|
||||
}
|
||||
|
||||
void cast_value( const value& v, double& out ){
|
||||
v.visit( cast_visitor<double>(out) );
|
||||
}
|
||||
|
||||
void cast_value( const value& v, float& out ){
|
||||
v.visit( cast_visitor<float>(out) );
|
||||
}
|
||||
|
||||
void cast_value( const value& v, bool& out ){
|
||||
v.visit( cast_visitor<bool>(out) );
|
||||
}
|
||||
|
||||
void cast_value( const value& v, fc::string& out ){
|
||||
v.visit( cast_visitor<fc::string>(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<value::value_type>::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<typename T>
|
||||
struct get_value_type{};
|
||||
template<> struct get_value_type<void> { static value::value_type type(){ return value::null_type; } };
|
||||
template<> struct get_value_type<int8_t> { static value::value_type type(){ return value::int8_type; } };
|
||||
template<> struct get_value_type<int16_t>{ static value::value_type type(){ return value::int16_type; } };
|
||||
template<> struct get_value_type<int32_t>{ static value::value_type type(){ return value::int32_type; } };
|
||||
template<> struct get_value_type<int64_t>{ static value::value_type type(){ return value::int64_type; } };
|
||||
template<> struct get_value_type<uint8_t>{ static value::value_type type(){ return value::uint8_type; } };
|
||||
template<> struct get_value_type<uint16_t>{ static value::value_type type(){ return value::uint16_type; } };
|
||||
template<> struct get_value_type<uint32_t>{ static value::value_type type(){ return value::uint32_type; } };
|
||||
template<> struct get_value_type<uint64_t>{ static value::value_type type(){ return value::uint64_type; } };
|
||||
template<> struct get_value_type<double>{ static value::value_type type(){ return value::double_type; } };
|
||||
template<> struct get_value_type<float>{ static value::value_type type(){ return value::float_type; } };
|
||||
template<> struct get_value_type<fc::string>{ static value::value_type type(){ return value::string_type; } };
|
||||
template<> struct get_value_type<bool>{ static value::value_type type(){ return value::bool_type; } };
|
||||
template<> struct get_value_type<fc::vector<value>>{ static value::value_type type(){ return value::array_type; } };
|
||||
template<> struct get_value_type<value::object>{ static value::value_type type(){ return value::object_type; } };
|
||||
|
||||
// fundamental values...
|
||||
template<typename T>
|
||||
struct value_holder_impl : value_holder {
|
||||
static_assert( !fc::is_class<T>::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<T>::name(); }
|
||||
|
||||
value_holder_impl(){
|
||||
static_assert( sizeof(value_holder_impl) <= 40, "Validate size" );
|
||||
}
|
||||
virtual value::value_type type()const { return get_value_type<T>::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<void> : 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<void>(); }
|
||||
virtual value_holder* copy_helper( char* c )const{ return new(c) value_holder_impl<void>();}
|
||||
virtual void visit( value_visitor&& v ) { v(); }
|
||||
virtual value_holder* move_helper( char* c ) { return new(c) value_holder_impl<void>(); }
|
||||
virtual value_holder* copy_helper( char* c )const{ return new(c) value_holder_impl<void>(); }
|
||||
};
|
||||
|
||||
|
||||
|
||||
template<>
|
||||
struct value_holder_impl<fc::string> : value_holder {
|
||||
template<typename V>
|
||||
value_holder_impl( V&& v ):val( fc::forward<V>(v) ){
|
||||
static_assert( sizeof(value_holder_impl<fc::string>) <= 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::object> : 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::array> : 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<value::array> ) <= 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<void>(); }
|
||||
value_holder* value_holder::copy_helper( char* c )const { return new(c) value_holder_impl<void>(); }
|
||||
|
||||
|
|
@ -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<value::array>::resize( size_t s ) { val.fields.resize(s); }
|
||||
void value_holder_impl<value::array>::reserve( size_t s ) { val.fields.reserve(s); }
|
||||
value& value_holder_impl<value::array>::at( size_t i) { return val.fields[i]; }
|
||||
const value& value_holder_impl<value::array>::at( size_t i)const { return val.fields[i]; }
|
||||
void value_holder_impl<value::array>::resize( size_t s ) { val.resize(s); }
|
||||
void value_holder_impl<value::array>::reserve( size_t s ) { val.reserve(s); }
|
||||
value& value_holder_impl<value::array>::at( size_t i) { return val[i]; }
|
||||
const value& value_holder_impl<value::array>::at( size_t i)const { return val[i]; }
|
||||
value_holder* value_holder_impl<value::array>::move_helper( char* c ){ return new(c) value_holder_impl( fc::move(val) ); }
|
||||
value_holder* value_holder_impl<value::array>::copy_helper( char* c )const{ return new(c) value_holder_impl(val); }
|
||||
|
||||
void value_holder_impl<value::array>::clear() { val.fields.clear(); }
|
||||
size_t value_holder_impl<value::array>::size()const { return static_cast<size_t>(val.fields.size()); }
|
||||
void value_holder_impl<value::array>::clear() { val.clear(); }
|
||||
size_t value_holder_impl<value::array>::size()const { return static_cast<size_t>(val.size()); }
|
||||
void value_holder_impl<value::array>::visit( value::const_visitor&& v )const { v(val); }
|
||||
void value_holder_impl<value::array>::visit( value_visitor&& v ) { v(val); }
|
||||
void value_holder_impl<value::array>::push_back( value&& v ) { val.fields.push_back( fc::move(v) ); }
|
||||
void value_holder_impl<value::array>::push_back( value&& v ) { val.push_back( fc::move(v) ); }
|
||||
|
||||
|
||||
void value_holder_impl<value::object>::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<fc::string> ), "size check" );
|
||||
new (holder) detail::value_holder_impl<fc::string>(v);
|
||||
}
|
||||
value::value( const fc::string& v, const value& val ) {
|
||||
static_assert( sizeof(holder) >= sizeof( detail::value_holder_impl<value::object> ), "size check" );
|
||||
new (holder) detail::value_holder_impl<value::object>(value::object());
|
||||
set( v, val );
|
||||
}
|
||||
value::value( value::object&& o ){
|
||||
static_assert( sizeof(holder) >= sizeof( detail::value_holder_impl<value::object> ), "size check" );
|
||||
new (holder) detail::value_holder_impl<value::object>(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>& 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<value::array>* o = static_cast<const detail::value_holder_impl<value::array>*>(gh(holder));
|
||||
return o->val;
|
||||
}
|
||||
fc::vector<value>& 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<value::array>* o = static_cast<detail::value_holder_impl<value::array>*>(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<value::object>* o = static_cast<const detail::value_holder_impl<value::object>*>(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<value::object>* o = static_cast<detail::value_holder_impl<value::object>*>(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<fc::string>* o = static_cast<const detail::value_holder_impl<fc::string>*>(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<fc::string>* o = static_cast<detail::value_holder_impl<fc::string>*>(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<value::object>* o = static_cast<const detail::value_holder_impl<value::object>*>(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<value::object>* o = static_cast<const detail::value_holder_impl<value::object>*>(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<value::object>* o = static_cast<const detail::value_holder_impl<value::object>*>(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<value::object>* o = dynamic_cast<detail::value_holder_impl<value::object>*>(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<value::object>* o = dynamic_cast<detail::value_holder_impl<value::object>*>(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>(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>(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>(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;
|
||||
|
|
|
|||
Loading…
Reference in a new issue