From 3d56a96d4ec83d51cace8b9fd98938fbcef6b997 Mon Sep 17 00:00:00 2001 From: Daniel Larimer Date: Sun, 21 Oct 2012 02:28:59 -0400 Subject: [PATCH] major updates to stream,reflect,value,and json - removed polymorphic reflection, made static_reflect default because there are cases such as deserializing an array that you need more information than the runtime reflection can provide such as the ability to resize arrays and know the array content type. - refactored iostream, sstream, fstream to be much simpler, fewer indirections, and fixed getline. - json parsing works using code from mace. - value is reimplemented based upon mace::rpc::value and no longer uses the runtime reflection that was removed. - moved the typename utility to its own header --- CMakeLists.txt | 10 +- include/fc/aligned.hpp | 2 + include/fc/fstream.hpp | 43 ++ include/fc/hex.hpp | 5 +- include/fc/iostream.hpp | 97 +++ include/fc/json.hpp | 52 +- include/fc/lexical_cast.hpp | 87 +++ include/fc/numeric_cast.hpp | 9 + include/fc/raw.hpp | 18 +- include/fc/reflect.hpp | 366 ++++----- include/fc/reflect_cast.hpp | 40 - include/fc/reflect_fwd.hpp | 32 - include/fc/reflect_impl.hpp | 32 - include/fc/reflect_ptr.hpp | 48 -- include/fc/reflect_ref.hpp | 0 include/fc/reflect_tmp.hpp | 125 --- include/fc/reflect_value.hpp | 9 - include/fc/reflect_vector.hpp | 48 -- include/fc/sha1.hpp | 5 +- include/fc/sstream.hpp | 44 ++ include/fc/static_reflect.hpp | 198 ----- include/fc/stream.hpp | 281 ++----- include/fc/typename.hpp | 19 + include/fc/utility.hpp | 2 +- include/fc/value.hpp | 266 ++++--- include/fc/value_cast.hpp | 280 ++++--- include/fc/value_fwd.hpp | 10 - include/fc/value_io.hpp | 255 ++++++ include/fc/vector.hpp | 21 +- src/iostream.cpp | 68 ++ src/json.cpp | 1376 +++++++++++++++++++++------------ src/lexical_cast.cpp | 26 + src/sha1.cpp | 13 +- src/sstream.cpp | 65 ++ src/stream.cpp | 384 --------- src/value.cpp | 716 +++++++++-------- src/value_cast.cpp | 95 --- 37 files changed, 2583 insertions(+), 2564 deletions(-) create mode 100644 include/fc/fstream.hpp create mode 100644 include/fc/iostream.hpp create mode 100644 include/fc/lexical_cast.hpp create mode 100644 include/fc/numeric_cast.hpp delete mode 100644 include/fc/reflect_cast.hpp delete mode 100644 include/fc/reflect_fwd.hpp delete mode 100644 include/fc/reflect_impl.hpp delete mode 100644 include/fc/reflect_ptr.hpp delete mode 100644 include/fc/reflect_ref.hpp delete mode 100644 include/fc/reflect_tmp.hpp delete mode 100644 include/fc/reflect_value.hpp delete mode 100644 include/fc/reflect_vector.hpp create mode 100644 include/fc/sstream.hpp delete mode 100644 include/fc/static_reflect.hpp create mode 100644 include/fc/typename.hpp delete mode 100644 include/fc/value_fwd.hpp create mode 100644 include/fc/value_io.hpp create mode 100644 src/iostream.cpp create mode 100644 src/lexical_cast.cpp create mode 100644 src/sstream.cpp delete mode 100644 src/stream.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index e08acd7..ea4172b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -45,7 +45,8 @@ include_directories( ${Boost_INCLUDE_DIR} ) include_directories( include ) set( sources - src/json_rpc_connection.cpp + src/value.cpp + src/lexical_cast.cpp src/spin_lock.cpp src/spin_yield_lock.cpp src/task.cpp @@ -55,13 +56,12 @@ set( sources src/json.cpp src/log.cpp src/time.cpp - src/stream.cpp + src/iostream.cpp + src/sstream.cpp src/exception.cpp src/thread.cpp - src/value.cpp src/hex.cpp src/sha1.cpp - src/value_cast.cpp src/filesystem.cpp src/ip.cpp src/bigint.cpp @@ -76,7 +76,7 @@ set( sources src/asio.cpp src/super_fast_hash.cpp src/file_mapping.cpp - src/program_options.cpp +# src/program_options.cpp ) setup_library( fc SOURCES ${sources} ) diff --git a/include/fc/aligned.hpp b/include/fc/aligned.hpp index d8b211e..7bda080 100644 --- a/include/fc/aligned.hpp +++ b/include/fc/aligned.hpp @@ -8,6 +8,8 @@ namespace fc { T _align; char _data[S]; } _store; + operator char*() { return _store._data; } + operator const char*()const { return _store._data; } }; } diff --git a/include/fc/fstream.hpp b/include/fc/fstream.hpp new file mode 100644 index 0000000..349d6f9 --- /dev/null +++ b/include/fc/fstream.hpp @@ -0,0 +1,43 @@ +#pragma once +#include + +namespace fc { + + class ofstream //: virtual public ostream { + public: + enum mode { out, binary }; + ofstream(); + ofstream( const fc::string& file, int m ); + ~ofstream(); + + void open( const fc::string& file, int m ); + ofstream& write( const char* buf, size_t len ); + void put( char c ); + void close(); + void flush(); + + private: + class impl; + fwd my; + }; + + class ifstream //: virtual public istream { + public: + enum mode { in, binary }; + ifstream(); + ifstream( const fc::string& file, int m ); + ~ifstream(); + + void open( const fc::string& file, int m ); + ifstream& read( char* buf, size_t len ); + void close(); + void flush(); + + bool eof()const; + + private: + class impl; + fwd my; + }; + +} // namespace fc diff --git a/include/fc/hex.hpp b/include/fc/hex.hpp index 3ae8d46..f3ca29e 100644 --- a/include/fc/hex.hpp +++ b/include/fc/hex.hpp @@ -1,5 +1,4 @@ -#ifndef _FC_HEX_HPP_ -#define _FC_HEX_HPP_ +#pragma once #include #include @@ -11,6 +10,4 @@ namespace fc { * @return the number of bytes decoded */ size_t from_hex( const fc::string& hex_str, char* out_data, size_t out_data_len ); - } -#endif // _FC_HEX_HPP_ diff --git a/include/fc/iostream.hpp b/include/fc/iostream.hpp new file mode 100644 index 0000000..68d35ed --- /dev/null +++ b/include/fc/iostream.hpp @@ -0,0 +1,97 @@ +#pragma once +#include +#include + +namespace fc { + class string; + + class istream { + public: + virtual ~istream(){}; + + virtual size_t readsome( char* buf, size_t len ) = 0; + virtual istream& read( char* buf, size_t len ) = 0; + + template + friend istream& operator>>( istream& i, T& v ){ return i.read(v); } + + virtual bool eof()const = 0; + + protected: + virtual istream& read( int64_t& ) = 0; + virtual istream& read( uint64_t& ) = 0; + virtual istream& read( int32_t& ) = 0; + virtual istream& read( uint32_t& ) = 0; + virtual istream& read( int16_t& ) = 0; + virtual istream& read( uint16_t& ) = 0; + virtual istream& read( int8_t& ) = 0; + virtual istream& read( uint8_t& ) = 0; + virtual istream& read( float& ) = 0; + virtual istream& read( double& ) = 0; + virtual istream& read( bool& ) = 0; + virtual istream& read( char& ) = 0; + virtual istream& read( fc::string& ) = 0; + }; + + class ostream { + public: + virtual ~ostream(){}; + + virtual ostream& write( const char* buf, size_t len ) = 0; + virtual void close() = 0; + virtual void flush() = 0; + + template + friend ostream& operator<<( ostream& o, const T& v ) { return o.write(fc::lexical_cast(v)); } + friend ostream& operator<<( ostream& o, char* v ) { return o.write(v); } + friend ostream& operator<<( ostream& o, const char* v ) { return o.write(v); } + friend ostream& operator<<( ostream& o, const fc::string& v ){ return o.write(v); } + + protected: + virtual ostream& write( const fc::string& ) = 0; + }; + class iostream : public virtual ostream, public virtual istream {}; + + fc::istream& getline( fc::istream&, fc::string&, char delim = '\n' ); + + struct cout_t : virtual public ostream { + virtual ostream& write( const char* buf, size_t len ); + virtual void close(); + virtual void flush(); + + virtual ostream& write( const fc::string& ); + }; + + struct cerr_t : virtual public ostream { + virtual ostream& write( const char* buf, size_t len ); + virtual void close(); + virtual void flush(); + + virtual ostream& write( const fc::string& ); + }; + + struct cin_t : virtual public istream { + virtual size_t readsome( char* buf, size_t len ); + virtual istream& read( char* buf, size_t len ); + virtual bool eof()const; + + virtual istream& read( int64_t& ); + virtual istream& read( uint64_t& ); + virtual istream& read( int32_t& ); + virtual istream& read( uint32_t& ); + virtual istream& read( int16_t& ); + virtual istream& read( uint16_t& ); + virtual istream& read( int8_t& ); + virtual istream& read( uint8_t& ); + virtual istream& read( float& ); + virtual istream& read( double& ); + virtual istream& read( bool& ); + virtual istream& read( char& ); + virtual istream& read( fc::string& ); + }; + + + extern cout_t cout; + extern cerr_t cerr; + extern cin_t cin; +} diff --git a/include/fc/json.hpp b/include/fc/json.hpp index 072dc5b..1c8aa41 100644 --- a/include/fc/json.hpp +++ b/include/fc/json.hpp @@ -1,28 +1,48 @@ -#ifndef _FC_JSON_HPP_ -#define _FC_JSON_HPP_ +#pragma once #include -#include -#include +#include +#include +#include namespace fc { class istream; class ostream; - class cref; + class path; namespace json { - string to_string( const cref& o ); - value_fwd from_string( const string& s ); - value_fwd from_string( const char* s, const char* e ); - void from_string( const string&, const ref& o ); + string to_string( const value& o ); + + + value from_string( const string& s ); + value from_string( const char* s, const char* e ); + value from_string( const fc::vector& v ); + + + string escape_string( const string& ); + string unescape_string( const string& ); + + void write( ostream& out, const value& val ); + + template + void write( ostream& out, const T& val ) { + write( out, value(val) ); + } + + template + string to_string( const T& o ) { + return json::to_string(value(o)); + } template T from_string( const string& s ) { - T tmp; from_string( s, tmp ); - return tmp; + return value_cast( from_string(s) ); } - string escape_string( const string& ); - string unescape_string( const string& ); - void write( ostream& out, const cref& val ); -} } -#endif + value from_file( const fc::path& s ); + template + T from_file( const fc::path& s ) { + return value_cast( fc::json::from_file(s) ); + } + } // namespace json +} // fc + diff --git a/include/fc/lexical_cast.hpp b/include/fc/lexical_cast.hpp new file mode 100644 index 0000000..fe8153e --- /dev/null +++ b/include/fc/lexical_cast.hpp @@ -0,0 +1,87 @@ +#pragma once +#include + +namespace fc { + + namespace detail { + template + struct lexical_cast { }; + + double to_double( const fc::string& s ); + inline double to_double( double d ) { return d; } + + int64_t to_int64( const fc::string& s ); + inline int64_t to_int64( double d ) { return d; } + inline int64_t to_int64( int64_t d ) { return d; } + + uint64_t to_uint64( const fc::string& s ); + inline uint64_t to_uint64( double d ) { return d; } + inline uint64_t to_uint64( uint64_t d ) { return d; } + + fc::string to_string( double d ); + fc::string to_string( uint64_t d ); + fc::string to_string( uint32_t d ); + fc::string to_string( uint16_t d ); + fc::string to_string( uint8_t d ); + fc::string to_string( int64_t d ); + fc::string to_string( int32_t d ); + fc::string to_string( int16_t d ); + fc::string to_string( int8_t d ); + fc::string to_string( char d ); + + template + struct lexical_cast { + static double cast( const R& v ) { return to_double( v ); } + }; + + template + struct lexical_cast { + static fc::string cast( const R& v ) { return to_string( v ); } + }; + + template + struct lexical_cast { + static uint64_t cast( const R& v ) { return to_uint64( v ); } + }; + + template + struct lexical_cast { static uint64_t cast( const R& v ) { return to_int64( v ); } }; + + template + struct lexical_cast { static uint32_t cast( const R& v ) { return to_int64( v ); } }; + + template + struct lexical_cast { static uint16_t cast( const R& v ) { return to_int64( v ); } }; + + template + struct lexical_cast { static uint8_t cast( const R& v ) { return to_int64( v ); } }; + + + template + struct lexical_cast { static uint32_t cast( const R& v ) { return to_uint64( v ); } }; + + template + struct lexical_cast { static uint16_t cast( const R& v ) { return to_uint64( v ); } }; + + template + struct lexical_cast { static uint8_t cast( const R& v ) { return to_uint64( v ); } }; + + template + struct lexical_cast { static bool cast( const R& v ) { return v; } }; + + template<> + struct lexical_cast { static bool cast( const fc::string& v ) { return v == "true"; } }; + + template<> + struct lexical_cast { static fc::string cast( const bool& v ) { return v ? "true" : "false";} }; + + template + struct lexical_cast { static float cast( const R& v ) { return to_double( v ); } }; + } + + + template + T lexical_cast( const R& v ) { + return detail::lexical_cast::cast(v); + } +} diff --git a/include/fc/numeric_cast.hpp b/include/fc/numeric_cast.hpp new file mode 100644 index 0000000..3fdb766 --- /dev/null +++ b/include/fc/numeric_cast.hpp @@ -0,0 +1,9 @@ +#pragma once + +namespace fc { + template + T numeric_cast( const R& v ) { + // TODO: do something smarter here, check ranges, etc + return static_cast(v); + } +} diff --git a/include/fc/raw.hpp b/include/fc/raw.hpp index 540e191..d61ac7b 100644 --- a/include/fc/raw.hpp +++ b/include/fc/raw.hpp @@ -1,6 +1,6 @@ #ifndef _TORNET_RPC_RAW_HPP_ #define _TORNET_RPC_RAW_HPP_ -#include +#include #include #include #include @@ -163,22 +163,6 @@ namespace fc { Stream& s; }; - template - struct pack_sequence { - pack_sequence( Stream& _s ):s(_s){} - template - void operator() ( const T& v )const { raw::pack(s,v); } - Stream& s; - }; - - template - struct unpack_sequence { - unpack_sequence( Stream& _s ):s(_s){} - template - void operator() ( T& v )const { raw::unpack(s,v); } - Stream& s; - }; - template struct if_class{ template diff --git a/include/fc/reflect.hpp b/include/fc/reflect.hpp index b4a60e3..469ca28 100644 --- a/include/fc/reflect.hpp +++ b/include/fc/reflect.hpp @@ -1,198 +1,198 @@ + +/** + * @file fc/reflect.hpp + * + * @brief Defines types and macros used to provide reflection. + * + */ #ifndef _FC_REFLECT_HPP_ #define _FC_REFLECT_HPP_ + +#include +#include +//#include +#include +#include +#include +#include +//#include +//#include #include -#include -#include -#include + + +//#include +//#include namespace fc { - class string; +/** + * @brief defines visit functions for T + * Unless this is specialized, visit() will not be defined for T. + * + * @tparam T - the type that will be visited. + * + * The @ref FC_REFLECT(TYPE,MEMBERS) or FC_STATIC_REFLECT_DERIVED(TYPE,BASES,MEMBERS) macro is used to specialize this + * class for your type. + */ +template +struct reflector{ + typedef T type; + typedef fc::false_type is_defined; + typedef fc::false_type is_enum; - class abstract_visitor; - class abstract_const_visitor; - class abstract_reflector; + /** + * @tparam Visitor a function object of the form: + * + * @code + * struct functor { + * template + * void operator()( const char* name )const; + * }; + * @endcode + * + * If T is an enum then the functor has the following form: + * @code + * struct functor { + * template + * void operator()( const char* name )const; + * }; + * @endcode + * + * @param v a functor that will be called for each member on T + * + * @note - this method is not defined for non-reflected types. + */ + #ifdef DOXYGEN + template + static inline void visit( const Visitor& v ); + #endif // DOXYGEN +}; - // provides reference semantics - class ref { - public: - template - ref( T& v ); - - ref( const ref& v ) - :_obj(v._obj),_reflector(v._reflector){} - - ref( void* o, abstract_reflector& r ) - :_obj(o),_reflector(r){} - - void* _obj; - abstract_reflector& _reflector; - - private: - ref& operator=(const ref& o); - }; - - class cref { - public: - template - cref( const T& v ); - - cref( const cref& v ) - :_obj(v._obj),_reflector(v._reflector){} - - cref( const ref& v ) - :_obj(v._obj),_reflector(v._reflector){} - - cref( const void* o, abstract_reflector& r ) - :_obj(o),_reflector(r){} - - const void* _obj; - abstract_reflector& _reflector; - - private: - cref& operator=(const cref& o); - }; + } // namespace fc - class abstract_reflector : virtual public abstract_value_type { - public: - virtual ~abstract_reflector(){} - virtual const char* name()const = 0; - virtual void visit( void* s, const abstract_visitor& v )const = 0; - virtual void visit( const void* s, const abstract_const_visitor& v )const = 0; - virtual ref get_member(void*, uint64_t) = 0; - virtual cref get_member(const void*, uint64_t) = 0; - virtual ref get_member(void*, const char*) = 0; - virtual cref get_member(const void*, const char*) = 0; - virtual size_t member_count(const void*) = 0; +#ifndef DOXYGEN - }; - - class abstract_visitor { - public: - virtual ~abstract_visitor(){} - virtual void visit()const=0; - virtual void visit( char& c )const=0; - virtual void visit( uint8_t& c )const=0; - virtual void visit( uint16_t& c )const=0; - virtual void visit( uint32_t& c )const=0; - virtual void visit( uint64_t& c )const=0; - virtual void visit( int8_t& c )const=0; - virtual void visit( int16_t& c )const=0; - virtual void visit( int32_t& c )const=0; - virtual void visit( int64_t& c )const=0; - virtual void visit( double& c )const=0; - virtual void visit( float& c )const=0; - virtual void visit( bool& c )const=0; - virtual void visit( fc::string& c )const=0; - virtual void visit( const char* member, int idx, int size, const ref& v)const=0; - virtual void visit( int idx, int size, const ref& v)const=0; - virtual void array_size( int size )const=0; - virtual void object_size( int size )const=0; - }; - - class abstract_const_visitor { - public: - virtual ~abstract_const_visitor(){} - virtual void visit()const=0; - virtual void visit( const char& c )const=0; - virtual void visit( const uint8_t& c )const=0; - virtual void visit( const uint16_t& c )const=0; - virtual void visit( const uint32_t& c )const=0; - virtual void visit( const uint64_t& c )const=0; - virtual void visit( const int8_t& c )const=0; - virtual void visit( const int16_t& c )const=0; - virtual void visit( const int32_t& c )const=0; - virtual void visit( const int64_t& c )const=0; - virtual void visit( const double& c )const=0; - virtual void visit( const float& c )const=0; - virtual void visit( const bool& c )const=0; - virtual void visit( const fc::string& c )const=0; - virtual void visit( const char* member, int idx, int size, const cref& v)const=0; - virtual void visit( int idx, int size, const cref& v)const=0; - virtual void array_size( int size )const=0; - virtual void object_size( int size )const=0; - }; - - namespace detail { - template - class reflector_impl : virtual public value_type, virtual public abstract_reflector { - virtual ref get_member(void*, uint64_t) { - int x = 0; - return x; - } - virtual cref get_member(const void*, uint64_t) { - int x = 0; - return x; - } - // throw if field is not found - virtual ref get_member(void*, const char*) { - int x = 0; - return x; - // init static hash map the first time it is called... - // lookup field in hash map, return ref - //return ref(); - } - // throw if field is not found - virtual cref get_member(const void*, const char*) { - int x = 0; - return x; - // init static hash map the first time it is called... - // lookup field in hash map, return ref - //return cref(); - } - // throw if field is not found - virtual size_t member_count(const void*) { - // init static hash map the first time it is called... - // lookup field in hash map, return ref - return 0; - } - }; - } +#define FC_REFLECT_VISIT_BASE(r, visitor, base) \ + fc::reflector::visit( visitor ); - template class get_typename{}; - template<> struct get_typename { static const char* name() { return "int32_t"; } }; - template<> struct get_typename { static const char* name() { return "int64_t"; } }; - template<> struct get_typename { static const char* name() { return "int16_t"; } }; - template<> struct get_typename { static const char* name() { return "int8_t"; } }; - template<> struct get_typename { static const char* name() { return "uint32_t"; } }; - template<> struct get_typename { static const char* name() { return "uint64_t"; } }; - template<> struct get_typename { static const char* name() { return "uint16_t"; } }; - template<> struct get_typename { static const char* name() { return "uint8_t"; } }; - template<> struct get_typename { static const char* name() { return "double"; } }; - template<> struct get_typename { static const char* name() { return "float"; } }; - template<> struct get_typename { static const char* name() { return "bool"; } }; - template<> struct get_typename { static const char* name() { return "char"; } }; - template<> struct get_typename { static const char* name() { return "string"; } }; - - template - class reflector : public detail::reflector_impl >{ - public: - enum _is_defined { is_defined = 0 }; - virtual const char* name()const { return get_typename::name(); } - virtual void visit( void* s, const abstract_visitor& v )const { - v.visit( *((T*)s) ); - } - virtual void visit( const void* s, const abstract_const_visitor& v )const { - v.visit( *((const T*)s) ); - } - - static reflector& instance() { static reflector inst; return inst; } - }; - - template reflector& reflect( const T& ) { return reflector::instance(); } - - template - ref::ref( T& v ) :_obj(&v),_reflector(reflector::instance()){} - - template - cref::cref( const T& v ) :_obj(&v),_reflector(reflector::instance()){} - - template - class reflector>; - -} // namespace fc +#ifndef WIN32 + #define TEMPLATE template +#else + #define TEMPLATE +#endif +//#include +#define FC_REFLECT_VISIT_MEMBER( r, visitor, elem ) \ + visitor.TEMPLATE operator()elem), type, &type::elem>( BOOST_PP_STRINGIZE(elem) ); -#endif // _REFLECT_HPP_ +#define FC_REFLECT_BASE_MEMBER_COUNT( r, OP, elem ) \ + OP fc::reflector::member_count + +#define FC_REFLECT_DERIVED_IMPL_INLINE( TYPE, INHERITS, MEMBERS ) \ +template\ +static inline void visit( const Visitor& v ) { \ + BOOST_PP_SEQ_FOR_EACH( FC_REFLECT_VISIT_BASE, v, INHERITS ) \ + BOOST_PP_SEQ_FOR_EACH( FC_REFLECT_VISIT_MEMBER, v, MEMBERS ) \ +} + +#define FC_REFLECT_DERIVED_IMPL_EXT( TYPE, INHERITS, MEMBERS ) \ +template\ +void fc::reflector::visit( const Visitor& v ) { \ + BOOST_PP_SEQ_FOR_EACH( FC_REFLECT_VISIT_BASE, v, INHERITS ) \ + BOOST_PP_SEQ_FOR_EACH( FC_REFLECT_VISIT_MEMBER, v, MEMBERS ) \ +} + +#endif // DOXYGEN + + +#define FC_REFLECT_VISIT_ENUM( r, visitor, elem ) \ + visitor.TEMPLATE operator()(BOOST_PP_STRINGIZE(elem)); +#define FC_REFLECT_ENUM_TO_STRING( r, visitor, elem ) \ + case elem: return BOOST_PP_STRINGIZE(elem); + +#define FC_REFLECT_ENUM_FROM_STRING( r, visitor, elem ) \ + if( strcmp( s, BOOST_PP_STRINGIZE(elem) ) == 0 ) return elem; + +#define FC_REFLECT_ENUM( ENUM, FIELDS ) \ +namespace fc { \ +template<> struct reflector { \ + typedef fc::true_type is_defined; \ + typedef fc::true_type is_enum; \ + template \ + static inline void visit( const Visitor& v ) { \ + BOOST_PP_SEQ_FOR_EACH( FC_REFLECT_VISIT_ENUM, v, FIELDS ) \ + }\ + static const char* to_string(int64_t i) { \ + switch( ENUM(i) ) { \ + BOOST_PP_SEQ_FOR_EACH( FC_REFLECT_ENUM_TO_STRING, v, FIELDS ) \ + default: \ + FC_REFLECT_THROW( fc::reflect::unknown_field(), "%1% not in enum '%2%'", %i %BOOST_PP_STRINGIZE(ENUM) ); \ + }\ + } \ + static ENUM from_string( const char* s ) { \ + BOOST_PP_SEQ_FOR_EACH( FC_REFLECT_ENUM_FROM_STRING, v, FIELDS ) \ + FC_REFLECT_THROW( fc::reflect::unknown_field(), "%1% in enum %2%", %s %BOOST_PP_STRINGIZE(ENUM) ); \ + } \ +}; \ +} } + + + +/** + * @def FC_REFLECT_DERIVED(TYPE,INHERITS,MEMBERS) + * + * @brief Specializes fc::reflector for TYPE where + * type inherits other reflected classes + * + * @param INHERITS - a sequence of base class names (basea)(baseb)(basec) + * @param MEMBERS - a sequence of member names. (field1)(field2)(field3) + */ +#define FC_REFLECT_DERIVED( TYPE, INHERITS, MEMBERS ) \ +namespace fc { \ +template<> struct reflector {\ + typedef TYPE type; \ + typedef fc::true_type is_defined; \ + typedef fc::false_type is_enum; \ + enum member_count_enum { \ + local_member_count = BOOST_PP_SEQ_SIZE(MEMBERS), \ + total_member_count = local_member_count BOOST_PP_SEQ_FOR_EACH( FC_REFLECT_BASE_MEMBER_COUNT, +, INHERITS )\ + }; \ + FC_REFLECT_DERIVED_IMPL_INLINE( TYPE, INHERITS, MEMBERS ) \ +}; } + + +/** + * @def FC_REFLECT(TYPE,MEMBERS) + * @brief Specializes fc::reflector for TYPE + * + * @param MEMBERS - a sequence of member names. (field1)(field2)(field3) + * + * @see FC_REFLECT_DERIVED + */ +#define FC_REFLECT( TYPE, MEMBERS ) \ + FC_REFLECT_DERIVED( TYPE, BOOST_PP_SEQ_NIL, MEMBERS ) + +#define FC_REFLECT_FWD( TYPE ) \ +namespace fc { \ +template<> struct reflector {\ + typedef TYPE type; \ + typedef fc::true_type is_defined; \ + enum member_count_enum { \ + local_member_count = BOOST_PP_SEQ_SIZE(MEMBERS), \ + total_member_count = local_member_count BOOST_PP_SEQ_FOR_EACH( FC_REFLECT_BASE_MEMBER_COUNT, +, INHERITS )\ + }; \ + template static void visit( const Visitor& v ); \ +}; } + + +#define FC_REFLECT_DERIVED_IMPL( TYPE, MEMBERS ) \ + FC_REFLECT_IMPL_DERIVED_EXT( TYPE, BOOST_PP_SEQ_NIL, MEMBERS ) + +#define FC_REFLECT_IMPL( TYPE, MEMBERS ) \ + FC_REFLECT_DERIVED_IMPL_EXT( TYPE, BOOST_PP_SEQ_NIL, MEMBERS ) + + + +#endif diff --git a/include/fc/reflect_cast.hpp b/include/fc/reflect_cast.hpp deleted file mode 100644 index 56c1e56..0000000 --- a/include/fc/reflect_cast.hpp +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef _REFLECT_CAST_HPP_ -#define _REFLECT_CAST_HPP_ -#include - -namespace fc { - /** - * This is specialized for each type to implement a cast - * from a reflected value. - * - * By default the cast will only work for 'exact' matches of - * type. Use duck_cast for a more flexible field-by-field - * cast. - */ - template - class const_cast_visitor : public abstract_const_visitor { - public: - const_cast_visitor( T& s ):_s(s){} - - virtual void visit()=0; - virtual void visit( const char& c )const=0; - virtual void visit( const uint8_t& c )const=0; - virtual void visit( const uint16_t& c )const=0; - virtual void visit( const uint32_t& c )const=0; - virtual void visit( const uint64_t& c )const=0; - virtual void visit( const int8_t& c )const=0; - virtual void visit( const int16_t& c )const=0; - virtual void visit( const int32_t& c )const=0; - virtual void visit( const int64_t& c )const=0; - virtual void visit( const double& c )const=0; - virtual void visit( const float& c )const=0; - virtual void visit( const bool& c )const=0; - virtual void visit( const fc::string& c )const=0; - virtual void visit( const char* member, int idx, int size, const cref& v)const=0; - virtual void visit( int idx, int size, const cref& v)const=0; - }; - - - -} // namespace fc -#endif // _REFLECT_CAST_HPP_ diff --git a/include/fc/reflect_fwd.hpp b/include/fc/reflect_fwd.hpp deleted file mode 100644 index 6481ffb..0000000 --- a/include/fc/reflect_fwd.hpp +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef _FC_REFLECT_FWD_HPP_ -#define _FC_REFLECT_FWD_HPP_ -/** - * @file reflect_fwd.hpp - * @brief forward declares types defined in reflect.hpp - * - * You should include this file in your headers to accelerate your - * compile times over including reflect.hpp - */ - -namespace fc { - class abstract_reflector; - template class reflector; - class abstract_visitor; - class abstract_const_visitor; - class ref; - class cref; -} - -#define FC_REFLECTABLE( TYPE ) \ -namespace fc{ \ - template<> class reflector : virtual public detail::reflector_impl > { \ - public:\ - enum _is_defined { is_defined = 1 }; \ - virtual const char* name()const; \ - virtual void visit( void* s, const abstract_visitor& v )const; \ - virtual void visit( const void* s, const abstract_const_visitor& v )const; \ - static reflector& instance(); \ - };\ -} - -#endif// _FC_REFLECT_FWD_HPP_ diff --git a/include/fc/reflect_impl.hpp b/include/fc/reflect_impl.hpp deleted file mode 100644 index 1fd38fe..0000000 --- a/include/fc/reflect_impl.hpp +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef _FC_REFLECT_IMPL_HPP_ -#define _FC_REFLECT_IMPL_HPP_ -#include -#include -#include - -/** - * @file reflect_impl.hpp - * @brief defines the FC_REFLECT() macro. - * - * This header uses the boost preprocessor library and - * - */ - -#define FC_REFLECT_FIELD( r, data, i, elem ) \ - v.visit( BOOST_PP_STRINGIZE(elem), i, data, e-> elem ); - -#define FC_REFLECT( NAME, MEMBERS ) \ -namespace fc { \ - const char* reflector::name()const { return BOOST_PP_STRINGIZE(NAME); } \ - void reflector::visit( void* s, const abstract_visitor& v )const { \ - NAME* e = (NAME*)s; \ - BOOST_PP_SEQ_FOR_EACH_I( FC_REFLECT_FIELD, BOOST_PP_SEQ_SIZE(MEMBERS), MEMBERS ) \ - } \ - void reflector::visit( const void* s, const abstract_const_visitor& v )const { \ - const NAME* e = (const NAME*)s; \ - BOOST_PP_SEQ_FOR_EACH_I( FC_REFLECT_FIELD, BOOST_PP_SEQ_SIZE(MEMBERS), MEMBERS ) \ - } \ - reflector& reflector::instance() { static reflector inst; return inst; } \ -} - -#endif // _FC_REFLECT_IMPL_HPP_ diff --git a/include/fc/reflect_ptr.hpp b/include/fc/reflect_ptr.hpp deleted file mode 100644 index 31a3d11..0000000 --- a/include/fc/reflect_ptr.hpp +++ /dev/null @@ -1,48 +0,0 @@ -#ifndef _FC_REFLECT_PTR_HPP_ -#define _FC_REFLECT_PTR_HPP_ -#include - -namespace fc { - - struct ptr { - ptr():_obj(0),_reflector(0){} - - template - ptr( T* v ) - :_obj(v),_reflector(&reflect(*v)){} - - ptr( const ptr& v ) - :_obj(v._obj),_reflector(v._reflector){} - - ref operator*()const { return ref( _obj, *_reflector); } - - private: - friend struct cptr; - void* _obj; - abstract_reflector* _reflector; - }; - - // provides pointer semantics - struct cptr { - cptr():_obj(0),_reflector(0){} - template - - cptr( const T* v ) - :_obj(v),_reflector(&reflect(*v)){} - - cptr( const cptr& v ) - :_obj(v._obj),_reflector(v._reflector){} - - cptr( const ptr& v ) - :_obj(v._obj),_reflector(v._reflector){} - - cref operator*()const { return cref( _obj, *_reflector); } - - private: - const void* _obj; - abstract_reflector* _reflector; - }; - -} - -#endif // _FC_REFLECT_PTR_HPP diff --git a/include/fc/reflect_ref.hpp b/include/fc/reflect_ref.hpp deleted file mode 100644 index e69de29..0000000 diff --git a/include/fc/reflect_tmp.hpp b/include/fc/reflect_tmp.hpp deleted file mode 100644 index 87d2c38..0000000 --- a/include/fc/reflect_tmp.hpp +++ /dev/null @@ -1,125 +0,0 @@ -struct s { - int a; - int b; -}; - -class visitor { - void operator()( const char*, void*, abstract_reflector& r ); -}; - -class abstract_reflector { - virtual void visit( void* s, visitor v ) = 0; -}; - - - -template -class reflector_impl : public abstract_reflector { - public: - virtual void visit( void* s, visitor v ) { - visit( *((S*)s), v ); - } - static Derived& instance() { - static Derived i; - return i; - } -}; - -template<> -class reflector : public reflector_impl< s, reflector > { - void visit( s&, visitor v ) { - v( "a", &s.a, reflector::instance() ) - } - const char* name() { return "s"; } -} - -class abstract_visitor { - // fundamental types called directly - virtual void operator()( double& d ); - virtual void operator()( float& d ); - virtual void operator()( int& d ); - - // objects call this operator for each named member.. - virtual void operator()( const char* member, int idx, void* d, abstract_reflector& v); - - // called for each item in a collection - virtual void operator()( int idx, void* d, abstract_reflector& v); -}; - -class json_visitor : public visitor{ - virtual void operator()( double& d ) { - - } - virtual void operator()( float& d ) { - - } - virtual void operator()( int& d ) { - } - virtual void operator()( void* d, abstract_reflector& v) { - to_json( d, v ); - } -}; - -namespace detail { - string to_json( const void*, abstract_reflector& r ) { - r.visit( v, to_json_visitor( v ) ); - } - void from_json( void*, abstract_reflector& r ); -} - -template -string to_json( const T& v) { - return detail::to_json( &v, reflect(v) ); -} - -struct param { - void* arg; - reflector* ref; -}; - -class invoker_impl { -}; - -class my_interface { - my_interface( invoker::ptr inv ); - - virtual int some_func( Arg a ) { - // this can go in cpp... - return inv->invoke( "some_func", a ); - } -}; - -/** - -*/ -class invoker { - /** - * If variadic templates are supported... use them here. - */ - template - future invoke( string name ) { - auto p = new promise(...) - invoke( p, name, 0 ); - return p; - } - - template - future invoke( const string& name, P1&& p ) { - auto p = new promise(...) - pair params[1]; - params[0].first = &p; - params[0].second = reflector::instance() ); - inv->invoke( p, name, 1, params ); - return p; - } - virtual void invoke( promise::ptr p, const string& s, int num_params = 0, param* params = NULL) = 0; - - /// up to max params... -}; - -class json_rpc_client : public invoker { - -} - - - diff --git a/include/fc/reflect_value.hpp b/include/fc/reflect_value.hpp deleted file mode 100644 index 41ec0ab..0000000 --- a/include/fc/reflect_value.hpp +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef _FC_REFLECT_VALUE_HPP_ -#define _FC_REFLECT_VALUE_HPP_ -#include -#include - -FC_REFLECTABLE( fc::value ) -FC_REFLECTABLE( fc::value::member ) - -#endif // _FC_REFLECT_VALUE_HPP_ diff --git a/include/fc/reflect_vector.hpp b/include/fc/reflect_vector.hpp deleted file mode 100644 index 49e5e22..0000000 --- a/include/fc/reflect_vector.hpp +++ /dev/null @@ -1,48 +0,0 @@ -#ifndef _FC_REFLECT_VECTOR_HPP_ -#define _FC_REFLECT_VECTOR_HPP_ -#include -#include -#include - -namespace fc { - template - class reflector> : public detail::reflector_impl, reflector> >{ - public: - virtual const char* name()const { - static fc::string s = fc::string("vector<") + reflector::instance().name() + '>'; - return s.c_str(); - } - virtual void visit( void* s, const abstract_visitor& v )const { - vector& vec = *((vector*)s); - size_t si = vec.size(); - for( size_t i = 0; i < si; ++i ) v.visit( i, si, vec.at(i) ); - } - virtual void visit( const void* s, const abstract_const_visitor& v )const { - const vector& vec = *((const vector*)s); - size_t si = vec.size(); - v.array_size(si); - for( size_t i = 0; i < si; ++i ) v.visit( i, si, vec.at(i) ); - } - static reflector& instance() { static reflector inst; return inst; } - }; - template<> - class reflector> : public detail::reflector_impl, reflector> >{ - public: - virtual const char* name()const { - return "vector"; - } - virtual void visit( void* s, const abstract_visitor& v )const { - vector& vec = *((vector*)s); - fc::string hex; - v.visit( hex ); - vec.resize( hex.size() / 2 ); - fc::from_hex( hex, vec.data(), vec.size() ); - } - virtual void visit( const void* s, const abstract_const_visitor& v )const { - const vector& vec = *((const vector*)s); - v.visit( fc::to_hex( vec.data(), vec.size() ) ); - } - static reflector& instance() { static reflector inst; return inst; } - }; -} // namespace fc -#endif // _FC_REFLECT_VECTOR_HPP_ diff --git a/include/fc/sha1.hpp b/include/fc/sha1.hpp index d4459b1..34ddb7a 100644 --- a/include/fc/sha1.hpp +++ b/include/fc/sha1.hpp @@ -1,5 +1,4 @@ -#ifndef _FC_SHA1_HPP_ -#define _FC_SHA1_HPP_ +#pragma once #include #include #include @@ -61,7 +60,5 @@ namespace fc { }; } -FC_REFLECTABLE( fc::sha1 ) -#endif // _FC_SHA1_HPP_ diff --git a/include/fc/sstream.hpp b/include/fc/sstream.hpp new file mode 100644 index 0000000..4029e1d --- /dev/null +++ b/include/fc/sstream.hpp @@ -0,0 +1,44 @@ +#pragma once +#include +#include + +namespace fc { + + class stringstream : virtual public iostream { + public: + stringstream(); + stringstream( fc::string& s); + ~stringstream(); + + fc::string str(); + + virtual bool eof()const; + virtual ostream& write( const char* buf, size_t len ); + virtual size_t readsome( char* buf, size_t len ); + virtual istream& read( char* buf, size_t len ); + virtual void close(); + virtual void flush(); + + protected: + virtual istream& read( int64_t& ); + virtual istream& read( uint64_t& ); + virtual istream& read( int32_t& ); + virtual istream& read( uint32_t& ); + virtual istream& read( int16_t& ); + virtual istream& read( uint16_t& ); + virtual istream& read( int8_t& ); + virtual istream& read( uint8_t& ); + virtual istream& read( float& ); + virtual istream& read( double& ); + virtual istream& read( bool& ); + virtual istream& read( char& ); + virtual istream& read( fc::string& ); + + virtual ostream& write( const fc::string& ); + + private: + class impl; + fwd my; + }; + +} diff --git a/include/fc/static_reflect.hpp b/include/fc/static_reflect.hpp deleted file mode 100644 index d70a77b..0000000 --- a/include/fc/static_reflect.hpp +++ /dev/null @@ -1,198 +0,0 @@ - -/** - * @file fc/static_reflect.hpp - * - * @brief Defines types and macros used to provide reflection. - * - */ -#ifndef _FC_STATIC_REFLECT_HPP_ -#define _FC_STATIC_REFLECT_HPP_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -//#include -//#include - -namespace fc { - -/** - * @brief defines visit functions for T - * Unless this is specialized, visit() will not be defined for T. - * - * @tparam T - the type that will be visited. - * - * The @ref FC_STATIC_REFLECT(TYPE,MEMBERS) or FC_STATIC_REFLECT_DERIVED(TYPE,BASES,MEMBERS) macro is used to specialize this - * class for your type. - */ -template -struct static_reflector{ - typedef T type; - typedef fc::false_type is_defined; - typedef fc::false_type is_enum; - - /** - * @tparam Visitor a function object of the form: - * - * @code - * struct functor { - * template - * void operator()( const char* name )const; - * }; - * @endcode - * - * If T is an enum then the functor has the following form: - * @code - * struct functor { - * template - * void operator()( const char* name )const; - * }; - * @endcode - * - * @param v a functor that will be called for each member on T - * - * @note - this method is not defined for non-reflected types. - */ - #ifdef DOXYGEN - template - static inline void visit( const Visitor& v ); - #endif // DOXYGEN -}; - - } // namespace fc - - -#ifndef DOXYGEN - -#define FC_STATIC_REFLECT_VISIT_BASE(r, visitor, base) \ - fc::static_reflector::visit( visitor ); - - -#ifndef WIN32 - #define TEMPLATE template -#else - #define TEMPLATE -#endif -#include -#define FC_STATIC_REFLECT_VISIT_MEMBER( r, visitor, elem ) \ - visitor.TEMPLATE operator()elem), type, &type::elem>( BOOST_PP_STRINGIZE(elem) ); - - -#define FC_STATIC_REFLECT_BASE_MEMBER_COUNT( r, OP, elem ) \ - OP fc::static_reflector::member_count - -#define FC_STATIC_REFLECT_DERIVED_IMPL_INLINE( TYPE, INHERITS, MEMBERS ) \ -template\ -static inline void visit( const Visitor& v ) { \ - BOOST_PP_SEQ_FOR_EACH( FC_STATIC_REFLECT_VISIT_BASE, v, INHERITS ) \ - BOOST_PP_SEQ_FOR_EACH( FC_STATIC_REFLECT_VISIT_MEMBER, v, MEMBERS ) \ -} - -#define FC_STATIC_REFLECT_DERIVED_IMPL_EXT( TYPE, INHERITS, MEMBERS ) \ -template\ -void fc::static_reflector::visit( const Visitor& v ) { \ - BOOST_PP_SEQ_FOR_EACH( FC_STATIC_REFLECT_VISIT_BASE, v, INHERITS ) \ - BOOST_PP_SEQ_FOR_EACH( FC_STATIC_REFLECT_VISIT_MEMBER, v, MEMBERS ) \ -} - -#endif // DOXYGEN - - -#define FC_STATIC_REFLECT_VISIT_ENUM( r, visitor, elem ) \ - visitor.TEMPLATE operator()(BOOST_PP_STRINGIZE(elem)); -#define FC_STATIC_REFLECT_ENUM_TO_STRING( r, visitor, elem ) \ - case elem: return BOOST_PP_STRINGIZE(elem); - -#define FC_STATIC_REFLECT_ENUM_FROM_STRING( r, visitor, elem ) \ - if( strcmp( s, BOOST_PP_STRINGIZE(elem) ) == 0 ) return elem; - -#define FC_STATIC_REFLECT_ENUM( ENUM, FIELDS ) \ -namespace fc { \ -template<> struct static_reflector { \ - typedef fc::true_type is_defined; \ - typedef fc::true_type is_enum; \ - template \ - static inline void visit( const Visitor& v ) { \ - BOOST_PP_SEQ_FOR_EACH( FC_STATIC_REFLECT_VISIT_ENUM, v, FIELDS ) \ - }\ - static const char* to_string(int64_t i) { \ - switch( ENUM(i) ) { \ - BOOST_PP_SEQ_FOR_EACH( FC_STATIC_REFLECT_ENUM_TO_STRING, v, FIELDS ) \ - default: \ - FC_STATIC_REFLECT_THROW( fc::reflect::unknown_field(), "%1% not in enum '%2%'", %i %BOOST_PP_STRINGIZE(ENUM) ); \ - }\ - } \ - static ENUM from_string( const char* s ) { \ - BOOST_PP_SEQ_FOR_EACH( FC_STATIC_REFLECT_ENUM_FROM_STRING, v, FIELDS ) \ - FC_STATIC_REFLECT_THROW( fc::reflect::unknown_field(), "%1% in enum %2%", %s %BOOST_PP_STRINGIZE(ENUM) ); \ - } \ -}; \ -} } - - - -/** - * @def FC_STATIC_REFLECT_DERIVED(TYPE,INHERITS,MEMBERS) - * - * @brief Specializes fc::static_reflector for TYPE where - * type inherits other reflected classes - * - * @param INHERITS - a sequence of base class names (basea)(baseb)(basec) - * @param MEMBERS - a sequence of member names. (field1)(field2)(field3) - */ -#define FC_STATIC_REFLECT_DERIVED( TYPE, INHERITS, MEMBERS ) \ -namespace fc { \ -template<> struct static_reflector {\ - typedef TYPE type; \ - typedef fc::true_type is_defined; \ - typedef fc::false_type is_enum; \ - enum member_count_enum { \ - local_member_count = BOOST_PP_SEQ_SIZE(MEMBERS), \ - total_member_count = local_member_count BOOST_PP_SEQ_FOR_EACH( FC_STATIC_REFLECT_BASE_MEMBER_COUNT, +, INHERITS )\ - }; \ - FC_STATIC_REFLECT_DERIVED_IMPL_INLINE( TYPE, INHERITS, MEMBERS ) \ -}; } - - -/** - * @def FC_STATIC_REFLECT(TYPE,MEMBERS) - * @brief Specializes fc::static_reflector for TYPE - * - * @param MEMBERS - a sequence of member names. (field1)(field2)(field3) - * - * @see FC_STATIC_REFLECT_DERIVED - */ -#define FC_STATIC_REFLECT( TYPE, MEMBERS ) \ - FC_STATIC_REFLECT_DERIVED( TYPE, BOOST_PP_SEQ_NIL, MEMBERS ) - -#define FC_STATIC_REFLECT_FWD( TYPE ) \ -namespace fc { \ -template<> struct static_reflector {\ - typedef TYPE type; \ - typedef fc::true_type is_defined; \ - enum member_count_enum { \ - local_member_count = BOOST_PP_SEQ_SIZE(MEMBERS), \ - total_member_count = local_member_count BOOST_PP_SEQ_FOR_EACH( FC_STATIC_REFLECT_BASE_MEMBER_COUNT, +, INHERITS )\ - }; \ - template static void visit( const Visitor& v ); \ -}; } - - -#define FC_STATIC_REFLECT_DERIVED_IMPL( TYPE, MEMBERS ) \ - FC_STATIC_REFLECT_IMPL_DERIVED_EXT( TYPE, BOOST_PP_SEQ_NIL, MEMBERS ) - -#define FC_STATIC_REFLECT_IMPL( TYPE, MEMBERS ) \ - FC_STATIC_REFLECT_DERIVED_IMPL_EXT( TYPE, BOOST_PP_SEQ_NIL, MEMBERS ) - - - -#endif diff --git a/include/fc/stream.hpp b/include/fc/stream.hpp index 1235384..f5f97fc 100644 --- a/include/fc/stream.hpp +++ b/include/fc/stream.hpp @@ -1,244 +1,93 @@ -#ifndef _FC_STREAM_HPP_ -#define _FC_STREAM_HPP_ +#pragma once #include -#include +#include namespace fc { class string; - namespace detail { - template - struct has_close { - typedef char (&no_tag)[1]; - typedef char (&yes_tag)[2]; - - template struct has_close_helper{}; - - template - static no_tag has_member_helper(...); - - template - static yes_tag has_member_helper( has_close_helper* p); - - enum closed_value { value = sizeof(has_member_helper(0)) == sizeof(yes_tag) }; - }; - - template::value> - struct if_close { static void close( C& c ) { c.close(); } }; - - template - struct if_close { static void close( C& ) { } }; - - - - class abstract_istream { - public: - abstract_istream(); - virtual ~abstract_istream(); - size_t readsome( char* buf, size_t len ); - - virtual size_t readsome_impl( char* buf, size_t len ) = 0; - - //private: - // store a boost::iostreams device that will do - // the actual reading/writing for the stream operators - //void* _store[51]; - char _store[51*sizeof(void*)]; - }; - - template - class istream : public abstract_istream { - public: - istream( IStream& i ):_in(i){} - - virtual size_t readsome_impl( char* buf, size_t len ) { - return _in.readsome(buf,len); - } - - private: - IStream& _in; - }; - - class abstract_ostream { - public: - abstract_ostream(); - virtual ~abstract_ostream(); - size_t write( const char* buf, size_t len ); - void close(); - void flush(); - - virtual void close_impl() = 0; - virtual void flush_impl() = 0; - virtual size_t write_impl( const char* buf, size_t len ) = 0; -// private: - // store a boost::iostreams device that will do - // the actual reading/writing for the stream operators - void* _store[50]; - }; - - template - class ostream : public abstract_ostream { - public: - ostream( OStream& o ):_out(o){} - - virtual size_t write_impl( const char* buf, size_t len ) { - _out.write(buf,len); - return len; - } - virtual void close_impl() { if_close::close(_out); } - virtual void flush_impl() { _out.flush(); } - - private: - OStream& _out; - }; - - } class istream { public: - template - istream( IStream& is ) { - static_assert( sizeof(detail::istream(is)) <= sizeof(_store), "Failed to reserve enough space"); - new ((void*)&_store[0]) detail::istream(is); - } - ~istream(); + virtual ~istream(){}; - size_t readsome( char* buf, size_t len ); + virtual size_t readsome( char* buf, size_t len ) = 0; - friend istream& operator>>( istream&, int64_t& ); - friend istream& operator>>( istream&, uint64_t& ); - friend istream& operator>>( istream&, int32_t& ); - friend istream& operator>>( istream&, uint32_t& ); - friend istream& operator>>( istream&, int16_t& ); - friend istream& operator>>( istream&, uint16_t& ); - friend istream& operator>>( istream&, int8_t& ); - friend istream& operator>>( istream&, uint8_t& ); - friend istream& operator>>( istream&, float& ); - friend istream& operator>>( istream&, double& ); - friend istream& operator>>( istream&, bool& ); - friend istream& operator>>( istream&, char& ); - friend istream& operator>>( istream&, fc::string& ); + template + friend istream& operator>>( istream& i, T& v ){ return i.read(v); } - private: - istream( const istream& ); - istream& operator=(const istream& ); - void* _store[54]; + virtual bool eof()const = 0; + + protected: + virtual istream& read( int64_t& ) = 0; + virtual istream& read( uint64_t& ) = 0; + virtual istream& read( int32_t& ) = 0; + virtual istream& read( uint32_t& ) = 0; + virtual istream& read( int16_t& ) = 0; + virtual istream& read( uint16_t& ) = 0; + virtual istream& read( int8_t& ) = 0; + virtual istream& read( uint8_t& ) = 0; + virtual istream& read( float& ) = 0; + virtual istream& read( double& ) = 0; + virtual istream& read( bool& ) = 0; + virtual istream& read( char& ) = 0; + virtual istream& read( fc::string& ) = 0; }; class ostream { public: - template - ostream( OStream& os ) { - static_assert( sizeof(detail::ostream(os)) <= sizeof(_store), "Failed to reserve enough space"); - new ((void*)&_store[0]) detail::ostream(os); - } + virtual ~ostream(){}; - ~ostream(); + virtual size_t write( const char* buf, size_t len ) = 0; + virtual void close() = 0; + virtual void flush() = 0; - size_t write( const char* buf, size_t len ); - void close(); - void flush(); + template + friend ostream& operator<<( ostream& o, const T& v ){ return o.write(fc::lexical_cast(v)); } - friend ostream& operator<<( ostream&, int64_t ); - friend ostream& operator<<( ostream&, uint64_t ); - friend ostream& operator<<( ostream&, int32_t ); - friend ostream& operator<<( ostream&, uint32_t ); - friend ostream& operator<<( ostream&, int16_t ); - friend ostream& operator<<( ostream&, uint16_t ); - friend ostream& operator<<( ostream&, int8_t ); - friend ostream& operator<<( ostream&, uint8_t ); - friend ostream& operator<<( ostream&, float ); - friend ostream& operator<<( ostream&, double ); - friend ostream& operator<<( ostream&, bool ); - friend ostream& operator<<( ostream&, char ); - friend ostream& operator<<( ostream&, const char* ); - friend ostream& operator<<( ostream&, const fc::string& ); + protected: + virtual ostream& write( const fc::string& ) = 0; + }; + class iostream : public virtual ostream, public virtual istream {}; - private: - ostream( const ostream& o ); - ostream& operator=(const ostream& o); - void* _store[54]; + bool getline( fc::istream&, fc::string&, char delim = '\n' ); + + struct cout_t : virtual public ostream { + virtual size_t write( const char* buf, size_t len ); + virtual void close(); + virtual void flush(); + + virtual ostream& write( const fc::string& ); }; - bool getline( fc::istream&, fc::string& ); + struct cerr_t : virtual public ostream { + virtual size_t write( const char* buf, size_t len ); + virtual void close(); + virtual void flush(); - class stringstream { - public: - stringstream(); - stringstream( fc::string& s); - ~stringstream(); - - fc::string str(); - - friend stringstream& operator>>( stringstream&, int64_t& ); - friend stringstream& operator>>( stringstream&, uint64_t& ); - friend stringstream& operator>>( stringstream&, int32_t& ); - friend stringstream& operator>>( stringstream&, uint32_t& ); - friend stringstream& operator>>( stringstream&, int16_t& ); - friend stringstream& operator>>( stringstream&, uint16_t& ); - friend stringstream& operator>>( stringstream&, int8_t& ); - friend stringstream& operator>>( stringstream&, uint8_t& ); - friend stringstream& operator>>( stringstream&, float& ); - friend stringstream& operator>>( stringstream&, double& ); - friend stringstream& operator>>( stringstream&, bool& ); - friend stringstream& operator>>( stringstream&, char& ); - friend stringstream& operator>>( stringstream&, fc::string& ); - - friend stringstream& operator<<( stringstream&, const int64_t& ); - friend stringstream& operator<<( stringstream&, const uint64_t& ); - friend stringstream& operator<<( stringstream&, const int32_t& ); - friend stringstream& operator<<( stringstream&, const uint32_t& ); - friend stringstream& operator<<( stringstream&, const int16_t& ); - friend stringstream& operator<<( stringstream&, const uint16_t& ); - friend stringstream& operator<<( stringstream&, const int8_t& ); - friend stringstream& operator<<( stringstream&, const uint8_t& ); - friend stringstream& operator<<( stringstream&, const float& ); - friend stringstream& operator<<( stringstream&, const double& ); - friend stringstream& operator<<( stringstream&, const bool& ); - friend stringstream& operator<<( stringstream&, const char& ); - friend stringstream& operator<<( stringstream&, const fc::string& ); - friend stringstream& operator<<( stringstream&, const char* ); - private: - class impl; - fwd my; + virtual ostream& write( const fc::string& ); }; - class ofstream { - public: - enum mode { out, binary }; - ofstream(); - ofstream( const fc::string& file, int m ); - ~ofstream(); + struct cin_t : virtual public istream { + virtual size_t readsome( char* buf, size_t len ); + virtual bool eof()const; - void open( const fc::string& file, int m ); - ofstream& write( const char* buf, size_t len ); - void put( char c ); - void close(); - void flush(); - - private: - class impl; - fwd my; - }; - class ifstream { - public: - enum mode { in, binary }; - ifstream(); - ifstream( const fc::string& file, int m ); - ~ifstream(); - - void open( const fc::string& file, int m ); - ifstream& read( char* buf, size_t len ); - void close(); - void flush(); - - private: - class impl; - fwd my; + virtual istream& read( int64_t& ); + virtual istream& read( uint64_t& ); + virtual istream& read( int32_t& ); + virtual istream& read( uint32_t& ); + virtual istream& read( int16_t& ); + virtual istream& read( uint16_t& ); + virtual istream& read( int8_t& ); + virtual istream& read( uint8_t& ); + virtual istream& read( float& ); + virtual istream& read( double& ); + virtual istream& read( bool& ); + virtual istream& read( char& ); + virtual istream& read( fc::string& ); }; - extern ostream cout; - extern ostream cerr; - extern istream cin; + + extern cout_t cout; + extern cerr_t cerr; + extern cin_t cin; } -#endif // _FC_STREAM_HPP_ diff --git a/include/fc/typename.hpp b/include/fc/typename.hpp new file mode 100644 index 0000000..43ff822 --- /dev/null +++ b/include/fc/typename.hpp @@ -0,0 +1,19 @@ +#pragma once +namespace fc { + class string; + template class get_typename{}; + template<> struct get_typename { static const char* name() { return "int32_t"; } }; + template<> struct get_typename { static const char* name() { return "int64_t"; } }; + template<> struct get_typename { static const char* name() { return "int16_t"; } }; + template<> struct get_typename { static const char* name() { return "int8_t"; } }; + template<> struct get_typename { static const char* name() { return "uint32_t"; } }; + template<> struct get_typename { static const char* name() { return "uint64_t"; } }; + template<> struct get_typename { static const char* name() { return "uint16_t"; } }; + template<> struct get_typename { static const char* name() { return "uint8_t"; } }; + template<> struct get_typename { static const char* name() { return "double"; } }; + template<> struct get_typename { static const char* name() { return "float"; } }; + template<> struct get_typename { static const char* name() { return "bool"; } }; + template<> struct get_typename { static const char* name() { return "char"; } }; + template<> struct get_typename { static const char* name() { return "char"; } }; + template<> struct get_typename { static const char* name() { return "string"; } }; +} diff --git a/include/fc/utility.hpp b/include/fc/utility.hpp index 10e7a01..f7be959 100644 --- a/include/fc/utility.hpp +++ b/include/fc/utility.hpp @@ -31,7 +31,7 @@ namespace fc { } template - struct is_class { typedef decltype(detail::is_class_helper(0)) type; }; + struct is_class { typedef decltype(detail::is_class_helper(0)) type; enum value_enum { value = type::value }; }; template const T& min( const T& a, const T& b ) { return a < b ? a: b; } diff --git a/include/fc/value.hpp b/include/fc/value.hpp index 7d4d17f..68f0ecc 100644 --- a/include/fc/value.hpp +++ b/include/fc/value.hpp @@ -1,141 +1,165 @@ -#ifndef _FC_VALUE_HPP_ -#define _FC_VALUE_HPP_ -#include -#include -#include -#include -#include +#pragma once + +#include +#include +#include namespace fc { - class string; - - /** - * @brief dynamic type that will store any reflected type. - * - * A struct can be stored directly or 'exploded' to be stored - * as individual elements. Direct storage is more effecient (no - * need to allocate/manage keys), but does not support adding / removing - * keys. - * - */ - class value { - public: - struct member { - member(); - member(const char* key); - member(string&& key ); + /** + * @brief a dynamic container that can hold + * integers, reals, strings, booleans, arrays, and + * or null. + * + * This type serves as an intermediate representation between + * C++ type and serialized type (JSON,XML,etc). + * + * As much as possible value attempts to preserve 'type' information, but + * type information is not always provided equally by all serialization formats. + * + * value is move aware, so move it when you can to avoid expensive copies + */ + class value { + public: + struct key_val; + struct object { + typedef fc::vector::const_iterator const_iterator; + //fc::string type; + fc::vector fields; + }; + struct array { + //fc::string type; + fc::vector fields; + }; - const string& key()const; - value& val(); - const value& val()const; + 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()( ){}; + }; - private: - friend class value; - friend class reflector; - fwd _key; - fwd _val; - }; - typedef member* iterator; - typedef const member* const_iterator; + value(); + value( value&& m ); + value( const value& m ); - value(); + 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& ); - template - explicit value( T&& t ):_obj(nullptr),_obj_type(nullptr) { - *this = cref(fc::forward(t)); - } + value( object&& o ); + value( const object& o ); + value( object& o ); - value( value&& v ); - value( const value& v ); - value( const cref& v ); - ~value(); + value( array&& a ); + value( array& a ); + value( const array& a ); - value& operator=( value&& v ); - value& operator=( const value& v ); - value& operator=( const cref& v ); + ~value(); - template - value& operator=( T&& t ) { - value temp(fc::forward(t)); - swap(temp,*this); + value& operator=( value&& v ); + value& operator=( const value& v ); + + /** + * Include fc/value_cast.hpp for implementation + */ + template + explicit value( T&& v ); + + template + value& operator=( T&& v ) { + value tmp(fc::forward(v) ); + fc::swap(*this,tmp); return *this; - } + } - template - value& push_back( T&& v ) { return push_back( value( forward(v) ) ); } - value& push_back( value&& v ); - value& push_back( const value& v ); + /** 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 begin()const; + object::const_iterator end()const; - /** - * These methods will create the key if it - * does not exist. - * @{ - */ - /** - * @pre value is null or an object - */ - value& operator[]( const string& key ); - /** - * @pre value is null or an object - */ - value& operator[]( const char* key ); - /** - * @pre value is null or an array or index is 0 - */ - value& operator[]( uint64_t index ); - value& operator[]( int index ); - /** @} */ + /** 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[]( string&& key ); + /** array & object interface **/ + void clear(); + size_t size()const; - const value& operator[]( const string& key )const; - const value& operator[]( const char* key )const; - const value& operator[]( uint64_t )const; + /** array interface **/ + void resize( size_t s ); + void reserve( size_t s ); + void push_back( value&& v ); + value& operator[]( int32_t idx ); + const value& operator[]( int32_t idx )const; - bool key_exists( const string& key ); - bool key_exists( const char* key ); - bool is_array()const; - bool is_object()const; - bool is_null()const; - bool is_string()const; - bool is_real()const; - bool is_float()const; - bool is_double()const; - bool is_integer()const; - bool is_int64()const; - bool is_int32()const; - bool is_int16()const; - bool is_int8()const; - bool is_boolean()const; + /** gets the stored type **/ + const char* type()const; + bool is_null()const; - template - bool is()const { - return _obj_type == reflector::instance(); - } + void visit( const_visitor&& v )const; + private: + /** throws exceptions on errors + * + * Defined in fc/value_cast.hpp because it depends upon + * reflection + */ + template + friend T value_cast( const value& v ); - fwd,24> get_keys()const; + aligned<24> holder; + }; - iterator find( const char* key ); - const_iterator find( const char* key )const; - iterator begin(); - const_iterator begin()const; - const_iterator end()const; + struct value::key_val { + key_val(){}; + + key_val( fc::string k, value v = value()) + :key(fc::move(k)),val(fc::move(v)){} + + key_val( key_val&& m ) + :key(fc::move(m.key)),val(fc::move(m.val)){} + + key_val( const key_val& m ) + :key(m.key),val(m.val){} + + key_val& operator=( key_val&& k ) { + key = fc::move(k.key); + val = fc::move(k.val); + return *this; + } + key_val& operator=( const key_val& k ) { + key = k.key; + val = k.val; + return *this; + } + + fc::string key; + value val; + }; - void* ptr(); - const void* ptr()const; - abstract_reflector* type()const; - private: - template friend const T& value_cast( const value& v ); - template friend T& value_cast( value& v ); - template friend T* value_cast( value* v ); - template friend const T* value_cast( const value* v ); - template friend T reinterpret_value_cast( const value& v ); +} // namespace fc - void* _obj; - abstract_reflector* _obj_type; - }; - -}; - - -#endif // _MACE_VALUE_HPP_ diff --git a/include/fc/value_cast.hpp b/include/fc/value_cast.hpp index f348989..8065310 100644 --- a/include/fc/value_cast.hpp +++ b/include/fc/value_cast.hpp @@ -1,100 +1,196 @@ -#ifndef _FC_VALUE_CAST_HPP_ -#define _FC_VALUE_CAST_HPP_ -#include +#pragma once #include -#include +#include #include +#include +#include +#include namespace fc { - template - const T& value_cast( const value& v ) { - if( &reflector::instance() == v._obj_type ) { - if( v._obj_type->size_of() <= 8 ) { - slog( "stack..." ); - return *((const T*)&v._obj); - } - slog( "heap..." ); - return *((const T*)v._obj); + namespace detail { + + template + struct cast_visitor : value::const_visitor { + cast_visitor( T& out ) + :m_out(out){} + virtual void operator()( const int8_t& v ){ m_out = fc::numeric_cast(v); } + virtual void operator()( const int16_t& v ){ m_out = fc::numeric_cast(v); } + virtual void operator()( const int32_t& v ){ m_out = fc::numeric_cast(v); } + virtual void operator()( const int64_t& v ){ m_out = fc::numeric_cast(v); } + virtual void operator()( const uint8_t& v ){ m_out = fc::numeric_cast(v); } + virtual void operator()( const uint16_t& v ){ m_out = fc::numeric_cast(v); } + virtual void operator()( const uint32_t& v ){ m_out = fc::numeric_cast(v); } + virtual void operator()( const uint64_t& v ){ m_out = fc::numeric_cast(v); } + virtual void operator()( const float& v ){ m_out = fc::numeric_cast(v); } + virtual void operator()( const double& v ){ m_out = fc::numeric_cast(v); } + virtual void operator()( const bool& v ){ m_out = fc::numeric_cast(v); } + virtual void operator()( const fc::string& v ) { m_out = fc::lexical_cast(v); } + virtual void operator()( const value::object& ) { FC_THROW_MSG("bad cast"); } + virtual void operator()( const value::array& ) { FC_THROW_MSG("bad cast"); } + virtual void operator()( ) { FC_THROW_MSG("bad cast"); } + private: + T& m_out; + }; + + template<> + struct cast_visitor : value::const_visitor { + cast_visitor( fc::string& out ) + :m_out(out){} + virtual void operator()( const int8_t& v ){ m_out = fc::lexical_cast(v); } + virtual void operator()( const int16_t& v ){ m_out = fc::lexical_cast(v); } + virtual void operator()( const int32_t& v ){ m_out = fc::lexical_cast(v); } + virtual void operator()( const int64_t& v ){ m_out = fc::lexical_cast(v); } + virtual void operator()( const uint8_t& v ){ m_out = fc::lexical_cast(v); } + virtual void operator()( const uint16_t& v ){ m_out = fc::lexical_cast(v); } + virtual void operator()( const uint32_t& v ){ m_out = fc::lexical_cast(v); } + virtual void operator()( const uint64_t& v ){ m_out = fc::lexical_cast(v); } + virtual void operator()( const float& v ){ m_out = fc::lexical_cast(v); } + virtual void operator()( const double& v ){ m_out = fc::lexical_cast(v); } + virtual void operator()( const bool& v ){ m_out = fc::lexical_cast(v); } + virtual void operator()( const fc::string& v ){ m_out = v; } + virtual void operator()( const value::object& ) { FC_THROW_MSG("bad cast"); } + virtual void operator()( const value::array& ) { FC_THROW_MSG("bad cast"); } + virtual void operator()( ) { FC_THROW_MSG("bad cast"); } + + private: + fc::string& m_out; + }; + + template<> + struct cast_visitor : value::const_visitor { + cast_visitor( value::array& out ) + :m_out(out){} + virtual void operator()( const int8_t& v ){ FC_THROW_MSG("bad cast");} + virtual void operator()( const int16_t& v ){ FC_THROW_MSG("bad cast");} + virtual void operator()( const int32_t& v ){ FC_THROW_MSG("bad cast");} + virtual void operator()( const int64_t& v ){ FC_THROW_MSG("bad cast");} + virtual void operator()( const uint8_t& v ){ FC_THROW_MSG("bad cast");} + virtual void operator()( const uint16_t& v ){ FC_THROW_MSG("bad cast");} + virtual void operator()( const uint32_t& v ){ FC_THROW_MSG("bad cast");} + virtual void operator()( const uint64_t& v ){ FC_THROW_MSG("bad cast");} + virtual void operator()( const float& v ){ FC_THROW_MSG("bad cast");} + virtual void operator()( const double& v ){ FC_THROW_MSG("bad cast");} + virtual void operator()( const bool& v ){ FC_THROW_MSG("bad cast");} + virtual void operator()( const fc::string& v ){ FC_THROW_MSG("bad cast");} + virtual void operator()( const value::object& ) { FC_THROW_MSG("bad cast");} + virtual void operator()( const value::array& a ) { m_out = a; } + virtual void operator()( ) { FC_THROW_MSG("bad cast");} + + private: + value::array& m_out; + }; + + template<> + struct cast_visitor : value::const_visitor { + cast_visitor( value::object& out ) + :m_out(out){} + virtual void operator()( const int8_t& v ){ FC_THROW_MSG("bad cast");} + virtual void operator()( const int16_t& v ){ FC_THROW_MSG("bad cast");} + virtual void operator()( const int32_t& v ){ FC_THROW_MSG("bad cast");} + virtual void operator()( const int64_t& v ){ FC_THROW_MSG("bad cast");} + virtual void operator()( const uint8_t& v ){ FC_THROW_MSG("bad cast");} + virtual void operator()( const uint16_t& v ){ FC_THROW_MSG("bad cast");} + virtual void operator()( const uint32_t& v ){ FC_THROW_MSG("bad cast");} + virtual void operator()( const uint64_t& v ){ FC_THROW_MSG("bad cast");} + virtual void operator()( const float& v ){ FC_THROW_MSG("bad cast");} + virtual void operator()( const double& v ){ FC_THROW_MSG("bad cast");} + virtual void operator()( const bool& v ){ FC_THROW_MSG("bad cast");} + virtual void operator()( const fc::string& v ){ FC_THROW_MSG("bad cast");} + virtual void operator()( const value::object& a ) { m_out = a; } + virtual void operator()( const value::array& ) { FC_THROW_MSG("bad cast");} + virtual void operator()( ) { FC_THROW_MSG("bad cast");} + + private: + value::object& m_out; + }; + template<> + struct cast_visitor : value::value::const_visitor { + virtual void operator()( const int8_t& v ) { FC_THROW_MSG("bad cast");} + virtual void operator()( const int16_t& v ) { FC_THROW_MSG("bad cast");} + virtual void operator()( const int32_t& v ) { FC_THROW_MSG("bad cast");} + virtual void operator()( const int64_t& v ) { FC_THROW_MSG("bad cast");} + virtual void operator()( const uint8_t& v ) { FC_THROW_MSG("bad cast");} + virtual void operator()( const uint16_t& v ) { FC_THROW_MSG("bad cast");} + virtual void operator()( const uint32_t& v ) { FC_THROW_MSG("bad cast");} + virtual void operator()( const uint64_t& v ) { FC_THROW_MSG("bad cast");} + virtual void operator()( const float& v ) { FC_THROW_MSG("bad cast");} + virtual void operator()( const double& v ) { FC_THROW_MSG("bad cast");} + virtual void operator()( const bool& v ) { FC_THROW_MSG("bad cast");} + virtual void operator()( const fc::string& v ) { FC_THROW_MSG("bad cast");} + virtual void operator()( const value::object& a ) { FC_THROW_MSG("bad cast");} + virtual void operator()( const value::array& ) { FC_THROW_MSG("bad cast");} + virtual void operator()( ) { } + }; + + template + struct cast_if_reflected { + template + static T cast( const value& v ) { + T out; + v.visit(cast_visitor(out)); + return out; + } + }; + + template<> + struct cast_if_reflected { + template + static T cast( const value& v ) { + T tmp; + unpack(v,tmp); + return tmp; + } + }; + + 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; + }; + + } // namespace detail + + + /** + * Convert from value v to T + * + * Performs the following conversions + * true -> 1.0, 1, "true" + * + * Not all casts are 'clean', the following conversions + * could cause errors: + * + * signed int -> unsigned + * large int -> smaller int + * real -> int + * non-numeric string -> number + * object -> string or number + * array -> string or number + * number,string,array -> object + */ + template + T value_cast( const value& v ) { + return detail::cast_if_reflected::is_defined>::template cast(v); } - FC_THROW( bad_cast() ); - } - template - T& value_cast( value& v ) { - if( &reflector::instance() == v._obj_type ) { - if( v._obj_type->size_of() <= 8 ) { - slog( "stack..." ); - return *((T*)&v._obj); - } - slog( "heap..." ); - return *((T*)v._obj); + + template + value::value( T&& v ) { + new (holder) detail::value_holder(); + fc::pack( *this, std::forward(v) ); } - FC_THROW( bad_cast() ); - } - - template - T* value_cast( value* v ) { - } - - template - const T* value_cast( const value* v ) { - } - - - template class reinterpret_value_visitor; - - #define CAST_VISITOR_DECL(X) \ - template<> class reinterpret_value_visitor : public abstract_const_visitor { \ - private: X& _s; \ - public: \ - reinterpret_value_visitor( X& s ):_s(s){} \ - virtual void visit()const; \ - virtual void visit( const char& c )const; \ - virtual void visit( const uint8_t& c )const; \ - virtual void visit( const uint16_t& c )const; \ - virtual void visit( const uint32_t& c )const; \ - virtual void visit( const uint64_t& c )const; \ - virtual void visit( const int8_t& c )const; \ - virtual void visit( const int16_t& c )const; \ - virtual void visit( const int32_t& c )const; \ - virtual void visit( const int64_t& c )const; \ - virtual void visit( const double& c )const; \ - virtual void visit( const float& c )const; \ - virtual void visit( const bool& c )const; \ - virtual void visit( const string& c )const; \ - virtual void visit( const char* member, int idx, int size, const cref& v)const;\ - virtual void visit( int idx, int size, const cref& v)const; \ - virtual void array_size( int size )const{} \ - virtual void object_size( int size )const{} \ - } - - CAST_VISITOR_DECL(int64_t); - CAST_VISITOR_DECL(int32_t); - CAST_VISITOR_DECL(int16_t); - CAST_VISITOR_DECL(int8_t); - CAST_VISITOR_DECL(uint64_t); - CAST_VISITOR_DECL(uint32_t); - CAST_VISITOR_DECL(uint16_t); - CAST_VISITOR_DECL(uint8_t); - CAST_VISITOR_DECL(double); - CAST_VISITOR_DECL(float); - CAST_VISITOR_DECL(bool); - CAST_VISITOR_DECL(string); - - - template - T reinterpret_value_cast( const value& v ) { - if( v.is_null() ) FC_THROW( bad_cast() ); - T r; - reinterpret_value_visitor vis(r); - if( v._obj_type->size_of() > sizeof(v._obj) ) - v._obj_type->visit( v._obj, vis ); - else - v._obj_type->visit( &v._obj, vis ); - return r; - } - } - - -#endif // _FC_VALUE_CAST_HPP_ diff --git a/include/fc/value_fwd.hpp b/include/fc/value_fwd.hpp deleted file mode 100644 index 10cc607..0000000 --- a/include/fc/value_fwd.hpp +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef _FC_VALUE_FWD_HPP_ -#define _FC_VALUE_FWD_HPP_ -#include - -namespace fc { - class value; - typedef fwd value_fwd; -} - -#endif // _MACE_VALUE_FWD_HPP_ diff --git a/include/fc/value_io.hpp b/include/fc/value_io.hpp new file mode 100644 index 0000000..e1db815 --- /dev/null +++ b/include/fc/value_io.hpp @@ -0,0 +1,255 @@ +#pragma once + +#include +#include +#include +#include + +namespace fc { + struct void_t{}; + + template + void pack(fc::value& jsv, const T& v ); + + template + void unpack( const fc::value& jsv, T& v ); + + template + void pack( fc::value& jsv, const fc::optional& v ); + + template + void unpack( const fc::value& jsv, fc::optional& v ); + + inline void pack( fc::value& jsv, const fc::value& v ) { jsv = v; } + inline void pack( fc::value& jsv, fc::value& v ) { jsv = v; } + inline void pack( fc::value& jsv, fc::value&& v ) { jsv = fc::move(v); } + inline void pack( fc::value& jsv, const void_t& v ) { jsv = fc::value(); } + inline void pack( fc::value& jsv, const bool& v ) { jsv = v; } + inline void pack( fc::value& jsv, const float& v ) { jsv = v; } + inline void pack( fc::value& jsv, const double& v ) { jsv = v; } + inline void pack( fc::value& jsv, const uint8_t& v ) { jsv = v; } + inline void pack( fc::value& jsv, const uint16_t& v ) { jsv = v; } + inline void pack( fc::value& jsv, const uint32_t& v ) { jsv = v; } + inline void pack( fc::value& jsv, const uint64_t& v ) { jsv = v; } + inline void pack( fc::value& jsv, const int8_t& v ) { jsv = v; } + inline void pack( fc::value& jsv, const int16_t& v ) { jsv = v; } + inline void pack( fc::value& jsv, const int32_t& v ) { jsv = v; } + inline void pack( fc::value& jsv, const int64_t& v ) { jsv = v; } + inline void pack( fc::value& jsv, const fc::string& v ) { jsv = v; } + inline void pack( fc::value& jsv, fc::string& v ) { jsv = v; } + inline void pack( fc::value& jsv, fc::string&& v ) { jsv = fc::move(v); } + inline void pack( fc::value& jsv, const char* v ) { jsv = fc::string(v); } + + void pack( fc::value& jsv, const fc::vector& value ); + template + void pack( fc::value& jsv, const fc::vector& value ); + + + inline void unpack( const fc::value& jsv, fc::value& v ) { v = jsv; } + template + void unpack( const fc::value& jsv, const T& v ); + template + void unpack( const fc::value& jsv, T& v ); + void unpack( const fc::value& jsv, bool& v ); + + inline void unpack( const fc::value& jsv, void_t& v ){ }; + + void unpack( const fc::value& jsv, float& v ); + void unpack( const fc::value& jsv, double& v ); + void unpack( const fc::value& jsv, uint8_t& v ); + void unpack( const fc::value& jsv, uint16_t& v ); + void unpack( const fc::value& jsv, uint32_t& v ); + void unpack( const fc::value& jsv, uint64_t& v ); + void unpack( const fc::value& jsv, int8_t& v ); + void unpack( const fc::value& jsv, int16_t& v ); + void unpack( const fc::value& jsv, int32_t& v ); + void unpack( const fc::value& jsv, int64_t& v ); + void unpack( const fc::value& jsv, fc::string& v ); + + void unpack( const fc::value& jsv, fc::vector& value ); + + void unpack( const fc::value& jsv, fc::vector& value ); + template + void unpack( const fc::value& jsv, fc::vector& value ); + + namespace detail { + template + struct pack_object_visitor { + pack_object_visitor(const Class& _c, fc::value& _val) + :c(_c),obj(_val){} + + /** + VC++ does not understand the difference of return types, so an extra layer is needed. + */ + template + inline void pack_helper( const T& v, const char* name )const { + fc::pack( obj[name], v ); + } + template + inline void pack_helper( const fc::optional& v, const char* name )const { + if( !!v ) { + fc::pack( obj[name], *v ); + } + } + template + inline void operator()( const char* name )const { + pack_helper( c.*p, name ); + } + + private: + const Class& c; + fc::value& obj; + }; + + template + struct is_optional { + typedef fc::false_type type; + }; + template + struct is_optional > { + typedef fc::true_type type; + }; + + template + struct unpack_object_visitor { + unpack_object_visitor(Class& _c, const fc::value& _val) + :c(_c),obj(_val){} + + template + void operator()( const char* name )const { + if( obj.find(name) != obj.end()) { + fc::unpack( obj[name], c.*p ); + } + else { + if( !is_optional< typename fc::remove_reference::type >::type::value ) { + wlog( "unable to find name: '%1%'",name); + } + } + } + Class& c; + const fc::value& obj; + }; + + template + struct if_enum { + template + static inline void pack( fc::value& jsv, const T& v ) { + jsv = fc::value::object(); + detail::pack_object_visitor pov(v,jsv); + fc::reflector::visit(pov); + } + template + static inline void unpack( const fc::value& jsv, T& v ) { + detail::unpack_object_visitor pov(v,jsv ); + fc::reflector::visit(pov); + } + }; + + template<> struct if_enum { + template + static inline void pack( fc::value& jsv, const T& v ) { + fc::pack( jsv, fc::reflector::to_string(v) ); + } + template + static inline void unpack( const fc::value& jsv, T& v ) { + if( strcmp( jsv.type(), "string" ) == 0 ) { + v = fc::reflector::from_string( value_cast(jsv).c_str() ); + } else { + // throw if invalid int, by attempting to convert to string + fc::reflector::to_string( v = value_cast(jsv) ); + } + } + }; + + + template + struct if_reflected { + template + static inline void pack(fc::value& s, const T& v ) { + v.did_not_implement_reflect_macro(); + } + template + static inline void unpack( const fc::value& s, T& v ) { + v.did_not_implement_reflect_macro(); + //wlog( "warning, ignoring unknown type" ); + } + }; + + template<> + struct if_reflected { + template + static inline void pack( fc::value& jsv, const T& v ) { + if_enum::is_enum>::pack( jsv,v ); + } + template + static inline void unpack( const fc::value& jsv, T& v ) { + if_enum::is_enum>::unpack( jsv,v ); + } + }; + + } // namesapce detail + + inline void unpack( const fc::value& jsv, bool& v ) { v = value_cast(jsv); } + inline void unpack( const fc::value& jsv, float& v ) { v = value_cast(jsv); } + inline void unpack( const fc::value& jsv, double& v ) { v = value_cast(jsv); } + inline void unpack( const fc::value& jsv, uint8_t& v ) { v = value_cast(jsv); } + inline void unpack( const fc::value& jsv, uint16_t& v ) { v = value_cast(jsv); } + inline void unpack( const fc::value& jsv, uint32_t& v ) { v = value_cast(jsv); } + inline void unpack( const fc::value& jsv, uint64_t& v ) { v = value_cast(jsv); } + inline void unpack( const fc::value& jsv, int8_t& v ) { v = value_cast(jsv); } + inline void unpack( const fc::value& jsv, int16_t& v ) { v = value_cast(jsv); } + inline void unpack( const fc::value& jsv, int32_t& v ) { v = value_cast(jsv); } + inline void unpack( const fc::value& jsv, int64_t& v ) { v = value_cast(jsv); } + inline void unpack( const fc::value& jsv, fc::string& v ) { v = value_cast(jsv); } + + template + void pack( fc::value& jsv, const fc::optional& v ) { + if( v ) pack( jsv, *v ); + else jsv = fc::value(); + } + template + void unpack( const fc::value& jsv, fc::optional& v ) { + if( strcmp( jsv.type(), "void" ) != 0 ) { + T tmp; + unpack( jsv, tmp ); + v = fc::move(tmp); + } + } + + + template + inline void pack( fc::value& jsv, const fc::vector& value ) { + jsv = fc::value::array(); + jsv.resize(value.size()); + typename fc::vector::const_iterator itr = value.begin(); + typename fc::vector::const_iterator end = value.end(); + uint32_t i = 0; + while( itr != end ) { + fc::pack( jsv[i], *itr ); + ++itr; + ++i; + } + } + + template + inline void unpack( const fc::value& jsv, fc::vector& val ) { + val.resize( jsv.size() ); + uint32_t s = jsv.size(); + for( uint32_t i = 0; i < s; ++i ) { + unpack( jsv[i], val[i] ); + } + } + + // default case + template + inline void pack( fc::value& jsv, const T& v ) { + detail::if_reflected< typename fc::reflector::is_defined >::pack(jsv,v); + } + + template + inline void unpack( const fc::value& jsv, T& v ) { + detail::if_reflected< typename fc::reflector::is_defined >::unpack(jsv,v); + } + +} // namespace fc + diff --git a/include/fc/vector.hpp b/include/fc/vector.hpp index 8b8cc84..cb66f05 100644 --- a/include/fc/vector.hpp +++ b/include/fc/vector.hpp @@ -55,6 +55,8 @@ namespace fc { template struct vector_impl { public: + typedef T* iterator; + typedef const T* const_iterator; vector_impl():_data(nullptr){} vector_impl( vector_impl&& c):_data(c._data){c._data =nullptr; } vector_impl( const vector_impl& c):_data(nullptr) { @@ -66,14 +68,16 @@ namespace fc { } //slog( "copy: this.size %d", size() ); } + vector_impl(const_iterator b, const_iterator e ):_data(nullptr) { + resize(e-b); + if( size() ) memcpy( data(), b, size() ); + } vector_impl(uint64_t s):_data(nullptr){ resize(s); } ~vector_impl() { clear(); } - typedef T* iterator; - typedef const T* const_iterator; uint64_t size()const { return _data ? _data->size : 0; } @@ -180,6 +184,8 @@ namespace fc { template class vector_impl { public: + typedef T* iterator; + typedef const T* const_iterator; vector_impl():_data(nullptr){} vector_impl( vector_impl&& c):_data(c._data){c._data =nullptr; } vector_impl( const vector_impl& c):_data(nullptr) { @@ -196,6 +202,13 @@ namespace fc { } } } + vector_impl(const_iterator b, const_iterator e ):_data(nullptr) { + resize(e-b); + for( auto i = begin(); i != end(); ++i ) { + *i = *b; + ++b; + } + } vector_impl(uint64_t s):_data(nullptr){ resize(s); @@ -203,8 +216,6 @@ namespace fc { ~vector_impl() { clear(); } - typedef T* iterator; - typedef const T* const_iterator; uint64_t size()const { return _data ? _data->size : 0; } @@ -353,6 +364,8 @@ namespace fc { vector( const vector& v ):detail::vector_impl::type>(v){} vector( vector&& v ):detail::vector_impl::type>(fc::move(v)){} + vector( const T* b, const T* e ):detail::vector_impl::type>(b,e){} + vector& operator=( vector&& v ) { *((base*)this) = fc::move(v); return *this; diff --git a/src/iostream.cpp b/src/iostream.cpp new file mode 100644 index 0000000..77a3900 --- /dev/null +++ b/src/iostream.cpp @@ -0,0 +1,68 @@ +#include +#include +#include +#include + +#include + +namespace fc { + fc::thread& cin_thread() { static fc::thread i("cin"); return i; } + + fc::istream& getline( fc::istream& i, fc::string& s, char delim ) { + fc::stringstream ss; + char c; + if( i.readsome( &c, 1 ) != 1 ) { + cin_thread().async([&](){ i.read(&c,1); } ).wait(); + } + while( !i.eof() ) { + if( c == delim ) { s = ss.str(); return i; } + ss.write(&c,1); + + if( i.readsome( &c, 1 ) != 1 ) { + cin_thread().async([&](){ i.read(&c,1); } ).wait(); + } + } + s = ss.str(); + return i; + } + + ostream& cout_t::write( const char* buf, size_t len ) { std::cout.write(buf,len); return *this; } + void cout_t::close() {} + void cout_t::flush() { std::cout.flush(); } + + ostream& cout_t::write( const fc::string& s ) { std::cout.write(s.c_str(),s.size()); return *this; } + + ostream& cerr_t::write( const char* buf, size_t len ) { std::cerr.write(buf,len); return *this; } + void cerr_t::close() {}; + void cerr_t::flush() { std::cerr.flush(); } + + ostream& cerr_t::write( const fc::string& s ) { std::cerr<< *reinterpret_cast(&s); return *this; } + + size_t cin_t::readsome( char* buf, size_t len ) { + return std::cin.readsome(buf,len); + } + istream& cin_t::read( char* buf, size_t len ) { + std::cin.read(buf,len); + return *this; + } + bool cin_t::eof()const { return std::cin.eof(); } + + istream& cin_t::read( int64_t& v) { std::cin >> v; return *this; } + istream& cin_t::read( uint64_t& v) { std::cin >> v; return *this; } + istream& cin_t::read( int32_t& v) { std::cin >> v; return *this; } + istream& cin_t::read( uint32_t& v) { std::cin >> v; return *this; } + istream& cin_t::read( int16_t& v) { std::cin >> v; return *this; } + istream& cin_t::read( uint16_t& v) { std::cin >> v; return *this; } + istream& cin_t::read( int8_t& v) { std::cin >> v; return *this; } + istream& cin_t::read( uint8_t& v) { std::cin >> v; return *this; } + istream& cin_t::read( float& v) { std::cin >> v; return *this; } + istream& cin_t::read( double& v) { std::cin >> v; return *this; } + istream& cin_t::read( bool& v) { std::cin >> v; return *this; } + istream& cin_t::read( char& v) { std::cin >> v; return *this; } + istream& cin_t::read( fc::string& v) { std::cin >> *reinterpret_cast(&v); return *this; } + + + cout_t cout; + cerr_t cerr; + cin_t cin; +} diff --git a/src/json.cpp b/src/json.cpp index 299108c..f6b9ac6 100644 --- a/src/json.cpp +++ b/src/json.cpp @@ -1,110 +1,265 @@ #include -#include -#include -#include -#include - -#include - -// TODO: replace sstream with light/fast compiling version -#include +#include +#include +#include +#include +#include +#include namespace fc { namespace json { + /** + * Placeholder for unparsed json data. + */ + class string { + public: + template + string( T&& v ):json_data( fc::forward(v) ){} + string( const string& s ):json_data(s.json_data){} + string( string&& s ):json_data(fc::move(s.json_data)){} + string(){} + string& operator=( const fc::string& s ) { + json_data = fc::vector(s.begin(),s.end()); + return *this; + } + template + string& operator=( T&& t ) { + json_data = fc::forward(t); + return *this; + } + string& operator=( string&& s ) { + json_data = fc::move(s.json_data); + return *this; + } + string& operator=( const string& s ) + { + json_data = s.json_data; + return *this; + } + fc::vector json_data; + }; - struct range { - range( const char* s, const char* e ) - :start(s),end(e){ } - - operator bool()const { return start < end; } - char operator*()const { return *start; } - - range& operator++() { ++start; return *this; } - range& operator++(int) { ++start; return *this; } - - operator string() { return string(start,end); } - - const char* start; - const char* end; + namespace errors { + enum error_type { + unknown_error = 0x0001, // Other errors not specified below + warning = 0x0002, // Other warnigns not specified below + sytnax_error = 0x0004, // fatal syntax errors unclosed brace + sytnax_warning = 0x0008, // recoverable syntax error (missing, missing ':', unquoted string) + missing_comma = 0x0010, // if the error was related to json syntax and not semantic + string_to_int = 0x0020, // any time lexical cast from string to int is required + double_to_int = 0x0040, // any time a double is received for an int + int_overflow = 0x0080, // any time int value is greater than underlying type + signed_to_unsigned = 0x0100, // any time a negative value is read for an unsigned field + int_to_bool = 0x0200, // any time an int is read for a bool + string_to_bool = 0x0400, // any time a string is read for a bool + bad_array_index = 0x0800, // atempt to read a vector field beyond end of sequence + unexpected_key = 0x1000, // fields in object + missing_key = 0x2000, // check required fields + type_mismatch = 0x4000, // expected a fundamental, got object, expected object, got array, etc. + type_conversion = 0x8000, // also set any time a conversion occurs + all = 0xffff, + none = 0x0000 }; + } // namespace errors + + /** + * Stores information about errors that occurred durring the parse. + * + * By default extra fields are 'ignored' as warning + * Loss of presision errors are warning. + * String to Int conversion warnings + * Double to Int + * Int to bool + * + */ + struct parse_error { + parse_error( int32_t ec, fc::string msg, char* s = 0, char* e = 0 ) + :message(fc::move(msg)),type(ec),start(s),end(e){} + + parse_error( parse_error&& m ) + :message(fc::move(m.message)),type(m.type),start(m.start),end(m.end){} + + fc::string message; + int32_t type; + char* start; + char* end; + }; + + /** + * Collects errors and manages how they are responded to. + */ + class error_collector { + public: + error_collector( error_collector&& e ) + :m_errors(fc::move(e.m_errors)){ + memcpy((char*)m_eclass,(char*)e.m_eclass, sizeof(m_eclass) ); + } + /* + error_collector( const error_collector&& e ) + :m_errors(e.m_errors){ + memcpy((char*)m_eclass,(char*)e.m_eclass, sizeof(m_eclass) ); + } + */ + ~error_collector() throw() { + try { + m_errors.clear(); + }catch(...){} + } + + enum error_defaults { + default_report = json::errors::all, + default_recover = json::errors::all, + default_throw = json::errors::none, + default_ignore = ~(default_report|default_recover|default_throw) + }; + + error_collector(){ + m_eclass[report_error_t] = default_report; + m_eclass[recover_error_t] = default_recover; + m_eclass[throw_error_t] = default_throw; + m_eclass[ignore_error_t] = default_ignore; + } + + inline bool report( int32_t e )const { + return 0 != (m_eclass[report_error_t] & e); + } + inline bool recover( int32_t e )const { + return 0 != (m_eclass[recover_error_t] & e); + } + inline bool ignore( int32_t e )const { + return 0 != (m_eclass[ignore_error_t] & e); + } + + void report_error( int32_t e ) { + m_eclass[report_error_t] |= e; + m_eclass[ignore_error_t] &= ~e; + } + void recover_error( int32_t e ) { + m_eclass[recover_error_t] |= e; + m_eclass[ignore_error_t] &= ~e; + } + void throw_error( int32_t e ) { + m_eclass[throw_error_t] |= e; + m_eclass[ignore_error_t] &= ~e; + } + void ignore_error( int32_t e ) { + m_eclass[ignore_error_t] |= e; + m_eclass[report_error_t] &= ~m_eclass[ignore_error_t]; + m_eclass[recover_error_t] &= ~m_eclass[ignore_error_t]; + m_eclass[throw_error_t] &= ~m_eclass[ignore_error_t]; + } + + void post_error( int32_t ec, fc::string msg, char* s = 0, char* e = 0 ) { + m_errors.push_back( parse_error( ec, fc::move(msg), s, e ) ); + if( ec & m_eclass[throw_error_t] ) { + throw fc::move(*this); + } + } + const fc::vector& get_errors()const { + return m_errors; + } + + private: + enum error_class { + ignore_error_t, + report_error_t, + recover_error_t, + throw_error_t, + num_error_classes + }; + uint32_t m_eclass[num_error_classes]; + fc::vector m_errors; + }; + fc::value to_value( char* start, char* end, error_collector& ec ); + + + + + + + + + + fc::string escape_string( const fc::string& s ) { + // calculate escape string size. + uint32_t ecount = 0; + for( auto i = s.begin(); i != s.end(); ++i ) { + if( ' '<= *i && *i <= '~' && *i !='\\' && *i != '"' ) { + ecount+=1; + } else { + switch( *i ) { + case '\t' : + case '\n' : + case '\r' : + case '\\' : + case '"' : + ecount += 2; break; + default: + ecount += 4; + } + } + } + // unless the size changed, just return it. + if( ecount == s.size() ) { return s; } + + // reserve the bytes + fc::string out; out.reserve(ecount); + // print it out. + for( auto i = s.begin(); i != s.end(); ++i ) { + if( ' '<= *i && *i <= '~' && *i !='\\' && *i != '"' ) { + out += *i; + } else { + out += '\\'; + switch( *i ) { + case '\t' : out += 't'; break; + case '\n' : out += 'n'; break; + case '\r' : out += 'r'; break; + case '\\' : out += '\\'; break; + case '"' : out += '"'; break; + default: + out += "x"; + const char* const hexdig = "0123456789abcdef"; + out += hexdig[*i >> 4]; + out += hexdig[*i & 0xF]; + } + } + } + return out; + } - class const_visitor : public fc::abstract_const_visitor { - public: - fc::ostream& out; - const_visitor( fc::ostream& o ):out(o){} - - virtual void visit()const{} - virtual void visit( const char& c )const{ out << '"' << c << '"'; } - virtual void visit( const uint8_t& c )const{ out << int(c); } - virtual void visit( const uint16_t& c )const{ out << c; } - virtual void visit( const uint32_t& c )const{ out << c; } - virtual void visit( const uint64_t& c )const{ out << c; } - virtual void visit( const int8_t& c )const{ out << int(c); } - virtual void visit( const int16_t& c )const{ out << c;} - virtual void visit( const int32_t& c )const{ out << c;} - virtual void visit( const int64_t& c )const{ out << c;} - virtual void visit( const double& c )const{ out << c;} - virtual void visit( const float& c )const{ out << c;} - virtual void visit( const bool& c )const{ out << (c?"true":"false"); } - virtual void visit( const fc::string& c )const{ - out << '"'<< escape_string(c)<<'"'; + fc::string unescape_string( const fc::string& s ) { + fc::string out; out.reserve(s.size()); + for( auto i = s.begin(); i != s.end(); ++i ) { + if( *i != '\\' ) { + if( *i != '"' ) out += *i; } - virtual void array_size( int size )const { - if( size == 0 ) { out <<"[]"; } - } - virtual void object_size( int size )const { - if( size == 0 ) { out <<"{}"; } - } - virtual void visit( const char* member, int idx, int size, const cref& v)const{ - if( !idx ) out <<"{"; - out<<'"'<= '0' && c <= '9' ) - return c - '0'; - if( c >= 'a' && c <= 'f' ) - return c - 'a' + 10; - if( c >= 'A' && c <= 'F' ) - return c - 'A' + 10; - return c; - } - - value to_value( char* start, char* end/*, error_collector& ec*/ ); + } + return out; + } /** * Any unescaped quotes are dropped. @@ -154,420 +309,641 @@ namespace fc { namespace json { return s; } - - string to_string( const cref& o ) { - std::stringstream ss; - { - fc::ostream os(ss); - o._reflector.visit( o._obj, fc::json::const_visitor(os) ); - } - return ss.str().c_str(); +/** + * Ignores leading white space. + * If it starts with [,", or { reads until matching ],", or } + * If it starts with something else it reads until [{",}]: or whitespace only + * allowing a starting - or a single . + * + * @note internal json syntax errors are not caught, only bracket errors + * are caught by this method. This makes it easy for error recovery + * when values are read recursivley. + * + * @param in start of input + * @param end end of input + * @param oend output parameter to the end of the value + * + * @return a pointer to the start of the value + */ +char* read_value( char* in, char* end, char*& oend ) { + char* start = in; + char* oin = in; + // ignore leading whitespace + while( (in < end) && ((*in == ' ') || (*in == '\t') || (*in == '\n') || (*in == '\r')) ) { + ++in; } + start = in; + if( start == end ) { + oend = end; + return start; + } + + bool found_dot = false; + // check for literal vs object, array or string + switch( *in ) { + case ':': + case ',': + case '=': + oend = in+1; + return start; + case '[': + case '{': + case '"': + break; + default: { // literal + // read until non-literal character + // allow it to start with - + // allow only one '.' + while( in != end ) { + switch( *in ) { + case '[': case ']': + case '{': case '}': + case ':': case '=': + case ',': case '"': + case ' ': case '\t': case '\n': case '\r': { + oend = in; + return start; + } + case '.': + if( found_dot ) { + oend = in; + return start; + } + found_dot = true; + break; + case '-': + if( in-start ){ oend = in; return start; } + } + ++in; + } + oend = in; + return start; + } + } // end literal check + + int depth = 0; + bool in_quote = false; + bool in_escape = false; + // read until closing ]} or " ignoring escaped " + while( in != end ) { + if( !in_quote ) { + switch( *in ) { + case '[': + case '{': ++depth; break; + case ']': + case '}': --depth; break; + case '"': + ++depth; + in_quote = true; + break; + default: // do nothing; + break; + } + } else { // in quote + switch( *in ) { + case '"': if( !in_escape ) { + --depth; + in_quote = false; + break; + } + case '\\': + in_escape = !in_escape; + break; + default: + in_escape = false; + } + } + ++in; + if( !depth ) { oend = in; return start; } + } + if( depth != 0 ) { + // TODO: Throw Parse Error! + elog("Parse Error!! '%s' size: %d", fc::string( oin, end ).c_str(), (oin-start)); + } + oend = in; return start; +} + +struct temp_set { + temp_set( char* v, char t ) + :old(*v),val(v) { *val = t; } + ~temp_set() { *val = old; } + char old; + char* val; +}; + +/** + * A,B,C + * Warn on extra ',' or missing ',' + */ +void read_values( value::array& a, char* in, char* end, fc::json::error_collector& ec ) { + char* ve = 0; + char* v = fc::json::read_value( in, end, ve ); + while( *v == ',' ) { + wlog( "unexpected ','"); + v = fc::json::read_value( ve, end, ve ); + } + if( v == ve ) return; // no values + + { temp_set temp(ve,'\0'); a.fields.push_back( to_value( v, ve, ec ) ); } + + char* c; + char* ce = 0; + do { // expect comma + value | '' + + // expect comma or '' + c = fc::json::read_value( ve, end, ce ); + + // '' means we are done, no errors + if( c == ce ) return; + + if( *c != ',' ) // we got a value when expecting ',' + { + wlog( "missing ," ); + temp_set temp(ce,'\0'); a.fields.push_back( to_value(c, ce, ec) ); + ve = ce; + continue; // start back at start + } + + // expect value + v = fc::json::read_value( ce, end, ve ); + while ( *v == ',' ) { // but got comma + // expect value + wlog( "extra comma at c->ce" ); + c = v; ce = ve; + v = fc::json::read_value( ve, end, ve ); + } + if( v == ve ) { + wlog( "trailing comma at c->ce" ); + } else { // got value + temp_set temp(ve,'\0'); + a.fields.push_back( to_value( v, ve, ec) ); + } + } while( ve < end );// expect comma + value | '' +} + + +/** + * Reads one level deep, does not recruse into sub objects. + */ +char* read_key_val( std::map& obj, bool sc, char* in, char* end, fc::json::error_collector& ec ) { + char* name_end = 0; + char* name = in; + do { + // read first char + name = fc::json::read_value( name, end, name_end ); + if( sc ) { // if we expect a , + if( *name != ',' ) { // but didn't get one + wlog( "expected ',' but got %1%", name ); // warn and accept name + } else { // we got the exepcted , read the expected name + name = fc::json::read_value( name_end, end, name_end ); + } + } else { // don't start with ',' + while( *name == ',' ) { // while we don't have a name, keep looking + wlog( "unexpected ',' " ); + name = fc::json::read_value( name_end, end, name_end ); + } + } + } while( *name == ',' ); + + + // now we should have a name. + if( name_end >= end -1 ) { + temp_set ntemp(name_end,'\0'); + elog( "early end after reading name %1%", name ); + return name_end; + } + if( *name != '"' ) { + temp_set ntemp(name_end,'\0'); + wlog( "unquoted name '%1%'", name ); + } else { + temp_set ntemp(name_end,'\0'); + name = inplace_unescape_string(name); + } + + char* col_end = 0; + char* col = fc::json::read_value( name_end, end, col_end ); + + char* val_end = 0; + char* val = 0; + + bool sep_error = false; + if( col_end-col == 1 ) { + switch( *col ) { + case ':': break; + case ';': + case '=': + wlog( "found %1% instead of ':'", *col ); + break; + default: + sep_error = true; + } + } else { + sep_error = true; + } + + if( sep_error ) { + temp_set ntemp(name_end,'\0'); + temp_set vtemp(col_end,'\0'); + wlog( "expected ':' but got %1%", col ); + wlog( "assuming this is the value... " ); + val = col; + val_end = col_end; + } else { + if( name_end >= end -1 ) { + temp_set ntemp(name_end,'\0'); + temp_set vtemp(col_end,'\0'); + elog( "early end after reading name '%1%' and col '%2%'", name, col ); + return name_end; + } + val = fc::json::read_value( col_end, end, val_end ); + if( val == end ) { + wlog( "no value specified" ); + } + } + temp_set ntemp(name_end,'\0'); + temp_set vtemp(val_end,'\0'); + //slog( "name: '%1%'", fc::string(name,name_end) ); + obj[name] = fc::vector(val,val_end); +// obj.fields.push_back( key_val( name, to_value( val, val_end, ec ) ) ); + return val_end; +} + + + + + +/** + * Reads an optional ',' followed by key : value, returning the next input position + * @param sc - start with ',' + */ +char* read_key_val( value::object& obj, bool sc, char* in, char* end, fc::json::error_collector& ec ) { + char* name_end = 0; + char* name = in; + do { + // read first char + name = fc::json::read_value( name, end, name_end ); + if( name == name_end ) + return name; + if( sc ) { // if we expect a , + if( *name != ',' ) { // but didn't get one + if( *name != '}' ) + wlog( "expected ',' or '}' but got %1%", name ); // warn and accept name + } else { // we got the exepcted , read the expected name + name = fc::json::read_value( name_end, end, name_end ); + } + } else { // don't start with ',' + while( *name == ',' ) { // while we don't have a name, keep looking + wlog( "unexpected ',' " ); + name = fc::json::read_value( name_end, end, name_end ); + } + } + } while( *name == ',' ); + + + // now we should have a name. + if( name_end >= end -1 ) { + temp_set ntemp(name_end,'\0'); + elog( "early end after reading name %1%", name ); + return name_end; + } + if( *name != '"' ) { + temp_set ntemp(name_end,'\0'); + wlog( "unquoted name '%1%'", name ); + } else { + temp_set ntemp(name_end,'\0'); + name = inplace_unescape_string(name); + } + + char* col_end = 0; + char* col = fc::json::read_value( name_end, end, col_end ); + + char* val_end = 0; + char* val = 0; + + bool sep_error = false; + if( col_end-col == 1 ) { + switch( *col ) { + case ':': break; + case ';': + case '=': + wlog( "found %1% instead of ':'", *col ); + break; + default: + sep_error = true; + } + } else { + sep_error = true; + } + + if( sep_error ) { + temp_set ntemp(name_end,'\0'); + temp_set vtemp(col_end,'\0'); + wlog( "expected ':' but got %1%", col ); + wlog( "assuming this is the value... " ); + val = col; + val_end = col_end; + } else { + if( name_end >= end -1 ) { + temp_set ntemp(name_end,'\0'); + temp_set vtemp(col_end,'\0'); + elog( "early end after reading name '%1%' and col '%2%'", name, col ); + return name_end; + } + val = fc::json::read_value( col_end, end, val_end ); + if( val == end ) { + wlog( "no value specified" ); + } + } + temp_set ntemp(name_end,'\0'); + temp_set vtemp(val_end,'\0'); + //slog( "name: '%1%'", fc::string(name,name_end) ); + obj.fields.push_back( value::key_val( name, to_value( val, val_end, ec ) ) ); + return val_end; +} + +// first_key =:: '' | "name" : VALUE *list_key +// list_key '' | ',' "name" : VALUE +void read_key_vals( value::object& obj, char* in, char* end, fc::json::error_collector& ec ) { + bool ex_c = false; + char* kv_end = in; + do { + //slog( "%1% bytes to read", (end-kv_end) ); + kv_end = read_key_val( obj, ex_c, kv_end, end, ec ); + ex_c = true; + } while( kv_end < end ); +} +// first_key =:: '' | "name" : VALUE *list_key +// list_key '' | ',' "name" : VALUE +std::map read_key_vals( char* in, char* end, fc::json::error_collector& ec ) { + std::map m; + bool ex_c = false; + char* kv_end = in; + do { + //slog( "%1% bytes to read", (end-kv_end) ); + kv_end = read_key_val( m, ex_c, kv_end, end, ec ); + ex_c = true; + } while( kv_end < end ); + return m; +} + + + +/** + * @brief adaptor for to_value( char*, char*, error_collector& ) + */ +fc::value to_value( fc::vector&& v, error_collector& ec ) { + if( v.size() == 0 ) return value(); + return to_value( &v.front(), &v.front() + v.size(), ec ); +} + +/** + * Returns a fc::value containing from the json string. + * + * @param ec - determines how to respond to parse errors and logs + * any errors that occur while parsing the string. + */ +fc::value to_value( char* start, char* end, error_collector& ec ) { + if( start == end ) return value(); + + char* ve = 0; + char* s = read_value( start, end, ve ); + //slog( "'%1%'", fc::string(start,ve) ); + switch( s[0] ) { + case '[': { + value::array a; + read_values( a, s+1, ve -1, ec ); + return a; + } + case '{': { + value::object o; + read_key_vals( o, s+1, ve -1, ec ); + value v = fc::move(o); + return v; + } + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': { + temp_set move_end(ve,'\0'); + for( char* n = s+1; n != ve; ++n ) { + if( *n == '.' ) { + return fc::lexical_cast(s); + } + } + return fc::lexical_cast(s); + } + case '-': { + temp_set move_end(ve,'\0'); + for( char* n = s+1; n != ve; ++n ) { + if( *n == '.' ) { + return fc::lexical_cast(s); + } + } + return fc::lexical_cast(s); + } + case '.': { + temp_set move_end(ve,'\0'); + return fc::lexical_cast(s); + } + case '\"': { + temp_set move_end(ve,'\0'); + return inplace_unescape_string( s ); + } + case 'n': { + temp_set move_end(ve,'\0'); + if( strcmp(s,"null" ) ) return value(); + } + case 't': { + temp_set move_end(ve,'\0'); + if( strcmp(s,"true" ) ) return true; + } + case 'f': { + temp_set move_end(ve,'\0'); + if( strcmp(s,"false" ) ) return false; + } + + default: + wlog( "return unable to parse... return as string '%s'", fc::string(s,ve).c_str() ); + return value( fc::string( s, ve) ); + } +} + +fc::string pretty_print( fc::vector&& v, uint8_t indent ) { + int level = 0; + fc::stringstream ss; + bool first = false; + bool quote = false; + bool escape = false; + for( uint32_t i = 0; i < v.size(); ++i ) { + switch( v[i] ) { + case '\\': + if( !escape ) { + if( quote ) + escape = true; + } else { escape = false; } + ss< + struct value_visitor : value::const_visitor { + value_visitor( Stream& s ):os(s){} + Stream& os; + virtual void operator()( const int8_t& v ){ os << v; } + virtual void operator()( const int16_t& v ){ os << v; } + virtual void operator()( const int32_t& v ){ os << v; } + virtual void operator()( const int64_t& v ){ os << v; } + virtual void operator()( const uint8_t& v ){ os << v; } + virtual void operator()( const uint16_t& v ){ os << v; } + virtual void operator()( const uint32_t& v ){ os << v; } + virtual void operator()( const uint64_t& v ){ os << v; } + virtual void operator()( const float& v ){ os << v; } + virtual void operator()( const double& v ){ os << v; } + virtual void operator()( const bool& v ){ os << (v ? "true" : "false"); } + virtual void operator()( const fc::string& v ){ os << '"' << escape_string(v) <<'"'; } + virtual void operator()( const value::object& o ){ + os << '{'; + for( uint32_t i = 0; i < o.fields.size(); ++i ) { + if( i ) os <<','; + (*this)( o.fields[i].key ); + os<<':'; + o.fields[i].val.visit( value_visitor(*this) ); } - } - return ss.str().c_str(); + os << '}'; + } + 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) ); + } + os << ']'; + } + virtual void operator()( ){ os << "null"; } + }; + + template + void to_json( const fc::value& v, Stream& os ) { + v.visit( value_visitor(os) ); + } + + void write( ostream& out, const value& val ) { + to_json( val, out ); } - string to_pretty_string( const cref& o, uint8_t indent ) { - auto s = to_string(o); - return pretty_print( s.c_str(), s.size(), indent ); - } + fc::string to_string( const fc::value& v ) { + fc::stringstream ss; + to_json( v, ss ); + return ss.str(); + } - - - /** - * Ignores leading white space. - * If it starts with [,", or reads until matching ],", or - * If it starts with something else it reads until [{",}]: or whitespace only - * allowing a starting - or a single . - * - * @note internal json syntax errors are not caught, only bracket errors - * are caught by this method. This makes it easy for error recovery - * when values are read recursivley. - * - * @param in start of input - * @param end end of input - * @param oend output parameter to the end of the value - * - * @return the range of inputs for the value - */ - range read_value( const range& in ) { - range start = in; - // ignore leading whitespace - bool done = false; - while( !done && start ) { - switch( *start ) { - case ' ': - case '\t': - case '\n': - case '\r': - case ',': - ++start; - default: - done = true; - } - } - if( !start ) return start; - range out = start; - - bool found_dot = false; - // check for literal vs object, array or string - switch( *start ) { - case ':': - case ',': - case '=': - out.end = start.start + 1; - return out; - case '[': - case '{': - case '"': - break; - default: { // literal - // read until non-literal character - // allow it to start with - - // allow only one '.' - while( start ) { - switch( *start ) { - case '[': case ']': - case '{': case '}': - case ':': case '=': - case ',': case '"': - case ' ': case '\t': case '\n': case '\r': { - out.end = start.start; - return out; - } - case '.': - if( found_dot ) { - out.end = start.start; - return out; - } - found_dot = true; - break; - case '-': - if( out.start-start.start ){ - out.end = start.start; - return out; - } - } - ++start; - } - out.end = start.start; - return out; - } - } // end literal check - - int depth = 0; - bool in_quote = false; - bool in_escape = false; - // read until closing ] or " ignoring escaped " - while( start ) { - if( !in_quote ) { - switch( *start) { - case '[': - case '{': ++depth; break; - case ']': - case '}': --depth; break; - case '"': - ++depth; - in_quote = true; - break; - default: // do nothing; - break; - } - } else { // in quote - switch( *start ) { - case '"': if( !in_escape ) { - --depth; - in_quote = false; - break; - } - case '\\': - in_escape = !in_escape; - break; - default: - in_escape = false; - } - } - ++start; - if( !depth ) { return range( out.start, start.start ); } + value from_file( const fc::path& local_path ) { + if( !exists(local_path) ) { + FC_THROW_MSG( "Source file '%s' does not exist", local_path.string() ); } - if( depth != 0 ) { - // TODO: Throw Parse Error! - elog("Parse Error!!"); + if( is_directory( local_path ) ) { + FC_THROW_MSG( "Source path '%s' is a directory, expected a file.", local_path.string() ); } - return range( out.start, start.start ); + + // memory map the file + file_mapping fmap( local_path.string().c_str(), read_only ); + size_t fsize = file_size(local_path); + + + mapped_region mr( fmap, fc::read_only, 0, fsize ); + + const char* pos = reinterpret_cast(mr.get_address()); + const char* end = pos + fsize; + + // TODO: implement a const version of to_value + fc::vector tmp(pos,end); + + json::error_collector ec; + return fc::json::to_value(tmp.data(), tmp.data()+fsize,ec); + } + + value from_string( const fc::string& s ) { + return from_string( s.c_str(), s.c_str() + s.size() ); + } + value from_string( fc::vector&& v ) { + error_collector ec; + return to_value( v.data(), v.data() + v.size(), ec ); + } + + value from_string( const char* s, const char* e ) { + return from_string( fc::vector(s,e) ); } - - - void write( ostream& out, const cref& val ) { - val._reflector.visit( val._obj, fc::json::const_visitor(out) ); - } - - void read( istream& in, ref& val ) { - - } - - - string escape_string( const string& s ) { - // calculate escape string size. - uint32_t ecount = 0; - for( auto i = s.begin(); i != s.end(); ++i ) { - if( ' '<= *i && *i <= '~' && *i !='\\' && *i != '"' ) { - ecount+=1; - } else { - switch( *i ) { - case '\t' : - case '\n' : - case '\r' : - case '\\' : - case '"' : - ecount += 2; break; - default: - ecount += 4; - } - } - } - // unless the size changed, just return it. - if( ecount == s.size() ) { return s; } - - // reserve the bytes - string out; out.reserve(ecount); - - // print it out. - for( auto i = s.begin(); i != s.end(); ++i ) { - if( ' '<= *i && *i <= '~' && *i !='\\' && *i != '"' ) { - out += *i; - } else { - out += '\\'; - switch( *i ) { - case '\t' : out += 't'; break; - case '\n' : out += 'n'; break; - case '\r' : out += 'r'; break; - case '\\' : out += '\\'; break; - case '"' : out += '"'; break; - default: - out += "x"; - const char* const hexdig = "0123456789abcdef"; - out += hexdig[*i >> 4]; - out += hexdig[*i & 0xF]; - } - } - } - return out; - } - string unescape_string( const string& s ) { - string out; out.reserve(s.size()); - for( auto i = s.begin(); i != s.end(); ++i ) { - if( *i != '\\' ) { - if( *i != '"' ) out += *i; - } - else { - ++i; - if( i == out.end() ) return out; - switch( *i ) { - case 't' : out += '\t'; break; - case 'n' : out += '\n'; break; - case 'r' : out += '\r'; break; - case '\\' : out += '\\'; break; - case '"' : out += '"'; break; - case 'x' : { - ++i; if( i == out.end() ) return out; - char c = from_hex(*i); - ++i; if( i == out.end() ) { out += c; return out; } - c = c<<4 | from_hex(*i); - out += c; - break; - } - default: - out += '\\'; - out += *i; - } - } - } - return out; - } - - range skip_separator( range r, char c ) { - while( r ) { - switch( *r ) { - case ' ': case '\n': case '\t': case '\r': - ++r; - continue; - default: - if( *r == c ) { ++r; } - else { - // wlog( "Expected ',' but found '%c'", *r ); - } - return r; - } - } - } - - /** - * [A,B,C] - */ - value read_array( const range& r ) { - BOOST_ASSERT( *r == '[' ); - BOOST_ASSERT( *(r.end-1) == ']' ); - value out; - range cur_range = read_value( r ); - - while( cur_range ) { - out.push_back( *from_string( cur_range.start, cur_range.end ) ); - cur_range = read_value( range( cur_range.end, r.end) ); - } - return out; - } - - /** - * @pre *input == { - * @pre *input.end-1 == } - */ - value read_object( const range& in ) { - BOOST_ASSERT( *in == '{' ); - BOOST_ASSERT( *(in.end-1) == '}' ); - value v; - range key = read_value( ++range(in) ); - range rest(key.end,in.end-1); - while( rest ) { - range val = skip_separator( range(key.end,in.end), ':' ); - val = read_value( val ); - v[string(key)] = *from_string( val.start, val.end ); - range key = read_value( rest ); - rest.start = key.end; - } - return v; - } - - value_fwd from_string( const string& s ) { - return from_string( s.c_str(), s.c_str() + s.size() ); - } - - value_fwd from_string( const char* start, const char* end ) { - if( start == end ) return value(); - - range s = read_value( range(start,end) ); - switch( s.start[0] ) { - case '[': - return read_array( s ); - case '{': - return read_object( s ); - case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { - for( const char* n = s.start+1; n != s.end; ++n ) { - if( *n == '.' ) { - return boost::lexical_cast(std::string(s.start,s.end)); - } - } - return boost::lexical_cast(std::string(s.start,s.end)); - } - case '-': { - for( const char* n = s.start+1; n != s.end; ++n ) { - if( *n == '.' ) { - return (value)boost::lexical_cast(std::string(s.start,s.end)); - } - } - return (value)boost::lexical_cast(std::string(s.start,s.end)); - } - case '.': { - return (value)boost::lexical_cast(std::string(s.start,s.end)); - } - case '\"': { - return (value)unescape_string( string(s.start,s.end) ); - } - case 'n': { - if( strncmp(s.start,"null",4 ) ) return value(); - } - case 't': { - if( strncmp(s.start,"true",4 ) ) return true; - } - case 'f': { - if( strncmp(s.start,"false",5 ) ) return false; - } - default: - wlog( "return unable to parse... return as string" ); - return value( string( s.start, s.end) ); - } - } - -} } // fc::json +}} // fc::json diff --git a/src/lexical_cast.cpp b/src/lexical_cast.cpp new file mode 100644 index 0000000..7a8ba3a --- /dev/null +++ b/src/lexical_cast.cpp @@ -0,0 +1,26 @@ +#include +#include +namespace fc { + + namespace detail { + double to_double( const fc::string& s ) { + return boost::lexical_cast(s.c_str()); + } + int64_t to_int64( const fc::string& s ) { + return boost::lexical_cast(s.c_str()); + } + uint64_t to_uint64( const fc::string& s ) { + return boost::lexical_cast(s.c_str()); + } + fc::string to_string( double d ){ return boost::lexical_cast(d); } + fc::string to_string( uint64_t d ){ return boost::lexical_cast(d); } + fc::string to_string( uint32_t d ){ return boost::lexical_cast(d); } + fc::string to_string( uint16_t d ){ return boost::lexical_cast(d); } + fc::string to_string( uint8_t d ){ return boost::lexical_cast(d); } + fc::string to_string( int64_t d ){ return boost::lexical_cast(d); } + fc::string to_string( int32_t d ){ return boost::lexical_cast(d); } + fc::string to_string( int16_t d ){ return boost::lexical_cast(d); } + fc::string to_string( int8_t d ){ return boost::lexical_cast(d); } + fc::string to_string( char d ){ return boost::lexical_cast(d); } + } +} diff --git a/src/sha1.cpp b/src/sha1.cpp index 6bbad2a..613e7e7 100644 --- a/src/sha1.cpp +++ b/src/sha1.cpp @@ -1,5 +1,5 @@ -#include #include +#include #include #include #include @@ -8,7 +8,7 @@ namespace fc { sha1::sha1() { memset( _hash, 0, sizeof(_hash) ); } sha1::sha1( const fc::string& hex_str ) { - from_hex( hex_str, (char*)_hash, sizeof(_hash) ); + fc::from_hex( hex_str, (char*)_hash, sizeof(_hash) ); } fc::string sha1::str()const { @@ -85,12 +85,3 @@ namespace fc { } // namespace fc -namespace fc { - const char* reflector::name()const { return "sha1"; } - void reflector::visit( void* s, const abstract_visitor& v )const { - } - void reflector::visit( const void* s, const abstract_const_visitor& v )const { - v.visit( fc::string( *((const sha1*)s)) ); - } - reflector& reflector::instance() { static reflector inst; return inst; } -} // namespace fc diff --git a/src/sstream.cpp b/src/sstream.cpp new file mode 100644 index 0000000..f1f7a8b --- /dev/null +++ b/src/sstream.cpp @@ -0,0 +1,65 @@ +#include +#include +#include + +namespace fc { + class stringstream::impl { + public: + impl( fc::string&s ) + :ss( s ) + { } + impl(){} + + std::stringstream ss; + }; + + stringstream::stringstream( fc::string& s ) + :my(s) { + } + stringstream::stringstream(){} + stringstream::~stringstream(){} + + + fc::string stringstream::str(){ + return my->ss.str();//.c_str();//*reinterpret_cast(&st); + } + + bool stringstream::eof()const { + return my->ss.eof(); + } + ostream& stringstream::write( const char* buf, size_t len ) { + my->ss.write(buf,len); + return *this; + } + size_t stringstream::readsome( char* buf, size_t len ) { + return my->ss.readsome(buf,len); + } + istream& stringstream::read( char* buf, size_t len ) { + my->ss.read(buf,len); + return *this; + } + void stringstream::close(){}; + void stringstream::flush(){}; + + istream& stringstream::read( int64_t& v ) { my->ss >> v; return *this; } + istream& stringstream::read( uint64_t& v ) { my->ss >> v; return *this; } + istream& stringstream::read( int32_t& v ) { my->ss >> v; return *this; } + istream& stringstream::read( uint32_t& v ) { my->ss >> v; return *this; } + istream& stringstream::read( int16_t& v ) { my->ss >> v; return *this; } + istream& stringstream::read( uint16_t& v ) { my->ss >> v; return *this; } + istream& stringstream::read( int8_t& v ) { my->ss >> v; return *this; } + istream& stringstream::read( uint8_t& v ) { my->ss >> v; return *this; } + istream& stringstream::read( float& v ) { my->ss >> v; return *this; } + istream& stringstream::read( double& v ) { my->ss >> v; return *this; } + istream& stringstream::read( bool& v ) { my->ss >> v; return *this; } + istream& stringstream::read( char& v ) { my->ss >> v; return *this; } + istream& stringstream::read( fc::string& v ) { my->ss >> *reinterpret_cast(&v); return *this; } + + ostream& stringstream::write( const fc::string& s) { + my->ss << s.c_str(); + return *this; + } + +} + + diff --git a/src/stream.cpp b/src/stream.cpp deleted file mode 100644 index 5e4be9d..0000000 --- a/src/stream.cpp +++ /dev/null @@ -1,384 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include - -namespace fc { - namespace detail { - namespace io = boost::iostreams; - class cin_source : public io::source { - public: - typedef char type; - - template - cin_source(T):_cin_thread(NULL){} - cin_source():_cin_thread(NULL){} - - cin_source( const cin_source& s ):_cin_thread(s._cin_thread){} - - std::streamsize read( char* s, std::streamsize n ) { - int r = std::cin.readsome(s,n); - slog( "%d", r ); - if( std::cin && r <= 0 ) { - std::cin.read( s, 1 ); - if( std::cin.eof() ) return -1; - return 1; - } - return r; - } - private: - fc::thread* _cin_thread; - }; - std::istream& get_cin_stream() { - static io::stream cin_stream;// = cin_source(); - cin_stream.open(0); - return cin_stream; - } - - class abstract_source : public io::source { - public: - typedef char type; - abstract_source( abstract_istream& ais ):_ais(ais){} - - std::streamsize read( char* s, std::streamsize n ) { - return _ais.readsome_impl( s, n ); - } - abstract_istream& _ais; - }; - abstract_istream::abstract_istream() { - static_assert( sizeof(_store) >= sizeof( io::stream ), "Failed to allocate enough space" ); - (new (&_store[0]) io::stream( *this )); - } - size_t abstract_istream::readsome( char* buf, size_t len ) { - auto iost = (io::stream*)(&_store[0]); - iost->read(buf,len); - return len; - } - - class abstract_sink : public io::sink { - public: - struct category : io::sink::category, io::flushable_tag {}; - typedef char type; - abstract_sink( abstract_ostream& aos ):_aos(aos){} - - std::streamsize write( const char* s, std::streamsize n ) { - return _aos.write_impl( s, n ); - } - void close() { _aos.close_impl(); } - bool flush() { _aos.flush_impl(); return true; } - - abstract_ostream& _aos; - }; - - abstract_ostream::abstract_ostream() { - static_assert( sizeof(_store) >= sizeof( io::stream ), "Failed to allocate enough space" ); - (new (&_store[0]) io::stream( *this )); - } - size_t abstract_ostream::write( const char* buf, size_t len ) { - auto iost = (io::stream*)(&_store[0]); - iost->write(buf,len); - return len; - } - void abstract_ostream::flush() { - auto iost = (io::stream*)(&_store[0]); - iost->flush(); - } - void abstract_ostream::close() { - auto iost = (io::stream*)(&_store[0]); - iost->close(); - } - - - abstract_istream::~abstract_istream() { - } - abstract_ostream::~abstract_ostream() { - auto iost = (io::stream*)(&_store[0]); - iost->~stream(); - } - } - - istream::~istream(){ - detail::abstract_istream* i = (detail::abstract_istream*)&_store[0]; - i->~abstract_istream(); - } - - size_t istream::readsome( char* buf, size_t len ){ - detail::abstract_istream* i = (detail::abstract_istream*)&_store[0]; - return i->readsome(buf,len); - } - #define read_help \ - detail::abstract_istream* aos = (detail::abstract_istream*)&i._store[0];\ - auto iist = (detail::io::stream*)(&aos->_store[0]); \ - (*iist) >> s; \ - return i; - - istream& operator>>( istream& i, int64_t& s){ read_help } - istream& operator>>( istream& i, uint64_t& s){ read_help } - istream& operator>>( istream& i, int32_t& s){ read_help } - istream& operator>>( istream& i, uint32_t& s){ read_help } - istream& operator>>( istream& i, int16_t& s){ read_help } - istream& operator>>( istream& i, uint16_t& s){ read_help } - istream& operator>>( istream& i, int8_t& s){ read_help } - istream& operator>>( istream& i, uint8_t& s){ read_help } - istream& operator>>( istream& i, float& s){ read_help } - istream& operator>>( istream& i, double& s){ read_help } - istream& operator>>( istream& i, bool& s){ read_help } - istream& operator>>( istream& i, char& s){ read_help } - istream& operator>>( istream& i, fc::string& s){ - std::string ss; - detail::abstract_istream* aos = (detail::abstract_istream*)&i._store[0]; - auto iist = (detail::io::stream*)(&aos->_store[0]); - (*iist) >> ss; - s = ss.c_str(); - return i; - } - - #undef read_help - - - ostream::~ostream(){ - detail::abstract_ostream* o = (detail::abstract_ostream*)&_store[0]; - close(); - o->~abstract_ostream(); - } - - size_t ostream::write( const char* buf, size_t len ){ - detail::abstract_ostream* o = (detail::abstract_ostream*)&_store[0]; - return o->write(buf,len); - } - void ostream::close(){ - detail::abstract_ostream* o = (detail::abstract_ostream*)&_store[0]; - o->close(); - } - void ostream::flush(){ - detail::abstract_ostream* o = (detail::abstract_ostream*)&_store[0]; - o->flush(); - } - #define print_help \ - detail::abstract_ostream* aos = (detail::abstract_ostream*)&o._store[0];\ - auto iost = (detail::io::stream*)(&aos->_store[0]); \ - (*iost) << s; \ - return o; - - ostream& operator<<( ostream& o, int64_t s ){ print_help } - ostream& operator<<( ostream& o, uint64_t s ){ print_help } - ostream& operator<<( ostream& o, int32_t s ){ print_help } - ostream& operator<<( ostream& o, uint32_t s ){ print_help } - ostream& operator<<( ostream& o, int16_t s ){ print_help } - ostream& operator<<( ostream& o, uint16_t s ){ print_help } - ostream& operator<<( ostream& o, int8_t s ){ print_help } - ostream& operator<<( ostream& o, uint8_t s ){ print_help } - ostream& operator<<( ostream& o, float s ){ print_help } - ostream& operator<<( ostream& o, double s ){ print_help } - ostream& operator<<( ostream& o, bool s ){ print_help } - ostream& operator<<( ostream& o, char s ){ print_help } - ostream& operator<<( ostream& o, const char* s ){ print_help } - ostream& operator<<( ostream& o, const fc::string& s ){ return o << s.c_str(); } - - #undef print_help - - class ofstream::impl { - public: - impl(){} - impl( const fc::string& s, int m ) - :ofs(s.c_str(), std::ios_base::binary ){} - - - std::ofstream ofs; - }; - - ofstream::ofstream(){} - ofstream::ofstream( const fc::string& s, int m ) - :my(s,m){} - ofstream::~ofstream(){} - void ofstream::open( const fc::string& s, int m ) { - my->ofs.open(s.c_str(), std::ios_base::binary ); - } - ofstream& ofstream::write( const char* b, size_t s ) { - my->ofs.write(b,s); - return *this; - } - void ofstream::put( char c ) { my->ofs.put(c); } - - - class ifstream::impl { - public: - impl(){} - impl( const fc::string& s, int m ) - :ifs(s.c_str(), std::ios_base::binary ){} - - - std::ifstream ifs; - }; - - - - ifstream::ifstream() { - } - ifstream::~ifstream() {} - ifstream::ifstream( const fc::string& s, int m ) - :my(s.c_str(), std::ios_base::binary){} - - ifstream& ifstream::read( char* b, size_t s ) { - my->ifs.read(b,s); - return *this; - } - void ifstream::open( const fc::string& s, int m ) { - my->ifs.open(s.c_str(), std::ios_base::binary ); - } - - class stringstream::impl { - public: - impl( fc::string&s ) - :ss( reinterpret_cast(s) ) - { } - impl(){} - - std::stringstream ss; - }; - - stringstream::stringstream( fc::string& s ) - :my(s) { - } - stringstream::stringstream(){} - stringstream::~stringstream(){} - - stringstream& operator<<( stringstream& s, const int64_t& v ){ - s.my->ss << v; - return s; - } - stringstream& operator<<( stringstream& s, const uint64_t& v ){ - s.my->ss << v; - return s; - } - stringstream& operator<<( stringstream& s, const int32_t& v ){ - s.my->ss << v; - return s; - } - stringstream& operator<<( stringstream& s, const uint32_t& v ){ - s.my->ss << v; - return s; - } - stringstream& operator<<( stringstream& s, const int16_t& v ){ - s.my->ss << v; - return s; - } - stringstream& operator<<( stringstream& s, const uint16_t& v ){ - s.my->ss << v; - return s; - } - stringstream& operator<<( stringstream& s, const int8_t& v ){ - s.my->ss << v; - return s; - } - stringstream& operator<<( stringstream& s, const uint8_t& v ){ - s.my->ss << v; - return s; - } - stringstream& operator<<( stringstream& s, const float& v ){ - s.my->ss << v; - return s; - } - stringstream& operator<<( stringstream& s, const double& v ){ - s.my->ss << v; - return s; - } - stringstream& operator<<( stringstream& s, const bool& v ){ - s.my->ss << v; - return s; - } - stringstream& operator<<( stringstream& s, const char& v ){ - s.my->ss << v; - return s; - } - stringstream& operator<<( stringstream& s, const char* cs ) { - s.my->ss << cs; - return s; - } - stringstream& operator<<( stringstream& s, const fc::string& v ){ - s.my->ss <(v); - return s; - } - - fc::string stringstream::str(){ - //std::string st = my->ss.str(); - return my->ss.str().c_str();//*reinterpret_cast(&st); - } - - - stringstream& operator>>( stringstream& s, int64_t& v ){ - s.my->ss >> v; - return s; - } - stringstream& operator>>( stringstream& s, uint64_t& v ){ - s.my->ss >> v; - return s; - } - stringstream& operator>>( stringstream& s, int32_t& v ){ - s.my->ss >> v; - return s; - } - stringstream& operator>>( stringstream& s, uint32_t& v ){ - s.my->ss >> v; - return s; - } - stringstream& operator>>( stringstream& s, int16_t& v ){ - s.my->ss >> v; - return s; - } - stringstream& operator>>( stringstream& s, uint16_t& v ){ - s.my->ss >> v; - return s; - } - stringstream& operator>>( stringstream& s, int8_t& v ){ - s.my->ss >> v; - return s; - } - stringstream& operator>>( stringstream& s, uint8_t& v ){ - s.my->ss >> v; - return s; - } - stringstream& operator>>( stringstream& s, float& v ){ - s.my->ss >> v; - return s; - } - stringstream& operator>>( stringstream& s, double& v ){ - s.my->ss >> v; - return s; - } - stringstream& operator>>( stringstream& s, bool& v ){ - s.my->ss >> v; - return s; - } - stringstream& operator>>( stringstream& s, char& v ){ - s.my->ss >> v; - return s; - } - stringstream& operator>>( stringstream& s, fc::string& v ){ - s.my->ss >> reinterpret_cast(v); - return s; - } - - bool getline( istream& in, fc::string& f ) { - std::stringstream ss; - char c; - while( in.readsome( &c, sizeof(c) ) > 0 ) { - slog( "%c", c ); - if( c != '\n' ) ss << c; - else { - f = ss.str(); - return true; - } - } - return false; - } - - ostream cout( std::cout ); - ostream cerr( std::cerr ); - istream cin( detail::get_cin_stream() ); -} //namespace fc - diff --git a/src/value.cpp b/src/value.cpp index d9eba3b..fdce710 100644 --- a/src/value.cpp +++ b/src/value.cpp @@ -1,375 +1,353 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include #include - -FC_REFLECT( fc::value::member, (_val) ) - +#include +#include namespace fc { - value::member::member(){} - value::member::member( const char* c ) - :_key(c){ } - value::member::member( string&& c ) - :_key(fc::move(c)){ } - const string& value::member::key()const { return *_key; } - value& value::member::val() { return *_val; } - const value& value::member::val()const { return *_val; } - - value::value() - :_obj(nullptr),_obj_type(nullptr){ slog( "%p", this ); } - - value::value( value&& v ) - :_obj(v._obj),_obj_type(v._obj_type) - { - slog( "move construct value" ); - v._obj_type = nullptr; - v._obj = nullptr; - } - - value::~value() { - slog( "~%p", this ); - if( nullptr != _obj_type ) { - if( _obj != nullptr ) { - slog( "obj_type %p", _obj_type ); - slog( "obj_type %s", _obj_type->name() ); - slog(".. obj type %p %s", _obj, _obj_type->name() ); - size_t s = _obj_type->size_of(); - if( s > sizeof(_obj) ) { - slog( "destroy! %p", _obj ); - _obj_type->destroy( _obj ); - } else { - slog( "destructor! %p", &_obj ); - _obj_type->destructor( &_obj ); - } - } - } - } - - value::value( const cref& v ) { - slog( "this:%p %s from cref" , this, v._reflector.name()); - _obj_type = &v._reflector; - size_t s = _obj_type->size_of(); - if( s > sizeof(_obj) ) { - slog( "construct %s heap of size %d",_obj_type->name(),_obj_type->size_of() ); - _obj = new char[_obj_type->size_of()]; - slog( "v._obj %p", v._obj ); - _obj_type->copy_construct( _obj, v._obj ); - } else { - slog( "construct %s in place %p type p %p", _obj_type->name(), _obj,_obj_type ); - _obj_type->copy_construct( &_obj, v._obj ); - } - } - - value::value( const value& v ) { - slog( "%p", this ); - // slog( "copy v %s", v.type()->name() ); - _obj_type = v._obj_type; - if( nullptr != _obj_type ) { - size_t s = _obj_type->size_of(); - if( s > sizeof(_obj) ) { - _obj = new char[_obj_type->size_of()]; - _obj_type->copy_construct( _obj, v._obj ); - } else { - _obj_type->copy_construct( &_obj, &v._obj ); - } - } - } - value& value::operator=( value&& v ) { - swap( v._obj, _obj); - swap( v._obj_type, _obj_type); - return *this; - if( v.type() == nullptr ) { - return *this; - } - slog( "move assign v %s", v.type()->name() ); - size_t s = _obj_type->size_of(); - if( s > sizeof(_obj) ) { - slog( "swap pointers to heap.." ); - fc::swap( _obj, v._obj ); - fc::swap( _obj_type, v._obj_type ); - } else { - slog( "move construct in place %p %s", this, v._obj_type->name() ); - int64_t tmp; - if( nullptr != _obj_type && nullptr != v._obj_type ) { - slog( "swaping objs %s and %s", _obj_type->name(), v._obj_type->name() ); - slog( "swaping objs %p and %p", &_obj, &v._obj ); - slog( "&tmp = %p", &tmp ); - _obj_type->move_construct( &tmp, &_obj ); - slog( "move to tmp" ); - v._obj_type->move_construct( &_obj, &v._obj ); - slog( "move to dest" ); - _obj_type->move_construct( &v._obj, &tmp ); - slog( "move to src" ); - } else { - fc::swap( _obj, v._obj ); - fc::swap( _obj_type, v._obj_type ); - } - } - - /* - value tmp(std::move(v)); - return *this; - size_t s = _obj_type->size_of(); - if( s > sizeof(_obj) ) { - slog( "" ); - fc::swap( _obj, v._obj ); - } else { - slog( "swap..." ); - void* tmp; - _obj_type->move( &tmp, &_obj ); - _obj_type->move( &_obj, &v._obj ); - _obj_type->move( &v._obj, &tmp ); - } - fc::swap( _obj_type, v._obj_type ); - */ - return *this; - } - value& value::operator=( const value& v ) { - slog( "assign copy" ); - value t(v); fc::swap(t,*this); - return *this; - } - value& value::operator=( const cref& v ) { - //slog( "assign copy this %p %p %s obj_type %s",_obj,_obj_type, v._reflector.name(),_obj_type->name() ); - //if( _obj_type != null_ptr ) { - //} - wlog( ".." ); - value t(v); - - wlog( "swap" ); - //swap( t._obj, _obj ); - //swap( t._obj_type, _obj_type ); - fc::swap(t,*this); - slog( "done swap" ); - return *this; - } - /** - * @pre value is null or an object - */ - value& value::operator[]( const string& key ) { - return (*this)[key.c_str()]; - } - - value& value::operator[]( string&& key ) { - if( is_null() ) { - *this = vector(1); - } - if( _obj_type == &reflector< vector >::instance() ) { - vector& vec = *static_cast*>(ptr()); - for( uint32_t i = 0; i < vec.size(); ++i ) { - if( vec[i].key() == key ) { return vec[i].val(); } - } - vec.push_back(member(fc::move(key))); - return vec.back().val(); - } - FC_THROW( bad_cast() ); - } - - - const value& value::operator[]( const string& key )const { - return (*this)[key.c_str()]; - } - - value& value::operator[]( const char* key ) { - if( is_null() ) { - *this = vector(); - } - if( _obj_type == &reflector >::instance() ) { - slog( "sizeof vector: %d", sizeof( vector ) ); - vector& v = *static_cast*>((void*)&_obj); - vector::iterator i = v.begin(); - while( i != v.end() ) { - // todo convert to string cmp to prevent temporary string?? - if( i->key() == key ) { - return i->val(); - } - ++i; - } - v.push_back( member( key ) ); - return v.back().val(); - } - // visit the native struct looking for key and return a ref to the value - // - // if not found, then convert native struct into vector and recurse - } - const value& value::operator[]( const char* key )const { - if( is_null() ) { - // TODO: throw! - } - if( _obj_type == &reflector >::instance() ) { - const vector& v = *static_cast*>((void*)&_obj); - vector::const_iterator i = v.begin(); - while( i != v.end() ) { - if( i->key() == key ) { - return i->val(); - } - ++i; - } - FC_THROW( range_error() ); - } - FC_THROW( bad_cast() ); - } - - value& value::operator[]( int index ) { - return (*this)[uint64_t(index)]; - } - value& value::operator[]( uint64_t index ) { - if( is_null() ) { - slog( "init from vector of size %d", index+1 ); - //static_assert( sizeof(_obj) >= sizeof(vector), "sanity check" ); - *this = vector(index+1); - //new (&_obj) vector(index+1); - //_obj_type = &reflector >::instance(); - } - if( _obj_type == &reflector >::instance() ) { - slog( "return ref to index..." ); - vector& v = *static_cast*>(ptr()); - if( v.size() <= index ) { v.resize(index+1); } - slog( "index %d vs size %d", index, v.size() ); - return v.at(index); - } - // visit the native struct looking for index... - // - // - } - const value& value::operator[]( uint64_t index )const { - if( is_null() ) { - // THROW - while(1) ; - } - if( _obj_type == &reflector >::instance() ) { - const vector& v = *static_cast*>(ptr()); - return v[index]; - } - // visit the native struct looking for index... throw if not found. - } - - bool value::key_exists( const string& key ) { - return key_exists(key.c_str()); - } - bool value::key_exists( const char* key ) { - return false; - } - bool value::is_array()const { - return _obj_type == &reflector >::instance(); - } - bool value::is_object()const { - return _obj_type == &reflector >::instance(); - } - bool value::is_null()const { - return _obj_type == nullptr; - } - bool value::is_string()const { - return _obj_type == &reflector::instance(); - } - bool value::is_float()const { - return _obj_type == &reflector::instance(); - } - bool value::is_double()const { - return _obj_type == &reflector::instance(); - } - bool value::is_real()const { - return is_float() || is_double(); - } - bool value::is_integer()const { - return false; - } - bool value::is_boolean()const { - return _obj_type == &reflector::instance(); - } - fwd,24> value::get_keys()const { - fwd,24> s; - return s; - } - - value& value::push_back( const value& v ) { - slog("here I go again... type %p %s", _obj_type, _obj_type ? _obj_type->name(): "null" ); - if( is_null() ) { - wlog( "converting this to vector..." ); - *this = vector(); - } - if( _obj_type == &reflector >::instance() ) { - vector& vec = *static_cast*>(ptr()); - vec.push_back(v); - } else { - FC_THROW( bad_cast() ); - } - return *this; - } - value& value::push_back( value&& v ) { - slog("here I go again... type %p %s", _obj_type, _obj_type ? _obj_type->name(): "null" ); - if( is_null() ) { - *this = vector(); - } - if( _obj_type == &reflector >::instance() ) { - vector& vec = *static_cast*>(ptr()); - vec.push_back(fc::move(v)); - } else { - FC_THROW( bad_cast() ); - } - return *this; - } - - void* value::ptr(){ - if( nullptr != _obj_type ) { - if( _obj_type->size_of() > sizeof(_obj) ) - return _obj; - return &_obj; - } - return nullptr; - } - const void* value::ptr()const { - if( _obj_type ) { - if( _obj_type->size_of() > sizeof(_obj) ) - return _obj; - return &_obj; - } - return nullptr; - } - - abstract_reflector* value::type()const { return _obj_type; } -} // namespace fc - - -namespace fc { - const char* reflector::name()const { return "value"; } - void reflector::visit( void* s, const abstract_visitor& v )const { - } - void reflector::visit( const void* s, const abstract_const_visitor& v )const { - const value& val = *((const value*)s); - if( val.is_null() ) { v.visit(); } - else if( val.is_array() ) { - const vector& vec = *static_cast*>(val.ptr()); - auto s = vec.size(); - auto e = vec.end(); - int idx = 0; - for( auto i = vec.begin(); i != e; ++i ) { - v.visit( idx, s, *i ); - ++idx; - } - } else if( val.is_object() ) { - const vector& vec = *static_cast*>(val.ptr()); - auto s = vec.size(); - auto e = vec.end(); - int idx = 0; - for( auto i = vec.begin(); i != e; ++i ) { - v.visit( i->key().c_str(), idx, s, i->val() ); - ++idx; - } + namespace detail { + struct value_visitor { + virtual void operator()( int8_t& v ){}; + virtual void operator()( int16_t& v ){}; + virtual void operator()( int32_t& v ){}; + virtual void operator()( int64_t& v ){}; + virtual void operator()( uint8_t& v ){}; + virtual void operator()( uint16_t& v ){}; + virtual void operator()( uint32_t& v ){}; + virtual void operator()( uint64_t& v ){}; + virtual void operator()( float& v ){}; + virtual void operator()( double& v ){}; + virtual void operator()( bool& v ){}; + virtual void operator()( fc::string& v ){}; + virtual void operator()( value::object& ){}; + virtual void operator()( value::array& ){}; + virtual void operator()( ){}; + }; + + + // fundamental values... + template + struct value_holder_impl : value_holder { + static_assert( !fc::is_class::value, "only fundamental types can be stored without specialization" ); + virtual const char* type()const { return fc::get_typename::name(); } + virtual void visit( value::const_visitor&& v )const{ v(val); } + virtual void visit( value_visitor&& v ) { v(val); } + virtual void clear() { val = T(); } + virtual size_t size()const { return 0; } + + virtual value_holder* move_helper( char* c ){ return new(c) value_holder_impl( fc::move(val) ); } + virtual value_holder* copy_helper( char* c )const{ return new(c) value_holder_impl(val); } + + template + value_holder_impl( V&& v ):val( fc::forward(v) ){} + + T val; + }; + + template<> + struct value_holder_impl : value_holder { + value_holder_impl(){}; + // typedef void_t T; + virtual const char* type()const { return "void"; } + virtual void visit( value::const_visitor&& v )const{ v(); } + virtual void visit( value_visitor&& v ) { v(); } + virtual void clear() { } + virtual size_t size()const { return 0; } + + virtual value_holder* move_helper( char* c ){ return new(c) value_holder_impl(); } + virtual value_holder* copy_helper( char* c )const{ return new(c) value_holder_impl();} + }; + + + + template<> + struct value_holder_impl : value_holder { + template + value_holder_impl( V&& v ):val( fc::forward(v) ){} + + virtual const char* type()const { return "string"; } + virtual void visit( value::const_visitor&& v )const { v(val); } + virtual void visit( value_visitor&& v ) { v(val); } + + virtual value_holder* move_helper( char* c ){ return new(c) value_holder_impl( fc::move(val) ); } + 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; } + + + fc::string val; + }; + + template<> + struct value_holder_impl : value_holder { + virtual const char* type()const { return "object"; } + virtual void visit( value::const_visitor&& v )const; + virtual void visit( value_visitor&& v ); + virtual value_holder* move_helper( char* c ); + virtual value_holder* copy_helper( char* c )const; + virtual void reserve( size_t s ); + + virtual void clear(); + virtual size_t size()const; + + template + value_holder_impl( V&& v ):val( fc::forward(v) ){} + + value::object val; + }; + + template<> + struct value_holder_impl : value_holder { + virtual const char* type()const { return "array"; } + virtual void visit( value::const_visitor&& v )const; + virtual void visit( value_visitor&& v ); + virtual value_holder* move_helper( char* c ); + virtual value_holder* copy_helper( char* c )const; + + virtual void resize( size_t s ); + virtual void reserve( size_t s ); + virtual value& at( size_t i); + virtual const value& at( size_t i)const; + virtual void push_back( value&& v ); + + template + value_holder_impl( V&& v ):val( fc::forward(v) ){} + + virtual void clear(); + virtual size_t size()const; - } else { - slog( "val type %s", val.type()->name() ); - val.type()->visit(val.ptr(), v ); - } - } - reflector& reflector::instance() { static reflector inst; return inst; } -} // namespace fc + value::array val; + }; + value_holder::~value_holder(){} + const char* value_holder::type()const { return "null"; } + void value_holder::visit( value::const_visitor&& v )const { v(); } + void value_holder::visit( value_visitor&& v ) { v(); } + + 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()); } + + value_holder* value_holder::move_helper( char* c ) { return new(c) value_holder(); } + value_holder* value_holder::copy_helper( char* c )const{ return new(c) value_holder(); } + + void value_holder_impl::resize( size_t s ) { val.fields.resize(s); } + void value_holder_impl::reserve( size_t s ) { val.fields.reserve(s); } + value& value_holder_impl::at( size_t i) { return val.fields[i]; } + const value& value_holder_impl::at( size_t i)const { return val.fields[i]; } + value_holder* value_holder_impl::move_helper( char* c ){ return new(c) value_holder_impl( fc::move(val) ); } + value_holder* value_holder_impl::copy_helper( char* c )const{ return new(c) value_holder_impl(val); } + + void value_holder_impl::clear() { val.fields.clear(); } + size_t value_holder_impl::size()const { return val.fields.size(); } + void value_holder_impl::visit( value::const_visitor&& v )const { v(val); } + void value_holder_impl::visit( value_visitor&& v ) { v(val); } + void value_holder_impl::push_back( value&& v ) { val.fields.push_back( fc::move(v) ); } + + + void value_holder_impl::visit( value::const_visitor&& v )const { v(val); } + void value_holder_impl::visit( value_visitor&& v ) { v(val); } + value_holder* value_holder_impl::move_helper( char* c ) { return new(c) value_holder_impl( fc::move(val) ); } + value_holder* value_holder_impl::copy_helper( char* c )const { return new(c) value_holder_impl(val); } + void value_holder_impl::reserve( size_t s ) { val.fields.reserve(s); } + + void value_holder_impl::clear() { val = value::object(); } + size_t value_holder_impl::size()const { return val.fields.size(); } + } // namespace detail + +static detail::value_holder* gh( aligned<24>& h ) { + return (detail::value_holder*)h._store._data; +} +static const detail::value_holder* gh( const aligned<24>& h ) { + return (const detail::value_holder*)&h._store._data; +} + +value::value() { + new (holder) detail::value_holder(); +} +value::value( value&& m ) { + gh(m.holder)->move_helper(holder._store._data); +} +value::value( const value& m ){ + gh(m.holder)->copy_helper(holder._store._data); +} +value::value( char* c ) { + new (holder) detail::value_holder_impl( c ); +} +value::~value() { + gh(holder)->~value_holder(); +} +value::value( int8_t v){ + static_assert( sizeof(holder) >= sizeof( detail::value_holder_impl ), "size check" ); + new (holder) detail::value_holder_impl(v); +} +value::value( int16_t v){ + static_assert( sizeof(holder) >= sizeof( detail::value_holder_impl ), "size check" ); + new (holder) detail::value_holder_impl(v); +} +value::value( int32_t v){ + new (holder) detail::value_holder_impl(v); +} +value::value( int64_t v){ + new (holder) detail::value_holder_impl(v); +} +value::value( uint8_t v){ + new (holder) detail::value_holder_impl(v); +} +value::value( uint16_t v){ + new (holder) detail::value_holder_impl(v); +} +value::value( uint32_t v){ + new (holder) detail::value_holder_impl(v); +} +value::value( uint64_t v){ + new (holder) detail::value_holder_impl(v); +} +value::value( double v){ + new (holder) detail::value_holder_impl(v); +} +value::value( float v){ + new (holder) detail::value_holder_impl(v); +} +value::value( bool v){ + new (holder) detail::value_holder_impl(v); +} +value::value( fc::string&& v){ + new (holder) detail::value_holder_impl(fc::move(v)); +} +value::value( fc::string& v){ + new (holder) detail::value_holder_impl(v); +} +value::value( const fc::string& v){ + new (holder) detail::value_holder_impl(v); +} +value::value( value::object&& o ){ + static_assert( sizeof(holder) >= sizeof( detail::value_holder_impl ), "size check" ); + new (holder) detail::value_holder_impl(fc::move(o)); +} +value::value( value::array&& a ){ + static_assert( sizeof(holder) >= sizeof( detail::value_holder_impl ), "size check" ); + new (holder) detail::value_holder_impl(fc::move(a)); +} +value::value( const value::array& a ){ + static_assert( sizeof(holder) >= sizeof( detail::value_holder_impl ), "size check" ); + new (holder) detail::value_holder_impl(a); +} +value::value( value::array& a ){ + static_assert( sizeof(holder) >= sizeof( detail::value_holder_impl ), "size check" ); + new (holder) detail::value_holder_impl(a); +} +value::value( const value::object& a ){ + static_assert( sizeof(holder) >= sizeof( detail::value_holder_impl ), "size check" ); + new (holder) detail::value_holder_impl(a); +} +value::value( value::object& a ){ + static_assert( sizeof(holder) >= sizeof( detail::value_holder_impl ), "size check" ); + new (holder) detail::value_holder_impl(a); +} + +value& value::operator=( value&& v ){ + decltype(holder) tmp; + gh(holder)->move_helper(tmp); + gh(v.holder)->move_helper(holder); + gh(tmp)->move_helper(v.holder); + return *this; +} +value& value::operator=( const value& v ){ + if( this == &v ) return *this; + gh(holder)->~value_holder(); + gh(v.holder)->copy_helper(holder); + return *this; +} + +value::object::const_iterator value::find( const char* key )const { + if( strcmp(gh(holder)->type(), "object") == 0) { + const detail::value_holder_impl* o = static_cast*>(gh(holder)); + for( auto i = o->val.fields.begin(); + i != o->val.fields.end(); ++i ) { + if( strcmp( i->key.c_str(), key ) == 0 ) + return i; + } + return o->val.fields.end(); + } + FC_THROW_MSG( "Bad cast of %s to object", gh(holder)->type() ); + return nullptr; +} +value::object::const_iterator value::begin()const { + if( strcmp(gh(holder)->type(), "object") == 0 ) { + const detail::value_holder_impl* o = static_cast*>(gh(holder)); + return o->val.fields.begin(); + } + FC_THROW_MSG( "Bad cast of %s to object", gh(holder)->type() ); + return nullptr; +} +value::object::const_iterator value::end()const { + if( strcmp(gh(holder)->type(), "object" ) == 0 ) { + const detail::value_holder_impl* o = static_cast*>(gh(holder)); + return o->val.fields.end(); + } + FC_THROW_MSG( "Bad cast of %s to object", gh(holder)->type() ); + return nullptr; +} +value& value::operator[]( const char* key ) { + if( strcmp(gh(holder)->type(), "object") == 0) { + detail::value_holder_impl* o = static_cast*>(gh(holder)); + for( auto i = o->val.fields.begin(); + i != o->val.fields.end(); ++i ) { + if( strcmp( i->key.c_str(), key ) == 0 ) + return i->val; + } + o->val.fields.push_back( key_val(key) ); + return o->val.fields.back().val; + } else if (strcmp(gh(holder)->type(), "null" ) == 0 ) { + new (holder) detail::value_holder_impl(value::object()); + return (*this)[key]; + } + FC_THROW_MSG( "Bad cast of %s to object", gh(holder)->type() ); + return *((value*)0); +} +value& value::operator[]( const fc::string& key ) { return (*this)[key.c_str()]; } +const value& value::operator[]( const fc::string& key )const { return (*this)[key.c_str()]; } +const value& value::operator[]( const char* key )const { + auto i = find(key); + if( i == end() ) { + FC_THROW_MSG( "Key '%s' not found in object", key ); + } + return i->val; +} + +void value::clear() { + gh(holder)->clear(); +} +size_t value::size()const { + return gh(holder)->size(); +} +void value::resize( size_t s ) { + gh(holder)->resize(s); +} +void value::reserve( size_t s ) { + gh(holder)->reserve(s); +} +void value::push_back( value&& v ) { + gh(holder)->push_back(fc::move(v)); +} +value& value::operator[]( int32_t idx ) { + return gh(holder)->at(idx); +} +const value& value::operator[]( int32_t idx )const { + return gh(holder)->at(idx); +} + +const char* value::type()const { return gh(holder)->type(); } + +void value::visit( value::const_visitor&& v )const { + auto h = ((detail::value_holder*)&holder[0]); + h->visit( fc::move(v) ); +} + +} // namepace fc diff --git a/src/value_cast.cpp b/src/value_cast.cpp index abaeff1..e69de29 100644 --- a/src/value_cast.cpp +++ b/src/value_cast.cpp @@ -1,95 +0,0 @@ -#include -#include -#include -#include - - -namespace fc { - - #define CAST_VISITOR_IMPL(X) \ - void reinterpret_value_visitor::visit()const{\ - FC_THROW( bad_cast() );\ - } \ - void reinterpret_value_visitor::visit( const char& c )const{ _s = c; } \ - void reinterpret_value_visitor::visit( const uint8_t& c )const{ _s = c; } \ - void reinterpret_value_visitor::visit( const uint16_t& c )const{ _s = c; } \ - void reinterpret_value_visitor::visit( const uint32_t& c )const{ _s = c; } \ - void reinterpret_value_visitor::visit( const uint64_t& c )const{ _s = c; } \ - void reinterpret_value_visitor::visit( const int8_t& c )const{ _s = c; } \ - void reinterpret_value_visitor::visit( const int16_t& c )const{ _s = c; } \ - void reinterpret_value_visitor::visit( const int32_t& c )const{ _s = c; } \ - void reinterpret_value_visitor::visit( const int64_t& c )const{ _s = c; } \ - void reinterpret_value_visitor::visit( const double& c )const{ _s = c; } \ - void reinterpret_value_visitor::visit( const float& c )const{ _s = c; } \ - void reinterpret_value_visitor::visit( const bool& c )const{ _s = c; } \ - void reinterpret_value_visitor::visit( const string& c )const{\ - _s = boost::lexical_cast( reinterpret_cast(c) ); \ - } \ - void reinterpret_value_visitor::visit( const char* member, int idx, int size, \ - const cref& v)const{\ - FC_THROW( bad_cast() );\ - }\ - void reinterpret_value_visitor::visit( int idx, int size, const cref& v)const{\ - FC_THROW( bad_cast() );\ - } - - CAST_VISITOR_IMPL(int64_t); - CAST_VISITOR_IMPL(int32_t); - CAST_VISITOR_IMPL(int16_t); - CAST_VISITOR_IMPL(int8_t); - CAST_VISITOR_IMPL(uint64_t); - CAST_VISITOR_IMPL(uint32_t); - CAST_VISITOR_IMPL(uint16_t); - CAST_VISITOR_IMPL(uint8_t); - CAST_VISITOR_IMPL(double); - CAST_VISITOR_IMPL(float); - CAST_VISITOR_IMPL(bool); - - #undef CAST_VISITOR_IMPL - - void reinterpret_value_visitor::visit()const{ - FC_THROW( bad_cast() ); - } - void reinterpret_value_visitor::visit( const char& c )const{ - slog("" ); - reinterpret_cast(_s) = boost::lexical_cast(c); - } - void reinterpret_value_visitor::visit( const uint8_t& c )const{ - reinterpret_cast(_s) = boost::lexical_cast(c); } - void reinterpret_value_visitor::visit( const uint16_t& c )const{ - reinterpret_cast(_s) = boost::lexical_cast(c); } - void reinterpret_value_visitor::visit( const uint32_t& c )const{ - reinterpret_cast(_s) = boost::lexical_cast(c); } - void reinterpret_value_visitor::visit( const uint64_t& c )const{ - reinterpret_cast(_s) = boost::lexical_cast(c); } - void reinterpret_value_visitor::visit( const int8_t& c )const{ - reinterpret_cast(_s) = boost::lexical_cast(c); } - void reinterpret_value_visitor::visit( const int16_t& c )const{ - reinterpret_cast(_s) = boost::lexical_cast(c); } - void reinterpret_value_visitor::visit( const int32_t& c )const{ - reinterpret_cast(_s) = boost::lexical_cast(c); } - void reinterpret_value_visitor::visit( const int64_t& c )const{ - reinterpret_cast(_s) = boost::lexical_cast(c); } - void reinterpret_value_visitor::visit( const double& c )const{ - reinterpret_cast(_s) = boost::lexical_cast(c); } - void reinterpret_value_visitor::visit( const float& c )const{ - reinterpret_cast(_s) = boost::lexical_cast(c); } - void reinterpret_value_visitor::visit( const bool& c )const{ - reinterpret_cast(_s) = boost::lexical_cast(c); } - - void reinterpret_value_visitor::visit( const string& c )const{ - slog( "" ); - _s = c; - } - void reinterpret_value_visitor::visit( const char* member, int idx, int size, - const cref& v)const{ - elog( "%s", member ); - FC_THROW( bad_cast() ); - } - void reinterpret_value_visitor::visit( int idx, int size, const cref& v)const{ - elog( "%d of %d", idx, size ); - FC_THROW( bad_cast() ); - } - - -}