From 8b43c83ed7e5fc630b04caf8c9355c5bf6a5a9a6 Mon Sep 17 00:00:00 2001 From: Jan Travnicek <Jan.Travnicek@fit.cvut.cz> Date: Mon, 20 Feb 2017 14:17:21 +0100 Subject: [PATCH] bitwise operations on vector bool --- alib2std/src/extensions/vector.hpp | 187 +++++++++++++- alib2std/test-src/extensions/VectorTest.cpp | 269 ++++++++++++++++++++ alib2std/test-src/extensions/VectorTest.h | 10 + 3 files changed, 465 insertions(+), 1 deletion(-) diff --git a/alib2std/src/extensions/vector.hpp b/alib2std/src/extensions/vector.hpp index 5dcfb42832..69164eb3ba 100644 --- a/alib2std/src/extensions/vector.hpp +++ b/alib2std/src/extensions/vector.hpp @@ -47,7 +47,192 @@ string to_string ( const std::vector < T, Ts ... > & value ) { return ss.str(); } +template < class ... Ts > +vector < bool, Ts ... > & operator |= ( vector < bool, Ts ... > & A, const vector < bool, Ts ... > & B ) { + A.resize ( std::max ( A.size ( ), B.size ( ) ) ); + + typename vector < bool, Ts ... >::iterator itA = A.begin ( ); + typename vector < bool, Ts ... >::const_iterator itB = B.begin ( ); + + // c++ implementation-specific + while ( itB < B.end ( ) ) // A is longer or of the same size as B + * ( itA._M_p ++ ) |= * ( itB._M_p ++ ); // word-at-a-time bitwise operation + + // The rest of A above the size of B can be left intact + + return A; +} + +template < class ... Ts > +vector < bool, Ts ... > operator | ( vector < bool, Ts ... > A, const vector < bool, Ts ... > & B ) { + A |= B; + return A; +} + +template < class ... Ts > +vector < bool, Ts ... > & operator &= ( vector < bool, Ts ... > & A, const vector < bool, Ts ... > & B ) { + A.resize ( std::max ( A.size ( ), B.size ( ) ) ); + + typename vector < bool, Ts ... >::iterator itA = A.begin ( ); + typename vector < bool, Ts ... >::const_iterator itB = B.begin ( ); + + // c++ implementation-specific + while ( itB < B.end ( ) ) // A is longer or of the same size as B + * ( itA._M_p ++ ) &= * ( itB._M_p ++ ); // word-at-a-time bitwise operation + + while ( itA < A.end ( ) ) // The rest of A above the size of B shall be zeroed + * ( itA._M_p ++ ) = 0; + + return A; +} + +template < class ... Ts > +vector < bool, Ts ... > operator & ( vector < bool, Ts ... > A, const vector < bool, Ts ... > & B ) { + A &= B; + return A; +} + +template < class ... Ts > +vector < bool, Ts ... > & operator ^= ( vector < bool, Ts ... > & A, const vector < bool, Ts ... > & B ) { + A.resize ( std::max ( A.size ( ), B.size ( ) ) ); + + typename vector < bool, Ts ... >::iterator itA = A.begin ( ); + typename vector < bool, Ts ... >::const_iterator itB = B.begin ( ); + + // c++ implementation-specific + while ( itB < B.end ( ) ) // A is longer or of the same size as B + * ( itA._M_p ++ ) ^= * ( itB._M_p ++ ); // word-at-a-time bitwise operation + + while ( itA < A.end ( ) ) // The rest of A above the size of B shall be flipped + * ( itA._M_p ++ ) = ~ * ( itA._M_p ++ ); + + return A; +} + +template < class ... Ts > +vector < bool, Ts ... > operator ^ ( vector < bool, Ts ... > A, const vector < bool, Ts ... > & B ) { + A ^= B; + return A; +} + +template < class ... Ts > +vector < bool, Ts ... > operator ~ ( vector < bool, Ts ... > A ) { + A.flip ( ); + return A; +} + +// the same type as the vector bool's internal storage type +typedef typename decay < decltype ( * ( declval < vector < bool > > ( ).begin ( )._M_p ) ) >::type vectorBoolInternalType; +// the size of the vector bool's internal storage type +const unsigned vectorBoolInternalTypeInBits = sizeof ( vectorBoolInternalType ) * 8; + +// private helper for mask computation +inline vectorBoolInternalType getMask ( size_t dist ) { + return ( ( vectorBoolInternalType { } + 1 ) << dist ) - 1; +} + +template < class ... Ts > +vector < bool, Ts ... > & operator <<= ( vector < bool, Ts ... > & A, size_t dist ) { + size_t distBlocks = dist / vectorBoolInternalTypeInBits; + size_t distWithin = dist % vectorBoolInternalTypeInBits; + size_t backDist = vectorBoolInternalTypeInBits - distWithin; + + // shift blocks if needed + if ( distBlocks ) { + // simulate behavior of reverse iterator + auto itAReverse = A.end ( ) - 1; + auto itASource = itAReverse; + itASource._M_p -= distBlocks; + + while ( itASource >= A.begin ( ) ) + * ( itAReverse._M_p -- ) = * ( itASource._M_p -- ); + + while ( itAReverse >= A.begin ( ) ) + * ( itAReverse._M_p -- ) = 0; + } + + // shift by the rest dist + { + vectorBoolInternalType bits1 { }; + vectorBoolInternalType bits2 { }; + // reuse bits1 which is zeroed in initialization to create one and the mask + vectorBoolInternalType mask = ~ getMask ( distWithin ); + + // it might be more clear to iterate from the begining. However this is working nicely + auto itA = A.begin ( ); + + while ( itA < A.end ( ) ) { + bits2 = * ( itA._M_p ) & mask; + * ( itA._M_p ) = * ( itA._M_p ) << distWithin | bits1 >> backDist; + bits1 = bits2; + + itA._M_p ++; + } + } + + return A; +} + +template < class ... Ts > +vector < bool, Ts ... > operator << ( vector < bool, Ts ... > A, size_t dist ) { + A <<= dist; + return A; +} + +template < class ... Ts > +vector < bool, Ts ... > & operator >>= ( vector < bool, Ts ... > & A, size_t dist ) { + size_t distBlocks = dist / vectorBoolInternalTypeInBits; + size_t distWithin = dist % vectorBoolInternalTypeInBits; + size_t sizeWithin = A.size ( ) % vectorBoolInternalTypeInBits; + size_t backDist = vectorBoolInternalTypeInBits - distWithin; + + // shift blocks if needed + if ( distBlocks ) { + auto itA = A.begin ( ); + auto itASource = itA; + itASource._M_p += distBlocks; + + while ( itASource < A.end ( ) ) + * ( itA._M_p ++ ) = * ( itASource._M_p ++ ); + + while ( itA < A.end ( ) ) + * ( itA._M_p ++ ) = 0; + } + + // shift by the rest dist + { + vectorBoolInternalType bits1 { }; + vectorBoolInternalType bits2 { }; + // reuse bits1 which is zeroed in initialization to create one and the mask + vectorBoolInternalType mask = getMask ( distWithin ); + + // it might be more clear to iterate from the begining. However this is working nicely + auto itAReverse = A.end ( ) - 1; + + // upper part of the last word in the vector can contain some garbage so it needs to be cleared + vectorBoolInternalType maskTopWord = getMask ( sizeWithin ); + if ( maskTopWord != 0 ) + * ( itAReverse._M_p ) &= maskTopWord; + + // simulate behavior of reverse iterator + while ( itAReverse >= A.begin ( ) ) { + bits2 = * ( itAReverse._M_p ) & mask; + * ( itAReverse._M_p ) = * ( itAReverse._M_p ) >> distWithin | bits1 << backDist; + bits1 = bits2; + + itAReverse._M_p --; + } + } + + return A; +} + +template < class ... Ts > +vector < bool, Ts ... > operator >> ( vector < bool, Ts ... > A, size_t dist ) { + A >>= dist; + return A; +} + } /* namespace std */ #endif /* __VECTOR_HPP_ */ - diff --git a/alib2std/test-src/extensions/VectorTest.cpp b/alib2std/test-src/extensions/VectorTest.cpp index e7420bda41..19a2a51bc7 100644 --- a/alib2std/test-src/extensions/VectorTest.cpp +++ b/alib2std/test-src/extensions/VectorTest.cpp @@ -18,3 +18,272 @@ void VectorTest::testProperties() { CPPUNIT_ASSERT((std::is_same<decltype(constData[0]), const int&>::value)); } + +void VectorTest::testVectorBool() { + std::vector < bool > A; + A.push_back ( true ); + A.push_back ( false ); + A.push_back ( true ); + A.push_back ( false ); + + std::vector < bool > B; + B.push_back ( true ); + B.push_back ( true ); + B.push_back ( false ); + B.push_back ( false ); + + { + std::vector < bool > C = A | B; + std::vector < bool > D = A; + D |= B; + + std::vector < bool > X; + X.push_back ( true ); + X.push_back ( true ); + X.push_back ( true ); + X.push_back ( false ); + + std::cout << X << std::endl; + std::cout << C << std::endl; + + CPPUNIT_ASSERT ( C == X ); + CPPUNIT_ASSERT ( D == X ); + } + + { + std::vector < bool > C = A & B; + std::vector < bool > D = A; + D &= B; + + std::vector < bool > X; + X.push_back ( true ); + X.push_back ( false ); + X.push_back ( false ); + X.push_back ( false ); + + CPPUNIT_ASSERT ( C == X ); + CPPUNIT_ASSERT ( D == X ); + } + + { + std::vector < bool > C = A ^ B; + std::vector < bool > D = A; + D ^= B; + + std::vector < bool > X; + X.push_back ( false ); + X.push_back ( true ); + X.push_back ( true ); + X.push_back ( false ); + + CPPUNIT_ASSERT ( C == X ); + CPPUNIT_ASSERT ( D == X ); + } +} + +void testOffset ( int offset ) { + unsigned long long shadow = 0x2A76B147D6521C87ULL; + std::vector < bool > data; + + for ( unsigned i = 0; i < sizeof ( unsigned long long ) * 8 + offset; ++ i ) { + data.push_back ( true ); + } + + for ( unsigned i = 0; i < sizeof ( unsigned long long ) * 8; ++ i ) { + data.push_back ( ( bool ) ( shadow & ( 1ULL << i ) ) ); + } + + data >>= sizeof ( unsigned long long ) * 6 - 1; + + std::vector < bool > ref; + for ( unsigned i = 0; i < sizeof ( unsigned long long ) * 2 + offset; ++ i ) { + ref.push_back ( true ); + } + + for ( unsigned i = 0; i < sizeof ( unsigned long long ) * 8; ++ i ) { + ref.push_back ( ( bool ) ( shadow & ( 1ULL << i ) ) ); + } + + ref.resize ( 128 + offset ); + + std::cout << "data = " << data << std::endl; + std::cout << "ref = " << ref << std::endl; + + CPPUNIT_ASSERT ( data == ref ); +} + +void VectorTest::testVectorBool2() { + unsigned long long shadow = 0x2A76B147D6521C87ULL; + std::vector < bool > data; + + for ( unsigned i = 0; i < sizeof ( unsigned long long ) * 8; ++ i ) { + data.push_back ( ( bool ) ( shadow & ( 1ULL << i ) ) ); + } + + shadow >>= 10; + data >>= 10; + + std::vector < bool > ref; + for ( unsigned i = 0; i < sizeof ( unsigned long long ) * 8; ++ i ) { + ref.push_back ( ( bool ) ( shadow & ( 1ULL << i ) ) ); + } + + // std::cout << "data = " << data << std::endl; + // std::cout << "ref = " << ref << std::endl; + + CPPUNIT_ASSERT ( data == ref ); + + for ( unsigned long i = - sizeof ( unsigned long long ) / 2 ; i < sizeof ( unsigned long long ) * 8; ++ i ) + testOffset ( i ); +} + +void VectorTest::testVectorBool3() { + unsigned long long shadow = 0x2A76B147D6521C87ULL; + std::vector < bool > data; + + for ( unsigned i = 0; i < sizeof ( unsigned long long ) * 8; ++ i ) { + data.push_back ( ( bool ) ( shadow & ( 1ULL << i ) ) ); + } + for ( unsigned i = 0; i < sizeof ( unsigned long long ) * 8; ++ i ) { + data.push_back ( ( bool ) ( shadow & ( 1ULL << i ) ) ); + } + for ( unsigned i = 0; i < sizeof ( unsigned long long ) * 8; ++ i ) { + data.push_back ( ( bool ) ( shadow & ( 1ULL << i ) ) ); + } + + std::vector < bool > data2 = data; + data2 >>= 64; + + data >>= 32; + data >>= 16; + data >>= 8; + data >>= 4; + data >>= 2; + data >>= 1; + data >>= 1; + + std::cout << "data = " << data << std::endl; + std::cout << "data2 = " << data2 << std::endl; + + data2 >>= 1; + data2 >>= 2; + data2 >>= 4; + data2 >>= 8; + data2 >>= 16; + data2 >>= 32; + data2 >>= 1; + + data >>= 27; + data >>= 17; + data >>= 13; + data >>= 7; + + std::cout << "data = " << data << std::endl; + std::cout << "data2 = " << data2 << std::endl; + + CPPUNIT_ASSERT ( data2 == data ); +} + +void testOffset2 ( int offset ) { + unsigned long long shadow = 0x2A76B147D6521C87ULL; + std::vector < bool > data; + + for ( unsigned i = 0; i < sizeof ( unsigned long long ) * 8 + offset; ++ i ) { + data.push_back ( true ); + } + + for ( unsigned i = 0; i < sizeof ( unsigned long long ) * 8; ++ i ) { + data.push_back ( ( bool ) ( shadow & ( 1ULL << i ) ) ); + } + + data <<= sizeof ( unsigned long long ) * 2 + 1; + + std::vector < bool > ref; + for ( unsigned i = 0; i < sizeof ( unsigned long long ) * 10 + offset; ++ i ) { + ref.push_back ( true ); + } + + for ( unsigned i = 0; i < sizeof ( unsigned long long ) * 8; ++ i ) { + ref.push_back ( ( bool ) ( shadow & ( 1ULL << i ) ) ); + } + + ref.resize ( 128 + offset ); + + std::cout << "data = " << data << std::endl; + std::cout << "ref = " << ref << std::endl; + + CPPUNIT_ASSERT ( data == ref ); +} + +void VectorTest::testVectorBool4() { + unsigned long long shadow = 0x2A76B147D6521C87ULL; + std::vector < bool > data; + + for ( unsigned i = 0; i < sizeof ( unsigned long long ) * 8; ++ i ) { + data.push_back ( ( bool ) ( shadow & ( 1ULL << i ) ) ); + } + + shadow <<= 10; + data <<= 10; + + std::vector < bool > ref; + for ( unsigned i = 0; i < sizeof ( unsigned long long ) * 8; ++ i ) { + ref.push_back ( ( bool ) ( shadow & ( 1ULL << i ) ) ); + } + + std::cout << "data = " << data << std::endl; + std::cout << "ref = " << ref << std::endl; + + CPPUNIT_ASSERT ( data == ref ); + + for ( unsigned long i = - sizeof ( unsigned long long ) / 2 ; i < sizeof ( unsigned long long ) * 8; ++ i ) + testOffset2 ( i ); +} + +void VectorTest::testVectorBool5() { + unsigned long long shadow = 0x2A76B147D6521C87ULL; + std::vector < bool > data; + + for ( unsigned i = 0; i < sizeof ( unsigned long long ) * 8; ++ i ) { + data.push_back ( ( bool ) ( shadow & ( 1ULL << i ) ) ); + } + for ( unsigned i = 0; i < sizeof ( unsigned long long ) * 8; ++ i ) { + data.push_back ( ( bool ) ( shadow & ( 1ULL << i ) ) ); + } + for ( unsigned i = 0; i < sizeof ( unsigned long long ) * 8; ++ i ) { + data.push_back ( ( bool ) ( shadow & ( 1ULL << i ) ) ); + } + + std::vector < bool > data2 = data; + data2 <<= 64; + + data <<= 32; + data <<= 16; + data <<= 8; + data <<= 4; + data <<= 2; + data <<= 1; + data <<= 1; + + std::cout << "data = " << data << std::endl; + std::cout << "data2 = " << data2 << std::endl; + + data2 <<= 1; + data2 <<= 2; + data2 <<= 4; + data2 <<= 8; + data2 <<= 16; + data2 <<= 32; + data2 <<= 1; + + data <<= 27; + data <<= 17; + data <<= 13; + data <<= 7; + + std::cout << "data = " << data << std::endl; + std::cout << "data2 = " << data2 << std::endl; + + CPPUNIT_ASSERT ( data2 == data ); +} + diff --git a/alib2std/test-src/extensions/VectorTest.h b/alib2std/test-src/extensions/VectorTest.h index 4416d62c59..52d7684aa3 100644 --- a/alib2std/test-src/extensions/VectorTest.h +++ b/alib2std/test-src/extensions/VectorTest.h @@ -8,6 +8,11 @@ class VectorTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE( VectorTest ); CPPUNIT_TEST( testProperties ); + CPPUNIT_TEST( testVectorBool ); + CPPUNIT_TEST( testVectorBool2 ); + CPPUNIT_TEST( testVectorBool3 ); + CPPUNIT_TEST( testVectorBool4 ); + CPPUNIT_TEST( testVectorBool5 ); CPPUNIT_TEST_SUITE_END(); public: @@ -15,6 +20,11 @@ public: void tearDown(); void testProperties(); + void testVectorBool(); + void testVectorBool2(); + void testVectorBool3(); + void testVectorBool4(); + void testVectorBool5(); }; #endif // VARIANT_TEST_H_ -- GitLab