diff --git a/include/fc/container/flat.hpp b/include/fc/container/flat.hpp index 2eca459..5e6a363 100644 --- a/include/fc/container/flat.hpp +++ b/include/fc/container/flat.hpp @@ -11,7 +11,7 @@ namespace fc { inline void pack( Stream& s, const flat_set& value, uint32_t _max_depth ) { FC_ASSERT( _max_depth > 0 ); --_max_depth; - pack( s, unsigned_int((uint32_t)value.size()), _max_depth ); + pack( s, unsigned_int(value.size()), _max_depth ); auto itr = value.begin(); auto end = value.end(); while( itr != end ) { @@ -38,7 +38,7 @@ namespace fc { inline void pack( Stream& s, const flat_map& value, uint32_t _max_depth ) { FC_ASSERT( _max_depth > 0 ); --_max_depth; - pack( s, unsigned_int((uint32_t)value.size()), _max_depth ); + pack( s, unsigned_int(value.size()), _max_depth ); auto itr = value.begin(); auto end = value.end(); while( itr != end ) { @@ -67,7 +67,7 @@ namespace fc { void pack( Stream& s, const bip::vector& value, uint32_t _max_depth ) { FC_ASSERT( _max_depth > 0 ); --_max_depth; - pack( s, unsigned_int((uint32_t)value.size()), _max_depth ); + pack( s, unsigned_int(value.size()), _max_depth ); if( !std::is_fundamental::value ) { auto itr = value.begin(); auto end = value.end(); diff --git a/include/fc/interprocess/container.hpp b/include/fc/interprocess/container.hpp index 7ede74b..a00346e 100644 --- a/include/fc/interprocess/container.hpp +++ b/include/fc/interprocess/container.hpp @@ -113,7 +113,7 @@ namespace fc { inline void pack( Stream& s, const bip::vector& value, uint32_t _max_depth=FC_PACK_MAX_DEPTH ) { FC_ASSERT( _max_depth > 0 ); --_max_depth; - pack( s, unsigned_int((uint32_t)value.size()), _max_depth ); + pack( s, unsigned_int(value.size()), _max_depth ); auto itr = value.begin(); auto end = value.end(); while( itr != end ) { diff --git a/include/fc/io/raw.hpp b/include/fc/io/raw.hpp index 9ef61ec..c12abb1 100644 --- a/include/fc/io/raw.hpp +++ b/include/fc/io/raw.hpp @@ -158,16 +158,6 @@ namespace fc { fc::raw::unpack( s, *v, _max_depth - 1 ); } FC_RETHROW_EXCEPTIONS( warn, "std::shared_ptr", ("type",fc::get_typename::name()) ) } - template inline void pack( Stream& s, const signed_int& v, uint32_t _max_depth ) { - uint32_t val = (v.value<<1) ^ (v.value>>31); - do { - uint8_t b = uint8_t(val) & 0x7f; - val >>= 7; - b |= ((val > 0) << 7); - s.write((char*)&b,1);//.put(b); - } while( val ); - } - template inline void pack( Stream& s, const unsigned_int& v, uint32_t _max_depth ) { uint64_t val = v.value; do { @@ -178,25 +168,16 @@ namespace fc { }while( val ); } - template inline void unpack( Stream& s, signed_int& vi, uint32_t _max_depth ) { - uint32_t v = 0; char b = 0; int by = 0; - do { - s.get(b); - v |= uint32_t(uint8_t(b) & 0x7f) << by; - by += 7; - } while( uint8_t(b) & 0x80 ); - vi.value = ((v>>1) ^ (v>>31)) + (v&0x01); - vi.value = v&0x01 ? vi.value : -vi.value; - vi.value = -vi.value; - } template inline void unpack( Stream& s, unsigned_int& vi, uint32_t _max_depth ) { uint64_t v = 0; char b = 0; uint8_t by = 0; do { s.get(b); - v |= uint32_t(uint8_t(b) & 0x7f) << by; + if( by >= 64 || (by == 63 && uint8_t(b) > 1) ) + FC_THROW_EXCEPTION( overflow_exception, "Invalid packed unsigned_int!" ); + v |= uint64_t(uint8_t(b) & 0x7f) << by; by += 7; } while( uint8_t(b) & 0x80 ); - vi.value = static_cast(v); + vi.value = static_cast(v); } template inline void unpack( Stream& s, const T& vi, uint32_t _max_depth ) @@ -273,9 +254,9 @@ namespace fc { // std::vector template inline void pack( Stream& s, const std::vector& value, uint32_t _max_depth ) { FC_ASSERT( _max_depth > 0 ); - fc::raw::pack( s, unsigned_int((uint32_t)value.size()), _max_depth - 1 ); + fc::raw::pack( s, unsigned_int(value.size()), _max_depth - 1 ); if( value.size() ) - s.write( &value.front(), (uint32_t)value.size() ); + s.write( &value.front(), value.size() ); } template inline void unpack( Stream& s, std::vector& value, uint32_t _max_depth ) { FC_ASSERT( _max_depth > 0 ); @@ -289,7 +270,7 @@ namespace fc { // fc::string template inline void pack( Stream& s, const fc::string& v, uint32_t _max_depth ) { FC_ASSERT( _max_depth > 0 ); - fc::raw::pack( s, unsigned_int((uint32_t)v.size()), _max_depth - 1 ); + fc::raw::pack( s, unsigned_int(v.size()), _max_depth - 1 ); if( v.size() ) s.write( v.c_str(), v.size() ); } @@ -433,7 +414,7 @@ namespace fc { inline void pack( Stream& s, const std::unordered_set& value, uint32_t _max_depth ) { FC_ASSERT( _max_depth > 0 ); --_max_depth; - fc::raw::pack( s, unsigned_int((uint32_t)value.size()), _max_depth ); + fc::raw::pack( s, unsigned_int(value.size()), _max_depth ); auto itr = value.begin(); auto end = value.end(); while( itr != end ) { @@ -478,7 +459,7 @@ namespace fc { inline void pack( Stream& s, const std::unordered_map& value, uint32_t _max_depth ) { FC_ASSERT( _max_depth > 0 ); --_max_depth; - fc::raw::pack( s, unsigned_int((uint32_t)value.size()), _max_depth ); + fc::raw::pack( s, unsigned_int(value.size()), _max_depth ); auto itr = value.begin(); auto end = value.end(); while( itr != end ) { @@ -506,7 +487,7 @@ namespace fc { inline void pack( Stream& s, const std::map& value, uint32_t _max_depth ) { FC_ASSERT( _max_depth > 0 ); --_max_depth; - fc::raw::pack( s, unsigned_int((uint32_t)value.size()), _max_depth ); + fc::raw::pack( s, unsigned_int(value.size()), _max_depth ); auto itr = value.begin(); auto end = value.end(); while( itr != end ) { @@ -534,7 +515,7 @@ namespace fc { inline void pack( Stream& s, const std::deque& value, uint32_t _max_depth ) { FC_ASSERT( _max_depth > 0 ); --_max_depth; - fc::raw::pack( s, unsigned_int((uint32_t)value.size()), _max_depth ); + fc::raw::pack( s, unsigned_int(value.size()), _max_depth ); auto itr = value.begin(); auto end = value.end(); while( itr != end ) { @@ -562,7 +543,7 @@ namespace fc { inline void pack( Stream& s, const std::vector& value, uint32_t _max_depth ) { FC_ASSERT( _max_depth > 0 ); --_max_depth; - fc::raw::pack( s, unsigned_int((uint32_t)value.size()), _max_depth ); + fc::raw::pack( s, unsigned_int(value.size()), _max_depth ); auto itr = value.begin(); auto end = value.end(); while( itr != end ) { @@ -590,7 +571,7 @@ namespace fc { inline void pack( Stream& s, const std::set& value, uint32_t _max_depth ) { FC_ASSERT( _max_depth > 0 ); --_max_depth; - fc::raw::pack( s, unsigned_int((uint32_t)value.size()), _max_depth ); + fc::raw::pack( s, unsigned_int(value.size()), _max_depth ); auto itr = value.begin(); auto end = value.end(); while( itr != end ) { diff --git a/include/fc/io/raw_fwd.hpp b/include/fc/io/raw_fwd.hpp index 157a745..87a9208 100644 --- a/include/fc/io/raw_fwd.hpp +++ b/include/fc/io/raw_fwd.hpp @@ -116,9 +116,6 @@ namespace fc { template inline void pack( Stream& s, const std::vector& v, uint32_t _max_depth=FC_PACK_MAX_DEPTH ); template inline void unpack( Stream& s, std::vector& v, uint32_t _max_depth=FC_PACK_MAX_DEPTH ); - template inline void pack( Stream& s, const signed_int& v, uint32_t _max_depth=FC_PACK_MAX_DEPTH ); - template inline void unpack( Stream& s, signed_int& vi, uint32_t _max_depth=FC_PACK_MAX_DEPTH ); - template inline void pack( Stream& s, const unsigned_int& v, uint32_t _max_depth=FC_PACK_MAX_DEPTH ); template inline void unpack( Stream& s, unsigned_int& vi, uint32_t _max_depth=FC_PACK_MAX_DEPTH ); diff --git a/include/fc/io/raw_variant.hpp b/include/fc/io/raw_variant.hpp index b07fbaa..59b93d9 100644 --- a/include/fc/io/raw_variant.hpp +++ b/include/fc/io/raw_variant.hpp @@ -128,7 +128,7 @@ namespace fc { namespace raw { { FC_ASSERT( _max_depth > 0 ); --_max_depth; - unsigned_int vs = (uint32_t)v.size(); + unsigned_int vs = v.size(); pack( s, vs, _max_depth ); for( auto itr = v.begin(); itr != v.end(); ++itr ) { diff --git a/include/fc/io/varint.hpp b/include/fc/io/varint.hpp index 00a8023..30e42bb 100644 --- a/include/fc/io/varint.hpp +++ b/include/fc/io/varint.hpp @@ -4,74 +4,37 @@ namespace fc { struct unsigned_int { - unsigned_int( uint32_t v = 0 ):value(v){} + unsigned_int( uint64_t v = 0 ):value(v){} template unsigned_int( T v ):value(v){} - //operator uint32_t()const { return value; } - //operator uint64_t()const { return value; } - template operator T()const { return static_cast(value); } - unsigned_int& operator=( int32_t v ) { value = v; return *this; } + unsigned_int& operator=( uint64_t v ) { value = v; return *this; } - uint32_t value; + uint64_t value; - friend bool operator==( const unsigned_int& i, const uint32_t& v ) { return i.value == v; } - friend bool operator==( const uint32_t& i, const unsigned_int& v ) { return i == v.value; } + friend bool operator==( const unsigned_int& i, const uint64_t& v ) { return i.value == v; } + friend bool operator==( const uint64_t& i, const unsigned_int& v ) { return i == v.value; } friend bool operator==( const unsigned_int& i, const unsigned_int& v ) { return i.value == v.value; } - friend bool operator!=( const unsigned_int& i, const uint32_t& v ) { return i.value != v; } - friend bool operator!=( const uint32_t& i, const unsigned_int& v ) { return i != v.value; } + friend bool operator!=( const unsigned_int& i, const uint64_t& v ) { return i.value != v; } + friend bool operator!=( const uint64_t& i, const unsigned_int& v ) { return i != v.value; } friend bool operator!=( const unsigned_int& i, const unsigned_int& v ) { return i.value != v.value; } - friend bool operator<( const unsigned_int& i, const uint32_t& v ) { return i.value < v; } - friend bool operator<( const uint32_t& i, const unsigned_int& v ) { return i < v.value; } + friend bool operator<( const unsigned_int& i, const uint64_t& v ) { return i.value < v; } + friend bool operator<( const uint64_t& i, const unsigned_int& v ) { return i < v.value; } friend bool operator<( const unsigned_int& i, const unsigned_int& v ) { return i.value < v.value; } - friend bool operator>=( const unsigned_int& i, const uint32_t& v ) { return i.value >= v; } - friend bool operator>=( const uint32_t& i, const unsigned_int& v ) { return i >= v.value; } + friend bool operator>=( const unsigned_int& i, const uint64_t& v ) { return i.value >= v; } + friend bool operator>=( const uint64_t& i, const unsigned_int& v ) { return i >= v.value; } friend bool operator>=( const unsigned_int& i, const unsigned_int& v ) { return i.value >= v.value; } }; -/** - * @brief serializes a 32 bit signed interger in as few bytes as possible - * - * Uses the google protobuf algorithm for seralizing signed numbers - */ -struct signed_int { - signed_int( int32_t v = 0 ):value(v){} - operator int32_t()const { return value; } - template - signed_int& operator=( const T& v ) { value = v; return *this; } - signed_int operator++(int) { return value++; } - signed_int& operator++(){ ++value; return *this; } - - int32_t value; - - friend bool operator==( const signed_int& i, const int32_t& v ) { return i.value == v; } - friend bool operator==( const int32_t& i, const signed_int& v ) { return i == v.value; } - friend bool operator==( const signed_int& i, const signed_int& v ) { return i.value == v.value; } - - friend bool operator!=( const signed_int& i, const int32_t& v ) { return i.value != v; } - friend bool operator!=( const int32_t& i, const signed_int& v ) { return i != v.value; } - friend bool operator!=( const signed_int& i, const signed_int& v ) { return i.value != v.value; } - - friend bool operator<( const signed_int& i, const int32_t& v ) { return i.value < v; } - friend bool operator<( const int32_t& i, const signed_int& v ) { return i < v.value; } - friend bool operator<( const signed_int& i, const signed_int& v ) { return i.value < v.value; } - - friend bool operator>=( const signed_int& i, const int32_t& v ) { return i.value >= v; } - friend bool operator>=( const int32_t& i, const signed_int& v ) { return i >= v.value; } - friend bool operator>=( const signed_int& i, const signed_int& v ) { return i.value >= v.value; } -}; - class variant; -void to_variant( const signed_int& var, variant& vo, uint32_t max_depth = 1 ); -void from_variant( const variant& var, signed_int& vo, uint32_t max_depth = 1 ); void to_variant( const unsigned_int& var, variant& vo, uint32_t max_depth = 1 ); void from_variant( const variant& var, unsigned_int& vo, uint32_t max_depth = 1 ); @@ -80,22 +43,13 @@ void from_variant( const variant& var, unsigned_int& vo, uint32_t max_depth = 1 #include namespace std { - template<> - struct hash - { - public: - size_t operator()(const fc::signed_int &a) const - { - return std::hash()(a.value); - } - }; template<> struct hash { public: - size_t operator()(const fc::signed_int &a) const + size_t operator()(const fc::unsigned_int &a) const { - return std::hash()(a.value); + return std::hash()(a.value); } }; } diff --git a/include/fc/reflect/typename.hpp b/include/fc/reflect/typename.hpp index 55695c2..7223d83 100644 --- a/include/fc/reflect/typename.hpp +++ b/include/fc/reflect/typename.hpp @@ -96,10 +96,8 @@ namespace fc { } }; - struct signed_int; struct unsigned_int; struct variant_object; - template<> struct get_typename { static const char* name() { return "signed_int"; } }; template<> struct get_typename { static const char* name() { return "unsigned_int"; } }; template<> struct get_typename { static const char* name() { return "fc::variant_object"; } }; diff --git a/src/io/varint.cpp b/src/io/varint.cpp index 6d5df6c..a5c6bbb 100644 --- a/src/io/varint.cpp +++ b/src/io/varint.cpp @@ -3,8 +3,6 @@ namespace fc { -void to_variant( const signed_int& var, variant& vo, uint32_t max_depth ) { vo = var.value; } -void from_variant( const variant& var, signed_int& vo, uint32_t max_depth ) { vo.value = static_cast(var.as_int64()); } void to_variant( const unsigned_int& var, variant& vo, uint32_t max_depth ) { vo = var.value; } -void from_variant( const variant& var, unsigned_int& vo, uint32_t max_depth ) { vo.value = static_cast(var.as_uint64()); } +void from_variant( const variant& var, unsigned_int& vo, uint32_t max_depth ) { vo.value = var.as_uint64(); } } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 153067e..600f6f8 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -49,6 +49,7 @@ add_executable( all_tests all_tests.cpp io/json_tests.cpp io/stream_tests.cpp io/tcp_test.cpp + io/varint_tests.cpp network/http/websocket_test.cpp thread/task_cancel.cpp thread/thread_tests.cpp diff --git a/tests/io/varint_tests.cpp b/tests/io/varint_tests.cpp new file mode 100644 index 0000000..f1f1536 --- /dev/null +++ b/tests/io/varint_tests.cpp @@ -0,0 +1,98 @@ +#include + +#include +#include +#include + +BOOST_AUTO_TEST_SUITE(varint_tests) + +#define UINT_LENGTH (1 + 5*1 + 3*2 + 3*3 + 3*4 + 2*5 + 3*6 + 3*7 + 3*8 + 3*9 + 2*10) +static const std::string EXPECTED_UINTS( "\036" // 30 = length of array + "\0\1\2\020\177" + "\200\1\200\2\377\177" + "\200\200\1\200\200\2\377\377\177" + "\200\200\200\1\200\200\200\2\377\377\377\177" + "\200\200\200\200\1" + "\252\325\252\325\012" + "\200\200\200\200\200\1" + "\200\200\200\200\200\2" + "\377\377\377\377\377\177" + "\200\200\200\200\200\200\1" + "\200\200\200\200\200\200\2" + "\377\377\377\377\377\377\177" + "\200\200\200\200\200\200\200\1" + "\200\200\200\200\200\200\200\2" + "\377\377\377\377\377\377\377\177" + "\200\200\200\200\200\200\200\200\1" + "\200\200\200\200\200\200\200\200\2" + "\377\377\377\377\377\377\377\377\177" + "\200\200\200\200\200\200\200\200\200\1" + "\377\377\377\377\377\377\377\377\377\1", + UINT_LENGTH ); +static const std::vector TEST_U = { + 0, // \0 + 1, // \1 + 2, // \2 + 0x10, // \020 + 0x7f, // \177 + 0x80, // \200\1 + 0x100, // \200\2 + 0x3fff, // \377\177 + 0x4000, // \200\200\1 + 0x8000, // \200\200\2 + 0x1fffff, // \377\377\177 + 0x200000, // \200\200\200\1 + 0x400000, // \200\200\200\2 + 0xfffffff, // \377\377\377\177 + 0x10000000, // \200\200\200\200\1 + 0xaaaaaaaa, // \252\325\252\325\012 + 0x800000000ULL, // \200\200\200\200\200\1 + 0x1000000000ULL, // \200\200\200\200\200\2 + 0x3ffffffffffULL, // \377\377\377\377\377\177 + 0x40000000000ULL, // \200\200\200\200\200\200\1 + 0x80000000000ULL, // \200\200\200\200\200\200\2 + 0x1ffffffffffffULL, // \377\377\377\377\377\377\177 + 0x2000000000000ULL, // \200\200\200\200\200\200\200\1 + 0x4000000000000ULL, // \200\200\200\200\200\200\200\2 + 0xffffffffffffffULL, // \377\377\377\377\377\377\377\177 + 0x100000000000000ULL, // \200\200\200\200\200\200\200\200\1 + 0x200000000000000ULL, // \200\200\200\200\200\200\200\200\2 + 0x7fffffffffffffffULL, // \377\377\377\377\377\377\377\377\177 + 0x8000000000000000ULL, // \200\200\200\200\200\200\200\200\200\1 + 0xffffffffffffffffULL // \377\377\377\377\377\377\377\377\377\1 + }; +BOOST_AUTO_TEST_CASE( test_unsigned ) +{ try { + const std::vector packed_u = fc::raw::pack>( TEST_U, 3 ); + BOOST_CHECK_EQUAL( UINT_LENGTH, packed_u.size() ); + BOOST_CHECK_EQUAL( EXPECTED_UINTS, std::string( packed_u.data(), packed_u.size() ) ); + std::vector unpacked_u; + fc::raw::unpack>( packed_u, unpacked_u, 3 ); + BOOST_CHECK_EQUAL( TEST_U.size(), unpacked_u.size() ); + for( size_t i = 0; i < TEST_U.size(); i++ ) + BOOST_CHECK_EQUAL( TEST_U[i].value, unpacked_u[i].value ); + + const std::string json_u = fc::json::to_string(fc::variant( TEST_U, 3 )); + BOOST_CHECK_EQUAL( "[0,1,2,16,127,128,256,16383,16384,32768,2097151,2097152,4194304,268435455,268435456,2863311530," + "\"34359738368\",\"68719476736\",\"4398046511103\",\"4398046511104\"," + "\"8796093022208\",\"562949953421311\",\"562949953421312\"," + "\"1125899906842624\",\"72057594037927935\",\"72057594037927936\"," + "\"144115188075855872\",\"9223372036854775807\",\"9223372036854775808\"," + "\"18446744073709551615\"]", json_u ); + std::vector unjson_u = fc::json::from_string( json_u ).as>( 3 ); + BOOST_CHECK_EQUAL( TEST_U.size(), unjson_u.size() ); + for( size_t i = 0; i < TEST_U.size(); i++ ) + BOOST_CHECK_EQUAL( TEST_U[i].value, unjson_u[i].value ); +} FC_LOG_AND_RETHROW() } + +BOOST_AUTO_TEST_CASE( test_limits ) +{ try { + static const std::string overflow = "\200\200\200\200\200\200\200\200\200\2"; // = 2^64 + static const std::string overlong = "\200\200\200\200\200\200\200\200\300\200\1"; + + fc::unsigned_int dest; + BOOST_CHECK_THROW( fc::raw::unpack( std::vector( overflow.begin(), overflow.end() ), dest, 3 ), fc::overflow_exception ); + BOOST_CHECK_THROW( fc::raw::unpack( std::vector( overlong.begin(), overlong.end() ), dest, 3 ), fc::overflow_exception ); +} FC_LOG_AND_RETHROW() } + +BOOST_AUTO_TEST_SUITE_END()