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