From 34e33d058b405ad61d19544aa46e80d4a0bc2741 Mon Sep 17 00:00:00 2001 From: Daniel Larimer Date: Sat, 8 Sep 2012 02:41:28 -0400 Subject: [PATCH] adding sha1 and hex methods... --- CMakeLists.txt | 6 +- include/fc/asio.hpp | 264 ++++++++++++++++++++++++++++++++++ include/fc/buffer.hpp | 21 +++ include/fc/exception.hpp | 2 +- include/fc/filesystem.hpp | 9 ++ include/fc/function.hpp | 48 +------ include/fc/hex.hpp | 16 +++ include/fc/sha1.hpp | 57 ++++++++ include/fc/static_reflect.hpp | 218 ++++++++++++++++++++++++++++ include/fc/task.hpp | 13 +- src/hex.cpp | 42 ++++++ src/sha1.cpp | 64 +++++++++ 12 files changed, 708 insertions(+), 52 deletions(-) create mode 100644 include/fc/asio.hpp create mode 100644 include/fc/buffer.hpp create mode 100644 include/fc/filesystem.hpp create mode 100644 include/fc/hex.hpp create mode 100644 include/fc/sha1.hpp create mode 100644 include/fc/static_reflect.hpp create mode 100644 src/hex.cpp create mode 100644 src/sha1.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 3143fcf..a830694 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -59,6 +59,8 @@ set( sources src/exception.cpp src/thread.cpp src/value.cpp + src/hex.cpp + src/sha1.cpp src/value_cast.cpp ) setup_library( fc SOURCES ${sources} ) @@ -66,5 +68,5 @@ setup_library( fc SOURCES ${sources} ) #add_executable( test_vec tests/vector_test.cpp ) #target_link_libraries( test_vec fc ${Boost_SYSTEM_LIBRARY} ${Boost_CHRONO_LIBRARY} ${Boost_THREAD_LIBRARY} ${Boost_CONTEXT_LIBRARY} ) -add_executable( unit_tests tests/unit.cpp ) -target_link_libraries( unit_tests fc ${Boost_CHRONO_LIBRARY} ${Boost_THREAD_LIBRARY} ${Boost_CONTEXT_LIBRARY} ${Boost_SYSTEM_LIBRARY} ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY} ) +#add_executable( unit_tests tests/unit.cpp ) +#target_link_libraries( unit_tests fc ${Boost_CHRONO_LIBRARY} ${Boost_THREAD_LIBRARY} ${Boost_CONTEXT_LIBRARY} ${Boost_SYSTEM_LIBRARY} ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY} ) diff --git a/include/fc/asio.hpp b/include/fc/asio.hpp new file mode 100644 index 0000000..3d97be0 --- /dev/null +++ b/include/fc/asio.hpp @@ -0,0 +1,264 @@ +/** + * @file fc/cmt/asio.hpp + * @brief defines wrappers for boost::asio functions + */ +#ifndef _FC_ASIO_HPP_ +#define _FC_ASIO_HPP_ +#include +#include +#include +#include + +namespace fc { +/** + * @brief defines fc::cmt wrappers for boost::asio functions. + */ +namespace asio { + /** + * @brief internal implementation types/methods for fc::cmt::asio + */ + namespace detail { + using namespace fc; + + void read_write_handler( const promise::ptr& p, + const boost::system::error_code& ec, + size_t bytes_transferred ); + void read_write_handler_ec( promise* p, + boost::system::error_code* oec, + const boost::system::error_code& ec, + size_t bytes_transferred ); + void error_handler( const promise::ptr& p, + const boost::system::error_code& ec ); + void error_handler_ec( promise* p, + const boost::system::error_code& ec ); + + template + struct non_blocking { + bool operator()( C& c ) { return c.non_blocking(); } + bool operator()( C& c, bool s ) { c.non_blocking(s); return true; } + }; + + #if WIN32 // windows stream handles do not support non blocking! + template<> + struct non_blocking { + typedef boost::asio::windows::stream_handle C; + bool operator()( C& ) { return false; } + bool operator()( C&, bool ) { return false; } + }; + #endif + } + /** + * @return the default boost::asio::io_service for use with fc::cmt::asio + * + * This IO service is automatically running in its own thread to service asynchronous + * requests without blocking any other threads. + */ + boost::asio::io_service& default_io_service(); + + /** + * @brief wraps boost::asio::async_read + * @pre s.non_blocking() == true + * @return the number of bytes read. + */ + template + size_t read( AsyncReadStream& s, const MutableBufferSequence& buf ) { + detail::non_blocking non_blocking; + + // TODO: determine if non_blocking query results in a system call that + // will slow down every read... + if( non_blocking(s) || non_blocking(s,true) ) { + boost::system::error_code ec; + size_t r = boost::asio::read( s, buf, ec ); + if( !ec ) return r; + if( ec != boost::asio::error::would_block ) + BOOST_THROW_EXCEPTION( boost::system::system_error(ec) ); + } + + promise::ptr p(new promise("fc::cmt::asio::read")); + boost::asio::async_read( s, buf, boost::bind( detail::read_write_handler, p, _1, _2 ) ); + return p->wait(); + } + /** + * This method will read at least 1 byte from the stream and will + * cooperatively block until that byte is available or an error occurs. + * + * If the stream is not in 'non-blocking' mode it will be put in 'non-blocking' + * mode it the stream supports s.non_blocking() and s.non_blocking(bool). + * + * If in non blocking mode, the call will be synchronous avoiding heap allocs + * and context switching. If the sync call returns 'would block' then an + * promise is created and an async read is generated. + * + * @return the number of bytes read. + */ + template + size_t read_some( AsyncReadStream& s, const MutableBufferSequence& buf ) { + detail::non_blocking non_blocking; + + // TODO: determine if non_blocking query results in a system call that + // will slow down every read... + if( non_blocking(s) || non_blocking(s,true) ) { + boost::system::error_code ec; + size_t r = s.read_some( buf, ec ); + if( !ec ) return r; + if( ec != boost::asio::error::would_block ) + BOOST_THROW_EXCEPTION( boost::system::system_error(ec) ); + } + + promise::ptr p(new promise("fc::cmt::asio::read_some")); + s.async_read_some( buf, boost::bind( detail::read_write_handler, p, _1, _2 ) ); + return p->wait(); + } + + /** @brief wraps boost::asio::async_write + * @return the number of bytes written + */ + template + size_t write( AsyncWriteStream& s, const ConstBufferSequence& buf ) { + detail::non_blocking non_blocking; + + if( non_blocking(s) || non_blocking(s,true) ) { + boost::system::error_code ec; + size_t r = boost::asio::write( s, buf, ec ); + if( !ec ) return r; + if( ec != boost::asio::error::would_block) { + BOOST_THROW_EXCEPTION( boost::system::system_error(ec) ); + } + } + promise::ptr p(new promise("fc::cmt::asio::write")); + boost::asio::async_write(s, buf, boost::bind( detail::read_write_handler, p, _1, _2 ) ); + return p->wait(); + } + + /** + * @pre s.non_blocking() == true + * @brief wraps boost::asio::async_write_some + * @return the number of bytes written + */ + template + size_t write_some( AsyncWriteStream& s, const ConstBufferSequence& buf ) { + detail::non_blocking non_blocking; + + if( non_blocking(s) || non_blocking(s,true) ) { + boost::system::error_code ec; + size_t r = s.write_some( buf, ec ); + if( !ec ) return r; + if( ec != boost::asio::error::would_block) { + BOOST_THROW_EXCEPTION( boost::system::system_error(ec) ); + } + } + promise::ptr p(new promise("fc::cmt::asio::write_some")); + s.async_write_some( buf, boost::bind( detail::read_write_handler, p, _1, _2 ) ); + return p->wait(); + } + + template + class sink : public boost::iostreams::sink { + public: + // struct category : boost::iostreams::sink::category {}; + typedef char type; + + sink( AsyncWriteStream& p ):m_stream(p){} + + std::streamsize write( const char* s, std::streamsize n ) { + return fc::cmt::asio::write( m_stream, boost::asio::const_buffers_1(s,n) ); + } + void close() { m_stream.close(); } + + private: + AsyncWriteStream& m_stream; + }; + + template + class source : public boost::iostreams::source { + public: + // struct category : boost::iostreams::sink::category {}; + typedef char type; + + source( AsyncReadStream& p ):m_stream(p){} + + std::streamsize read( char* s, std::streamsize n ) { + return fc::cmt::asio::read_some( m_stream, boost::asio::buffer(s,n) ); + } + void close() { m_stream.close(); } + + private: + AsyncReadStream& m_stream; + }; + template + class io_device { + public: + typedef boost::iostreams::bidirectional_device_tag category; + typedef char char_type; + + io_device( AsyncStream& p ):m_stream(p){} + + std::streamsize write( const char* s, std::streamsize n ) { + return fc::cmt::asio::write( m_stream, boost::asio::const_buffers_1(s,static_cast(n)) ); + } + std::streamsize read( char* s, std::streamsize n ) { + try { + return fc::cmt::asio::read_some( m_stream, boost::asio::buffer(s,n) ); + } catch ( const boost::system::system_error& e ) { + if( e.code() == boost::asio::error::eof ) + return -1; + throw; + } + } + void close() { m_stream.close(); } + + private: + AsyncStream& m_stream; + }; + + + namespace tcp { + typedef boost::asio::ip::tcp::endpoint endpoint; + typedef boost::asio::ip::tcp::resolver::iterator resolver_iterator; + typedef boost::asio::ip::tcp::resolver resolver; + std::vector resolve( const std::string& hostname, const std::string& port ); + + /** @brief wraps boost::asio::async_accept + * @post sock is connected + * @post sock.non_blocking() == true + * @throw on error. + */ + template + void accept( AcceptorType& acc, SocketType& sock ) { + promise::ptr p( new promise("fc::cmt::asio::tcp::accept") ); + acc.async_accept( sock, boost::bind( fc::cmt::asio::detail::error_handler, p, _1 ) ); + auto ec = p->wait(); + if( !ec ) sock.non_blocking(true); + if( ec ) BOOST_THROW_EXCEPTION( boost::system::system_error(ec) ); + } + + /** @brief wraps boost::asio::socket::async_connect + * @post sock.non_blocking() == true + * @throw on error + */ + template + void connect( AsyncSocket& sock, const EndpointType& ep ) { + promise::ptr p(new promise("fc::cmt::asio::tcp::connect")); + sock.async_connect( ep, boost::bind( fc::cmt::asio::detail::error_handler, p, _1 ) ); + auto ec = p->wait(); + if( !ec ) sock.non_blocking(true); + if( ec ) BOOST_THROW_EXCEPTION( boost::system::system_error(ec) ); + } + + typedef boost::iostreams::stream > ostream; + typedef boost::iostreams::stream > istream; + typedef boost::iostreams::stream > iostream; + + } + namespace udp { + typedef boost::asio::ip::udp::endpoint endpoint; + typedef boost::asio::ip::udp::resolver::iterator resolver_iterator; + typedef boost::asio::ip::udp::resolver resolver; + /// @brief resolve all udp::endpoints for hostname:port + std::vector resolve( resolver& r, const std::string& hostname, const std::string& port ); + } + + +} } // namespace fc::asio + +#endif // _BOOST_CMT_ASIO_HPP_ diff --git a/include/fc/buffer.hpp b/include/fc/buffer.hpp new file mode 100644 index 0000000..3af9a21 --- /dev/null +++ b/include/fc/buffer.hpp @@ -0,0 +1,21 @@ +#ifndef _FC_BUFFER_HPP_ +#define _FC_BUFFER_HPP_ +namespace fc { + + struct const_buffer { + const_buffer( const char* const c = 0, size_t l = 0 ) + :data(c),len(l){} + const char* const data; + size_t len; + }; + + struct mutable_buffer { + mutable_buffer( char* c = 0, size_t l = 0 ) + :data(c),len(l){} + char* data; + size_t len; + }; + +} + +#endif // _FC_BUFFER_HPP_ diff --git a/include/fc/exception.hpp b/include/fc/exception.hpp index fe5d40b..551792f 100644 --- a/include/fc/exception.hpp +++ b/include/fc/exception.hpp @@ -48,7 +48,7 @@ namespace fc { } // namespace fc -#define FC_THROW( X ) throw (X) +#define FC_THROW( X, ... ) throw (X) #endif // _FC_EXCEPTION_HPP_ diff --git a/include/fc/filesystem.hpp b/include/fc/filesystem.hpp new file mode 100644 index 0000000..20a7dd4 --- /dev/null +++ b/include/fc/filesystem.hpp @@ -0,0 +1,9 @@ +#ifndef _FC_FILESYSTEM_HPP_ +#define _FC_FILESYSTEM_HPP_ +#include + +namespace fc { + typedef boost::filesystem::path path; +} + +#endif // _FC_FILESYSTEM_HPP_ diff --git a/include/fc/function.hpp b/include/fc/function.hpp index da50863..7e316c6 100644 --- a/include/fc/function.hpp +++ b/include/fc/function.hpp @@ -1,50 +1,12 @@ #ifndef _FC_FUNCTION_HPP_ #define _FC_FUNCTION_HPP_ +#include +#include namespace fc { - - namespace detail { - template - void call( void* functor ) { - (*static_cast(functor*))(); - } - } - - class function { - public: - template - function( Functor&& f ) { - static_assert( sizeof(f) <= sizeof(store) ); - new ((void*)&store[0]) Functor( fc::forward(f) ); - call = &detail::call; - copy = &detail::copy; - move = &detail::move; - } - - function( const function& f ) - :call(f.call),move(f.move),copy(f.copy){ - copy( &f.store[0], &store[0] ); - } - - function( function&& f ) - :call(f.call),move(f.move),copy(f.copy){ - move( &f.store[0], &store[0] ); - } - - function& operator = ( function&& f ) { - - } - - void operator()()const { call(&store[0]); } - - private: - uint64_t store[8]; - void (*call)(void*); - void (*move)(void* src, void* dst); - void (*copy)(const void*, void* dst); - void (*destroy)(void*); - }; - + // place holder for more compile-effecient functor + template + using function = std::function; } #endif // _FC_FUNCTION_HPP_ diff --git a/include/fc/hex.hpp b/include/fc/hex.hpp new file mode 100644 index 0000000..3ae8d46 --- /dev/null +++ b/include/fc/hex.hpp @@ -0,0 +1,16 @@ +#ifndef _FC_HEX_HPP_ +#define _FC_HEX_HPP_ +#include +#include + +namespace fc { + uint8_t from_hex( char c ); + fc::string to_hex( const char* d, uint32_t s ); + + /** + * @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/sha1.hpp b/include/fc/sha1.hpp new file mode 100644 index 0000000..16648e8 --- /dev/null +++ b/include/fc/sha1.hpp @@ -0,0 +1,57 @@ +#ifndef _FC_SHA1_HPP_ +#define _FC_SHA1_HPP_ +#include +#include + +namespace fc { + + class sha1 { + public: + sha1(); + explicit sha1( const fc::string& hex_str ); + + fc::string str()const; + + operator fc::string()const; + + char* data()const; + + static sha1 hash( const char* d, uint32_t dlen ); + static sha1 hash( const fc::string& ); + + class encoder { + public: + encoder(); + + void write( const char* d, uint32_t dlen ); + void reset(); + sha1 result(); + + private: + struct impl; + fwd my; + }; + + template + inline friend T& operator<<( T& ds, const sha1& ep ) { + ds.write( (const char*)ep.hash, sizeof(ep.hash) ); + return ds; + } + + template + inline friend T& operator>>( T& ds, sha1& ep ) { + ds.read( (char*)ep.hash, sizeof(ep.hash) ); + return ds; + } + friend sha1 operator << ( const sha1& h1, uint32_t i ); + friend sha1 operator ^ ( const sha1& h1, const sha1 h2 ); + friend bool operator >= ( const sha1& h1, const sha1 h2 ); + friend bool operator > ( const sha1& h1, const sha1 h2 ); + private: + uint32_t _hash[5]; + }; + +} + +#endif // _FC_SHA1_HPP_ + diff --git a/include/fc/static_reflect.hpp b/include/fc/static_reflect.hpp new file mode 100644 index 0000000..4fb189b --- /dev/null +++ b/include/fc/static_reflect.hpp @@ -0,0 +1,218 @@ + +/** + * @file mace/reflect/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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//#include +//#include + +namespace mace { +/** + * @brief types, methods associated with the MACE.Reflect Library + */ +namespace reflect { + +/** + * @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 reflector{ + typedef T type; + typedef boost::fusion::vector<> base_class_types; + typedef boost::false_type is_defined; + typedef boost::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 mace::reflect + + +#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 + +#define FC_STATIC_REFLECT_VISIT_MEMBER( r, visitor, elem ) \ + visitor.TEMPLATE operator()( 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 ) \ +FC_STATIC_REFLECT_TYPEINFO(ENUM) \ +namespace mace { namespace reflect { \ +template<> struct reflector { \ + typedef boost::true_type is_defined; \ + typedef boost::true_type is_enum; \ + typedef boost::fusion::vector<> base_class_types; \ + 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( mace::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( mace::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 ) \ +FC_STATIC_REFLECT_TYPEINFO(TYPE) \ +namespace fc { \ +template<> struct static_reflector {\ + typedef TYPE type; \ + typedef boost::true_type is_defined; \ + typedef boost::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 ) \ +FC_STATIC_REFLECT_TYPEINFO(TYPE) \ +namespace mace { namespace reflect { \ +template<> struct static_reflector {\ + typedef TYPE type; \ + typedef boost::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 )\ + }; \ + typedef boost::fusion::vector base_class_types; \ + 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/task.hpp b/include/fc/task.hpp index 146867a..69b8700 100644 --- a/include/fc/task.hpp +++ b/include/fc/task.hpp @@ -2,6 +2,7 @@ #define _FC_TASK_HPP_ #include #include +#include namespace fc { struct context; @@ -56,29 +57,29 @@ namespace fc { class task : virtual public task_base, virtual public promise { public: template - task( Functor&& f ):task_base(&_functor[0]) { + task( Functor&& f ):task_base(&_functor) { static_assert( sizeof(f) <= sizeof(_functor), "sizeof(Functor) is larger than FunctorSize" ); - new ((char*)&_functor[0]) Functor( fc::forward(f) ); + new ((char*)&_functor) Functor( fc::forward(f) ); _destroy_functor = &detail::functor_destructor::destroy; _promise_impl = static_cast*>(this); _run_functor = &detail::functor_run::run; } - char _functor[FunctorSize]; + aligned _functor; }; template class task : virtual public task_base, virtual public promise { public: template - task( Functor&& f ):task_base(&_functor[0]) { + task( Functor&& f ):task_base(&_functor) { static_assert( sizeof(f) <= sizeof(_functor), "sizeof(Functor) is larger than FunctorSize" ); - new ((char*)&_functor[0]) Functor( fc::forward(f) ); + new ((char*)&_functor) Functor( fc::forward(f) ); _destroy_functor = &detail::functor_destructor::destroy; _promise_impl = static_cast*>(this); _run_functor = &detail::void_functor_run::run; } - char _functor[FunctorSize]; + aligned _functor; }; } diff --git a/src/hex.cpp b/src/hex.cpp new file mode 100644 index 0000000..5904cab --- /dev/null +++ b/src/hex.cpp @@ -0,0 +1,42 @@ +#include +#include + +namespace fc { + + uint8_t from_hex( char c ) { + if( c >= '0' && c <= '9' ) + return c - '0'; + if( c >= 'a' && c <= 'f' ) + return c - 'a' + 10; + if( c >= 'A' && c <= 'F' ) + return c - 'A' + 10; + FC_THROW( "Invalid hex character '%c'", c ); + return 0; + } + + fc::string to_hex( const char* d, uint32_t s ) { + fc::string r; + const char* to_hex="0123456789abcdef"; + uint8_t* c = (uint8_t*)d; + for( uint32_t i = 0; i < s; ++i ) + (r += to_hex[(c[i]>>4)]) += to_hex[(c[i] &0x0f)]; + return r; + } + + size_t from_hex( const fc::string& hex_str, char* out_data, size_t out_data_len ) { + fc::string::const_iterator i = hex_str.begin(); + uint8_t* out_pos = (uint8_t*)out_data; + uint8_t* out_end = out_pos + out_data_len; + while( i != hex_str.end() && out_end != out_pos ) { + *out_pos = from_hex( *i ) << 4; + ++i; + if( i != hex_str.end() ) { + *out_pos |= from_hex( *i ); + ++i; + } + ++out_pos; + } + return out_pos - (uint8_t*)out_data; + } + +} diff --git a/src/sha1.cpp b/src/sha1.cpp new file mode 100644 index 0000000..5ebf594 --- /dev/null +++ b/src/sha1.cpp @@ -0,0 +1,64 @@ +#include +#include +#include +#include +#include + +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::string sha1::str()const { + return to_hex( (char*)_hash, sizeof(_hash) ); + } + sha1::operator fc::string()const { return str(); } + + sha1 operator << ( const sha1& h1, uint32_t i ) { + sha1 result; + uint8_t* r = (uint8_t*)result._hash; + uint8_t* s = (uint8_t*)h1._hash; + for( uint32_t p = 0; p < sizeof(h1._hash)-1; ++p ) + r[p] = s[p] << i | (s[p+1]>>(8-i)); + r[19] = s[19] << i; + return result; + } + sha1 operator ^ ( const sha1& h1, const sha1 h2 ) { + sha1 result; + result._hash[0] = h1._hash[0] ^ h2._hash[0]; + result._hash[1] = h1._hash[1] ^ h2._hash[1]; + result._hash[2] = h1._hash[2] ^ h2._hash[2]; + result._hash[3] = h1._hash[3] ^ h2._hash[3]; + result._hash[4] = h1._hash[4] ^ h2._hash[4]; + return result; + } + bool operator >= ( const sha1& h1, const sha1 h2 ) { + return memcmp( h1._hash, h2._hash, sizeof(h1._hash) ) >= 0; + } + bool operator > ( const sha1& h1, const sha1 h2 ) { + return memcmp( h1._hash, h2._hash, sizeof(h1._hash) ) > 0; + } + + struct sha1::encoder::impl { + SHA_CTX ctx; + }; + + sha1::encoder::encoder() { + reset(); + } + + void sha1::encoder::write( const char* d, uint32_t dlen ) { + SHA1_Update( &my->ctx, d, dlen); + } + sha1 sha1::encoder::result() { + sha1 h; + SHA1_Final((uint8_t*)h.data(), &my->ctx ); + return h; + } + void sha1::encoder::reset() { + SHA1_Init( &my->ctx); + } + +}