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:
Daniel Larimer 2013-02-07 16:08:43 -05:00
parent b527bbbab6
commit 25872b11b8
17 changed files with 709 additions and 441 deletions

View file

@ -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
)

View file

@ -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; }

View file

@ -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()

View file

@ -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:

View file

@ -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();\
} \
}; \
}

View file

@ -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 );

View file

@ -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 );

View file

@ -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)
)

View file

@ -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

View file

@ -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);

View file

@ -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();

View file

@ -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();

View file

@ -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
View 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) );
}
}

View file

@ -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) );

View file

@ -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();

View file

@ -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;