From 669cf151e5311b5134181427c7e1b2f3904793ec Mon Sep 17 00:00:00 2001 From: theoreticalbts Date: Tue, 22 May 2018 11:57:39 -0400 Subject: [PATCH 1/5] chainbase.hpp: Implement count() function --- libraries/chainbase/include/chainbase/chainbase.hpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/libraries/chainbase/include/chainbase/chainbase.hpp b/libraries/chainbase/include/chainbase/chainbase.hpp index 0ecea742d7..08c899ccd4 100644 --- a/libraries/chainbase/include/chainbase/chainbase.hpp +++ b/libraries/chainbase/include/chainbase/chainbase.hpp @@ -967,6 +967,13 @@ namespace chainbase { return get_mutable_index().emplace( std::forward(con) ); } + template< typename ObjectType > + size_t count()const + { + typedef typename get_index_type::type index_type; + return get_index< index_type >().indices().size(); + } + template< typename Lambda > auto with_read_lock( Lambda&& callback, uint64_t wait_micro = 1000000 ) -> decltype( (*(Lambda*)nullptr)() ) { From ffde5d5dd53e5f34acff6931a4234f5c6ed10cd9 Mon Sep 17 00:00:00 2001 From: theoreticalbts Date: Fri, 25 May 2018 12:48:11 -0400 Subject: [PATCH 2/5] Move by_name to steem_object_types.hpp --- libraries/chain/include/steem/chain/account_object.hpp | 1 - libraries/chain/include/steem/chain/steem_object_types.hpp | 1 + libraries/chain/include/steem/chain/steem_objects.hpp | 1 - libraries/chain/include/steem/chain/witness_objects.hpp | 1 - 4 files changed, 1 insertion(+), 3 deletions(-) diff --git a/libraries/chain/include/steem/chain/account_object.hpp b/libraries/chain/include/steem/chain/account_object.hpp index 0f72e77581..2a2ccfd96e 100644 --- a/libraries/chain/include/steem/chain/account_object.hpp +++ b/libraries/chain/include/steem/chain/account_object.hpp @@ -232,7 +232,6 @@ namespace steem { namespace chain { time_point_sec effective_on; }; - struct by_name; struct by_proxy; struct by_next_vesting_withdrawal; diff --git a/libraries/chain/include/steem/chain/steem_object_types.hpp b/libraries/chain/include/steem/chain/steem_object_types.hpp index e77301cede..295adb5e28 100644 --- a/libraries/chain/include/steem/chain/steem_object_types.hpp +++ b/libraries/chain/include/steem/chain/steem_object_types.hpp @@ -33,6 +33,7 @@ inline std::string to_string( const shared_string& str ) { return std::string( s inline void from_string( shared_string& out, const string& in ){ out.assign( in.begin(), in.end() ); } struct by_id; +struct by_name; enum object_type { diff --git a/libraries/chain/include/steem/chain/steem_objects.hpp b/libraries/chain/include/steem/chain/steem_objects.hpp index d2f28ff432..03c9819e52 100755 --- a/libraries/chain/include/steem/chain/steem_objects.hpp +++ b/libraries/chain/include/steem/chain/steem_objects.hpp @@ -449,7 +449,6 @@ namespace steem { namespace chain { allocator< decline_voting_rights_request_object > > decline_voting_rights_request_index; - struct by_name; typedef multi_index_container< reward_fund_object, indexed_by< diff --git a/libraries/chain/include/steem/chain/witness_objects.hpp b/libraries/chain/include/steem/chain/witness_objects.hpp index 62bfe73dd2..3bbe7dd763 100644 --- a/libraries/chain/include/steem/chain/witness_objects.hpp +++ b/libraries/chain/include/steem/chain/witness_objects.hpp @@ -193,7 +193,6 @@ namespace steem { namespace chain { struct by_vote_name; - struct by_name; struct by_pow; struct by_work; struct by_schedule_time; From 6f2d827111b01eb998e3c0f0696c1bec30cdea79 Mon Sep 17 00:00:00 2001 From: theoreticalbts Date: Sun, 27 May 2018 16:00:09 -0400 Subject: [PATCH 3/5] Implement fc::int_array --- libraries/fc/include/fc/int_array.hpp | 80 ++++++++++++++++++++++++++ libraries/fc/include/fc/io/raw.hpp | 30 +++++++--- libraries/fc/include/fc/io/raw_fwd.hpp | 4 ++ 3 files changed, 106 insertions(+), 8 deletions(-) create mode 100644 libraries/fc/include/fc/int_array.hpp diff --git a/libraries/fc/include/fc/int_array.hpp b/libraries/fc/include/fc/int_array.hpp new file mode 100644 index 0000000000..4273a6052f --- /dev/null +++ b/libraries/fc/include/fc/int_array.hpp @@ -0,0 +1,80 @@ +#pragma once + +#include + +#include +#include + +namespace fc { + +/** + * Like fc::array, but does zero-initialization and has friendly JSON format + */ + +template +class int_array +{ + public: + int_array(){ memset( data, 0, sizeof(data) ); } + + T& at( size_t pos ) { FC_ASSERT( pos < N); return data[pos]; } + const T& at( size_t pos )const { FC_ASSERT( pos < N); return data[pos]; } + + T& operator[]( size_t pos ) { FC_ASSERT( pos < N); return data[pos]; } + const T& operator[]( size_t pos )const { FC_ASSERT( pos < N); return data[pos]; } + + const T* begin()const { return &data[0]; } + const T* end()const { return &data[N]; } + + T* begin() { return &data[0]; } + T* end() { return &data[N]; } + + size_t size()const { return N; } + + T data[N]; +}; + +template struct get_typename< fc::int_array > +{ + static const char* name() + { + static std::string _name = std::string("fc::int_array<")+std::string(fc::get_typename::name())+","+ fc::to_string(N) + ">"; + return _name.c_str(); + } +}; + +template +void from_variant( const variant& var, fc::int_array& a ) +{ + const variants& vars = var.get_array(); + memset( a.data, 0, sizeof(a.data) ); + variants& varray = var.get_array(); // throws if is not array + FC_ASSERT( varray.size() == N ); + + for( size_t i=0; i::is_signed ) + { + int64_t temp = varray[i].as_int64(); + FC_ASSERT( (temp >= std::numeric_limits::min()) && (temp <= std::numeric_limits::max()) ); + a[i] = temp; + } + else + { + uint64_t temp = varray[i].as_uint64(); + FC_ASSERT( temp <= std::numeric_limits::max() ); + a[i] = temp; + } + } +} + +template +void to_variant( const fc::int_array& a, variant& v ) +{ + std::vector vars(N); + for( size_t i=0; i #include #include +#include #include #include #include @@ -120,22 +121,35 @@ namespace fc { } FC_RETHROW_EXCEPTIONS( warn, "" ) } template - inline void pack( Stream& s, const fc::array& v) { - s.write((const char*)&v.data[0],N*sizeof(T)); - } - - template - inline void pack( Stream& s, const std::shared_ptr& v) + inline void pack( Stream& s, const fc::array& v) { - fc::raw::pack( s, *v ); + s.write((const char*)&v.data[0],N*sizeof(T)); } template inline void unpack( Stream& s, fc::array& v) { try { - s.read((char*)&v.data[0],N*sizeof(T)); + s.read( (char*)&v.data[0], N*sizeof(T) ); } FC_RETHROW_EXCEPTIONS( warn, "fc::array", ("type",fc::get_typename::name())("length",N) ) } + template + inline void pack( Stream& s, const fc::int_array& v) + { + s.write( (const char*)&v.data[0], N*sizeof(T) ); + } + + template + inline void unpack( Stream& s, fc::int_array& v) + { try { + s.read( (char*)&v.data[0], N*sizeof(T) ); + } FC_RETHROW_EXCEPTIONS( warn, "fc::int_array", ("type",fc::get_typename::name())("length",N) ) } + + template + inline void pack( Stream& s, const std::shared_ptr& v) + { + fc::raw::pack( s, *v ); + } + template inline void unpack( Stream& s, std::shared_ptr& v) { try { diff --git a/libraries/fc/include/fc/io/raw_fwd.hpp b/libraries/fc/include/fc/io/raw_fwd.hpp index d25c20c182..154d9ba79f 100644 --- a/libraries/fc/include/fc/io/raw_fwd.hpp +++ b/libraries/fc/include/fc/io/raw_fwd.hpp @@ -20,6 +20,7 @@ namespace fc { class variant_object; class path; template class static_variant; + template class int_array; template class enum_type; namespace ip { class endpoint; } @@ -116,6 +117,9 @@ namespace fc { template inline void pack( Stream& s, const fc::array& v); template inline void unpack( Stream& s, fc::array& v); + template inline void pack( Stream& s, const fc::int_array& v); + template inline void unpack( Stream& s, fc::int_array& v); + template inline void pack( Stream& s, const bool& v ); template inline void unpack( Stream& s, bool& v ); From a49f76123238d5406eb7dd549366cbbe9a9ed7db Mon Sep 17 00:00:00 2001 From: theoreticalbts Date: Fri, 15 Jun 2018 15:34:01 -0400 Subject: [PATCH 4/5] Implement fc methods for signed saturation addition/subtraction --- libraries/fc/include/fc/saturation.hpp | 91 ++++++++++++++++++++++++++ libraries/fc/tests/CMakeLists.txt | 4 ++ libraries/fc/tests/saturation_test.cpp | 79 ++++++++++++++++++++++ 3 files changed, 174 insertions(+) create mode 100644 libraries/fc/include/fc/saturation.hpp create mode 100644 libraries/fc/tests/saturation_test.cpp diff --git a/libraries/fc/include/fc/saturation.hpp b/libraries/fc/include/fc/saturation.hpp new file mode 100644 index 0000000000..b0f05e26e5 --- /dev/null +++ b/libraries/fc/include/fc/saturation.hpp @@ -0,0 +1,91 @@ +#pragma once + +#include +#include + +namespace fc { + +// Based loosely on http://locklessinc.com/articles/sat_arithmetic/ + +template< typename IntType > +struct corresponding_unsigned; + +template<> +struct corresponding_unsigned< int8_t > +{ + typedef uint8_t type; +}; + +template<> +struct corresponding_unsigned< int16_t > +{ + typedef uint16_t type; +}; + +template<> +struct corresponding_unsigned< int32_t > +{ + typedef uint32_t type; +}; + +template<> +struct corresponding_unsigned< int64_t > +{ + typedef uint64_t type; +}; + +template< typename Signed > +Signed signed_sat_add( Signed x, Signed y ) +{ + typedef typename corresponding_unsigned< Signed >::type u; + u ux(x), uy(y); + u res(ux+uy); + + // Compute saturated result sat, which is 0x7F... if x>=0, 0x80... otherwise + u sat = (x >= 0) ? u( std::numeric_limits< Signed >::max() ) + : u( std::numeric_limits< Signed >::min() ); + + // If overflow occurs, the correct result is sat + // If no overflow occurs, the correct result is res + // + // Overflow occurred if and only if the following two conditions occur: + // (a) ux,uy are the same sign s + // (b) res has a different sign than s + // + // But we know: + // (a) iff ~(ux^uy) has sign bit=1 + // (b) iff (ux^res) has sign bit=1 + // + // Therefore the sign bit of ~(ux^uy) & (uy ^ res) is 1 iff overflow occurred + // + return (Signed(~(ux^uy) & (ux^res)) < 0) ? sat : res; +} + +template< typename Signed > +Signed signed_sat_sub( Signed x, Signed y ) +{ + typedef typename corresponding_unsigned< Signed >::type u; + u ux(x), uy(y); + u res(ux-uy); + + // Compute saturated result sat, which is 0x7F... if x>=0, 0x80... otherwise + u sat = (x >= 0) ? u( std::numeric_limits< Signed >::max() ) + : u( std::numeric_limits< Signed >::min() ); + + // If overflow occurs, the correct result is sat + // If no overflow occurs, the correct result is res + // + // Overflow occurred if and only if the following two conditions occur: + // (a) ux,uy are different signs + // (b) res has a different sign than ux + // + // But we know: + // (a) iff (ux^uy) has sign bit=1 + // (b) iff (ux^res) has sign bit=1 + // + // Therefore the sign bit of ~(ux^uy) & (uy ^ res) is 1 iff overflow occurred + // + return (Signed((ux^uy) & (ux^res)) < 0) ? sat : res; +} + +} diff --git a/libraries/fc/tests/CMakeLists.txt b/libraries/fc/tests/CMakeLists.txt index e1747d1d47..20b7f7592a 100644 --- a/libraries/fc/tests/CMakeLists.txt +++ b/libraries/fc/tests/CMakeLists.txt @@ -37,6 +37,9 @@ target_link_libraries( ecc_test fc ) add_executable( log_test crypto/log_test.cpp ) target_link_libraries( log_test fc ) +add_executable( saturation_test saturation_test.cpp ) +target_link_libraries( saturation_test fc ) + #add_executable( test_aes aes_test.cpp ) #target_link_libraries( test_aes fc ${rt_library} ${pthread_library} ) #add_executable( test_sleep sleep.cpp ) @@ -63,6 +66,7 @@ add_executable( all_tests all_tests.cpp thread/thread_tests.cpp bloom_test.cpp real128_test.cpp + saturation_test.cpp utf8_test.cpp ) target_link_libraries( all_tests fc ) diff --git a/libraries/fc/tests/saturation_test.cpp b/libraries/fc/tests/saturation_test.cpp new file mode 100644 index 0000000000..ad9afd3800 --- /dev/null +++ b/libraries/fc/tests/saturation_test.cpp @@ -0,0 +1,79 @@ + +#include + +#include +#include +#include + +template< typename Signed, typename BiggerSigned > +int test_all() +{ + const Signed a = std::numeric_limits< Signed >::min(); + const Signed b = std::numeric_limits< Signed >::max(); + + Signed x = a; + while( true ) + { + Signed y = a; + while( true ) + { + BiggerSigned z0big = BiggerSigned(x) + BiggerSigned(y); + if( z0big < a ) + z0big = a; + if( z0big > b ) + z0big = b; + Signed z0 = Signed(z0big); + Signed z1 = fc::signed_sat_add( x, y ); + + if( z0 != z1 ) + { + std::cout << "Addition does not work for " << x << ", " << y << std::endl; + return 1; + } + + z0big = BiggerSigned(x) - BiggerSigned(y); + if( z0big < a ) + z0big = a; + if( z0big > b ) + z0big = b; + z0 = Signed(z0big); + z1 = fc::signed_sat_sub( x, y ); + + if( z0 != z1 ) + { + std::cout << "Subtraction does not work for " << x << ", " << y << std::endl; + return 1; + } + + if( y == b ) + break; + ++y; + } + if( x == b ) + break; + ++x; + } + return 0; +} + +int64_t sat_add_i64( int64_t a, int64_t b ) +{ + return fc::signed_sat_add( a, b ); +} + +int64_t sat_sub_i64( int64_t a, int64_t b ) +{ + return fc::signed_sat_sub( a, b ); +} + +int main( int argc, char** argv, char** envp ) +{ + int result = test_all< int8_t, int16_t >(); + if( result ) + return 1; + result = test_all< int16_t, int32_t >(); + if( result ) + return 1; + + return 0; +} From 1a035ff65a6f189fdc4225811b2b1fb4485bd1c3 Mon Sep 17 00:00:00 2001 From: theoreticalbts Date: Fri, 15 Jun 2018 17:48:06 -0400 Subject: [PATCH 5/5] Fix int_array use of const, fixes clang compile --- libraries/fc/include/fc/int_array.hpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libraries/fc/include/fc/int_array.hpp b/libraries/fc/include/fc/int_array.hpp index 4273a6052f..2c848989af 100644 --- a/libraries/fc/include/fc/int_array.hpp +++ b/libraries/fc/include/fc/int_array.hpp @@ -46,9 +46,8 @@ template struct get_typename< fc::int_array > template void from_variant( const variant& var, fc::int_array& a ) { - const variants& vars = var.get_array(); memset( a.data, 0, sizeof(a.data) ); - variants& varray = var.get_array(); // throws if is not array + const variants& varray = var.get_array(); // throws if is not array FC_ASSERT( varray.size() == N ); for( size_t i=0; i