From 77f9a5e95056e76a7d79f0be6d5451f91b3cfe89 Mon Sep 17 00:00:00 2001 From: Maxime Pinard Date: Fri, 20 Sep 2024 17:50:07 +0200 Subject: [PATCH] New formatting rules --- .clang-format | 122 +- example/src/main.cpp | 280 +- include/sul/dynamic_bitset.hpp | 7175 ++++++++--------- tests/include/MultiTakeGenerator.hpp | 107 +- tests/include/RandomBitsetStringGenerator.hpp | 93 +- tests/include/RandomChunkGenerator.hpp | 130 +- .../include/RandomDynamicBitsetGenerator.hpp | 98 +- tests/include/config.hpp | 2 +- tests/include/utils.hpp | 34 +- tests/src/count.cpp | 78 +- tests/src/find_first_find_next.cpp | 65 +- tests/src/tests.cpp | 3906 +++++---- 12 files changed, 5954 insertions(+), 6136 deletions(-) diff --git a/.clang-format b/.clang-format index 7663720..38d925b 100644 --- a/.clang-format +++ b/.clang-format @@ -1,98 +1,38 @@ --- -Language: Cpp -AccessModifierOffset: '-4' -AlignAfterOpenBracket: Align -AlignConsecutiveAssignments: 'false' -AlignConsecutiveDeclarations: 'false' -AlignEscapedNewlines: Left -AlignOperands: 'true' -AlignTrailingComments: 'false' -AllowAllParametersOfDeclarationOnNextLine: 'false' -AllowShortBlocksOnASingleLine: 'false' -AllowShortCaseLabelsOnASingleLine: 'false' +BasedOnStyle: LLVM +AccessModifierOffset: -4 +AlignArrayOfStructures: Left +AlignEscapedNewlines: DontAlign +AlignTrailingComments: + Kind: Never +AllowShortEnumsOnASingleLine: false AllowShortFunctionsOnASingleLine: None -AllowShortIfStatementsOnASingleLine: 'false' -AllowShortLoopsOnASingleLine: 'false' -AlwaysBreakAfterReturnType: None -AlwaysBreakBeforeMultilineStrings: 'false' -AlwaysBreakTemplateDeclarations: 'Yes' -BinPackArguments: 'false' -BinPackParameters: 'false' -BraceWrapping: - AfterClass: true - AfterControlStatement: true - AfterEnum: true - AfterFunction: true - AfterNamespace: true - AfterObjCDeclaration: false - AfterStruct: true - AfterUnion: true - AfterExternBlock: true - BeforeCatch: true - BeforeElse: true - IndentBraces: false - SplitEmptyFunction: true - SplitEmptyRecord: true - SplitEmptyNamespace: true -BreakAfterJavaFieldAnnotations: 'true' +AlwaysBreakTemplateDeclarations: Yes +BinPackArguments: false +BinPackParameters: false BreakBeforeBinaryOperators: NonAssignment -BreakBeforeBraces: Custom -BreakBeforeTernaryOperators: 'true' +BreakBeforeBraces: Allman BreakConstructorInitializers: BeforeComma BreakInheritanceList: BeforeComma -BreakStringLiterals: 'false' -ColumnLimit: '100' -CompactNamespaces: 'false' -ConstructorInitializerAllOnOneLineOrOnePerLine: 'true' -ConstructorInitializerIndentWidth: '2' -ContinuationIndentWidth: '2' -Cpp11BracedListStyle: 'true' -DerivePointerAlignment: 'false' -DisableFormat: 'false' -ExperimentalAutoDetectBinPacking: 'false' -FixNamespaceComments: 'true' -ForEachMacros: - - foreach - - Q_FOREACH - - BOOST_FOREACH -IncludeBlocks: Preserve -IndentCaseLabels: 'true' +ColumnLimit: 120 +ContinuationIndentWidth: 2 +IndentCaseBlocks: true +IndentCaseLabels: true IndentPPDirectives: AfterHash -IndentWidth: '4' -IndentWrappedFunctionNames: 'false' -KeepEmptyLinesAtTheStartOfBlocks: 'true' -MacroBlockBegin: '' -MacroBlockEnd: '' -MaxEmptyLinesToKeep: '1' -NamespaceIndentation: None -PenaltyBreakAssignment: 2 -PenaltyBreakBeforeFirstCallParameter: 19 -PenaltyBreakComment: 300 -PenaltyBreakFirstLessLess: 120 -PenaltyBreakString: 1000 -PenaltyBreakTemplateDeclaration: 10 -PenaltyExcessCharacter: 1000000 -PenaltyReturnTypeOnItsOwnLine: 1000000 +IndentWidth: 4 +InsertNewlineAtEOF: true +NamespaceIndentation: All +PackConstructorInitializers: CurrentLine PointerAlignment: Left -ReflowComments: 'false' -SortIncludes: 'false' -SortUsingDeclarations: 'false' -SpaceAfterCStyleCast: 'false' -SpaceAfterTemplateKeyword: 'false' -SpaceBeforeAssignmentOperators: 'true' -SpaceBeforeCpp11BracedList: 'false' -SpaceBeforeCtorInitializerColon: 'false' -SpaceBeforeInheritanceColon: 'true' -SpaceBeforeParens: Never -SpaceBeforeRangeBasedForLoopColon: 'false' -SpaceInEmptyParentheses: 'false' -SpacesBeforeTrailingComments: '1' -SpacesInAngles: 'false' -SpacesInCStyleCastParentheses: 'false' -SpacesInContainerLiterals: 'false' -SpacesInParentheses: 'false' -SpacesInSquareBrackets: 'false' -Standard: Cpp11 -TabWidth: '4' -UseTab: ForIndentation -... +#ReflowComments: false # for Doxygen +SeparateDefinitionBlocks: Always +ShortNamespaceLines: 0 +SpaceAfterTemplateKeyword: false +SpaceBeforeParens: Custom +SpaceBeforeParensOptions: + AfterControlStatements: false + AfterForeachMacros: false + AfterIfMacros: false + #AfterPlacementOperator: false +SpaceBeforeRangeBasedForLoopColon: false +TabWidth: 4 diff --git a/example/src/main.cpp b/example/src/main.cpp index dd54ee6..e73f81f 100644 --- a/example/src/main.cpp +++ b/example/src/main.cpp @@ -11,185 +11,185 @@ int main() { - std::cout << std::boolalpha; + std::cout << std::boolalpha; - // declare bitset with 12 bits from a value - sul::dynamic_bitset a(12, 0b0100010110111); + // declare bitset with 12 bits from a value + sul::dynamic_bitset a(12, 0b0100010110111); - // remove all bits, resize to 0 - a.clear(); + // remove all bits, resize to 0 + a.clear(); - // add a bit at 1 to the end of the bitset - a.push_back(true); + // add a bit at 1 to the end of the bitset + a.push_back(true); - // remove last bit if not empty - a.pop_back(); + // remove last bit if not empty + a.pop_back(); - // append a full block to the bitset (including the leftmost leading 0s) - // in this case append 32 bits - a.append(314153u); + // append a full block to the bitset (including the leftmost leading 0s) + // in this case append 32 bits + a.append(314153u); - // same as above with multiple blocks - a.append({112u, 5146u, 546u}); + // same as above with multiple blocks + a.append({112u, 5146u, 546u}); - // resize the bitset, keep 12 first bits, discard others - a.resize(12); + // resize the bitset, keep 12 first bits, discard others + a.resize(12); - // set bits 3 to 7 to 1 - a.set(3, 4, true); + // set bits 3 to 7 to 1 + a.set(3, 4, true); - // set bit 2 to 0 - a.set(2, false); + // set bit 2 to 0 + a.set(2, false); - // set bit 1 to 1 - a.set(1); + // set bit 1 to 1 + a.set(1); - // set all bits to 1 - a.set(); + // set all bits to 1 + a.set(); - // reset bits 4 to 9 to 0 - a.reset(4, 5); + // reset bits 4 to 9 to 0 + a.reset(4, 5); - // reset bit 8 to 0 - a.reset(8); + // reset bit 8 to 0 + a.reset(8); - // reset all bits to 0 - a.reset(); + // reset all bits to 0 + a.reset(); - // flip bits 5 to 8 - a.flip(5, 3); + // flip bits 5 to 8 + a.flip(5, 3); - // flip bit 2 - a.flip(2); + // flip bit 2 + a.flip(2); - // flip all bits - a.flip(); + // flip all bits + a.flip(); - std::cout << "a = " << a << std::endl; + std::cout << "a = " << a << std::endl; - // test the value of bit 2 - std::cout << "Bit 2 is on? " << a.test(2) << std::endl; + // test the value of bit 2 + std::cout << "Bit 2 is on? " << a.test(2) << std::endl; - // test bit 4 and set it to 0 - std::cout << "Bit 4 is on? " << a.test_set(4, false) << " (set it to 0)" << std::endl; - std::cout << "a = " << a << std::endl; + // test bit 4 and set it to 0 + std::cout << "Bit 4 is on? " << a.test_set(4, false) << " (set it to 0)" << std::endl; + std::cout << "a = " << a << std::endl; - // test bit 7 and set it to 1 - std::cout << "Bit 7 is on? " << a.test_set(7) << " (set it to 1)" << std::endl; - std::cout << "a = " << a << std::endl; + // test bit 7 and set it to 1 + std::cout << "Bit 7 is on? " << a.test_set(7) << " (set it to 1)" << std::endl; + std::cout << "a = " << a << std::endl; - // test if the bitset is empty - std::cout << "Is the bitset empty? " << a.empty() << std::endl; + // test if the bitset is empty + std::cout << "Is the bitset empty? " << a.empty() << std::endl; - // get bitset size - std::cout << "Bitset size: " << a.size() << std::endl; + // get bitset size + std::cout << "Bitset size: " << a.size() << std::endl; - // test if all bits are 1 - std::cout << "All bits are on? " << a.all() << std::endl; + // test if all bits are 1 + std::cout << "All bits are on? " << a.all() << std::endl; - // test if there is at least one bit at 1 - std::cout << "Any bits are on? " << a.any() << std::endl; + // test if there is at least one bit at 1 + std::cout << "Any bits are on? " << a.any() << std::endl; - // test if all bits are 0 - std::cout << "All bits are off? " << a.none() << std::endl; + // test if all bits are 0 + std::cout << "All bits are off? " << a.none() << std::endl; - // count bits to 1 - std::cout << "Number of bits on: " << a.count() << std::endl; + // count bits to 1 + std::cout << "Number of bits on: " << a.count() << std::endl; - // get number of blocks used by the bitset - std::cout << "Number of blocks used by the bitset: " << a.num_blocks() << std::endl; + // get number of blocks used by the bitset + std::cout << "Number of blocks used by the bitset: " << a.num_blocks() << std::endl; - // get bitset capacity - std::cout << "Bitset capacity: " << a.capacity() << std::endl; + // get bitset capacity + std::cout << "Bitset capacity: " << a.capacity() << std::endl; - // find position of the first bit to 1 - const size_t pos = a.find_first(); - std::cout << "First bit on position: " << pos << std::endl; + // find position of the first bit to 1 + const size_t pos = a.find_first(); + std::cout << "First bit on position: " << pos << std::endl; - // find position of the next bit to 1 - std::cout << "Second bit on position: " << a.find_next(pos) << std::endl; + // find position of the next bit to 1 + std::cout << "Second bit on position: " << a.find_next(pos) << std::endl; - // conversion to string with . and * - std::cout << "String representation (. and *): " << a.to_string('.', '*') << std::endl; + // conversion to string with . and * + std::cout << "String representation (. and *): " << a.to_string('.', '*') << std::endl; - // conversion to string with 0 and 1 - std::cout << "String representation (0 and 1): " << a.to_string() << std::endl; + // conversion to string with 0 and 1 + std::cout << "String representation (0 and 1): " << a.to_string() << std::endl; - // conversion to unsigned long - std::cout << "Numeric value (unsigned long): " << a.to_ulong() << std::endl; + // conversion to unsigned long + std::cout << "Numeric value (unsigned long): " << a.to_ulong() << std::endl; - // conversion to unsigned long long - std::cout << "Numeric value (unsigned long long): " << a.to_ullong() << std::endl; + // conversion to unsigned long long + std::cout << "Numeric value (unsigned long long): " << a.to_ullong() << std::endl; - // iterate on bits on - std::cout << "Bits on: "; - a.iterate_bits_on([](size_t bit_pos) noexcept { std::cout << bit_pos << ' '; }); - std::cout << std::endl; - // (it is possible to pass parameters and return a 'continue' bool) - size_t bit_counter = 0; - std::cout << "3 first bits on: "; - a.iterate_bits_on( - [&bit_counter](size_t bit_pos, size_t limit) noexcept { - std::cout << bit_pos << ' '; - return ++bit_counter < limit; - }, - 3); - std::cout << std::endl; + // iterate on bits on + std::cout << "Bits on: "; + a.iterate_bits_on([](size_t bit_pos) noexcept { std::cout << bit_pos << ' '; }); + std::cout << std::endl; + // (it is possible to pass parameters and return a 'continue' bool) + size_t bit_counter = 0; + std::cout << "3 first bits on: "; + a.iterate_bits_on( + [&bit_counter](size_t bit_pos, size_t limit) noexcept + { + std::cout << bit_pos << ' '; + return ++bit_counter < limit; + }, + 3); + std::cout << std::endl; - // reserve 64 bits - a.reserve(64); + // reserve 64 bits + a.reserve(64); - // requests the removal of unused capacity - a.shrink_to_fit(); + // requests the removal of unused capacity + a.shrink_to_fit(); - // get allocator - [[maybe_unused]] const sul::dynamic_bitset::allocator_type allocator = - a.get_allocator(); + // get allocator + [[maybe_unused]] const sul::dynamic_bitset::allocator_type allocator = a.get_allocator(); - // get pointer to the underlying array of blocks - const uint32_t* data = a.data(); - std::cout << "address of the underlying array of blocks: " << data << std::endl; + // get pointer to the underlying array of blocks + const uint32_t* data = a.data(); + std::cout << "address of the underlying array of blocks: " << data << std::endl; - // declare bitset from string - sul::dynamic_bitset b("011001010101"); - std::cout << "b = " << b << std::endl; - - // determine if a bitset is a subset of another bitset - // (if it only contain bits from the other bitset) - std::cout << "a is a subset of b? " << a.is_subset_of(b) << std::endl; - - // determine if a bitset is a proper subset of another bitset - // (if it is different and only contain bits from the other bitset) - std::cout << "a is a proper subset of b? " << a.is_proper_subset_of(b) << std::endl; - - // determine if a bitset intersect another bitset - // (if they have common bits to 1) - std::cout << "Does a intersect b? " << a.intersects(b) << std::endl; - - // operators - std::cout << "~a: " << ~a << std::endl; - std::cout << "a << 3: " << (a << 3) << std::endl; - std::cout << "a >> 3: " << (a >> 3) << std::endl; - std::cout << "a & b: " << (a & b) << std::endl; - std::cout << "a | b: " << (a | b) << std::endl; - std::cout << "a ^ b: " << (a ^ b) << std::endl; - std::cout << "a - b: " << (a - b) << std::endl; - std::cout << "a == b: " << (a == b) << std::endl; - std::cout << "a < b: " << (a < b) << std::endl; - - // operator[] access - std::cout << "a[3]: " << a[3] << std::endl; - std::cout << "~a[3]: " << ~a[3] << std::endl; - a[3] = false; - a[3].set(); - a[3].reset(); - a[3].flip(); - a[3].assign(true); - a[3] = a[2]; - a[3] &= a[2]; - a[3] |= a[2]; - a[3] ^= a[2]; - a[3] -= a[2]; - - return 0; + // declare bitset from string + sul::dynamic_bitset b("011001010101"); + std::cout << "b = " << b << std::endl; + + // determine if a bitset is a subset of another bitset + // (if it only contain bits from the other bitset) + std::cout << "a is a subset of b? " << a.is_subset_of(b) << std::endl; + + // determine if a bitset is a proper subset of another bitset + // (if it is different and only contain bits from the other bitset) + std::cout << "a is a proper subset of b? " << a.is_proper_subset_of(b) << std::endl; + + // determine if a bitset intersect another bitset + // (if they have common bits to 1) + std::cout << "Does a intersect b? " << a.intersects(b) << std::endl; + + // operators + std::cout << "~a: " << ~a << std::endl; + std::cout << "a << 3: " << (a << 3) << std::endl; + std::cout << "a >> 3: " << (a >> 3) << std::endl; + std::cout << "a & b: " << (a & b) << std::endl; + std::cout << "a | b: " << (a | b) << std::endl; + std::cout << "a ^ b: " << (a ^ b) << std::endl; + std::cout << "a - b: " << (a - b) << std::endl; + std::cout << "a == b: " << (a == b) << std::endl; + std::cout << "a < b: " << (a < b) << std::endl; + + // operator[] access + std::cout << "a[3]: " << a[3] << std::endl; + std::cout << "~a[3]: " << ~a[3] << std::endl; + a[3] = false; + a[3].set(); + a[3].reset(); + a[3].flip(); + a[3].assign(true); + a[3] = a[2]; + a[3] &= a[2]; + a[3] |= a[2]; + a[3] ^= a[2]; + a[3] -= a[2]; + + return 0; } diff --git a/include/sul/dynamic_bitset.hpp b/include/sul/dynamic_bitset.hpp index 8584f1b..6a76ed2 100644 --- a/include/sul/dynamic_bitset.hpp +++ b/include/sul/dynamic_bitset.hpp @@ -43,42 +43,42 @@ * @since 1.0.0 */ -#include -#include #include -#include -#include +#include +#include #include -#include #include +#include #include -#include -#include +#include +#include +#include +#include // define DYNAMIC_BITSET_CAN_USE_LIBPOPCNT #if !defined(DYNAMIC_BITSET_NO_LIBPOPCNT) // https://github.com/kimwalisch/libpopcnt -# if __has_include() -# include -# define DYNAMIC_BITSET_CAN_USE_LIBPOPCNT true -# endif +# if __has_include() +# include +# define DYNAMIC_BITSET_CAN_USE_LIBPOPCNT true +# endif #endif #if !defined(DYNAMIC_BITSET_CAN_USE_LIBPOPCNT) -# define DYNAMIC_BITSET_CAN_USE_LIBPOPCNT false +# define DYNAMIC_BITSET_CAN_USE_LIBPOPCNT false #endif // define DYNAMIC_BITSET_CAN_USE_STD_BITOPS #if !defined(DYNAMIC_BITSET_NO_STD_BITOPS) // https://en.cppreference.com/w/cpp/header/bit -# if __has_include() -# include -# ifdef __cpp_lib_bitops -# define DYNAMIC_BITSET_CAN_USE_STD_BITOPS true -# endif -# endif +# if __has_include() +# include +# ifdef __cpp_lib_bitops +# define DYNAMIC_BITSET_CAN_USE_STD_BITOPS true +# endif +# endif #endif #if !defined(DYNAMIC_BITSET_CAN_USE_STD_BITOPS) -# define DYNAMIC_BITSET_CAN_USE_STD_BITOPS false +# define DYNAMIC_BITSET_CAN_USE_STD_BITOPS false #endif // define DYNAMIC_BITSET_CAN_USE_CLANG_BUILTIN_POPCOUNT @@ -87,55 +87,54 @@ // define DYNAMIC_BITSET_CAN_USE_MSVC_BUILTIN_BITSCANFORWARD // define DYNAMIC_BITSET_CAN_USE_MSVC_BUILTIN_BITSCANFORWARD64 #if !DYNAMIC_BITSET_CAN_USE_STD_BITOPS && !defined(DYNAMIC_BITSET_NO_COMPILER_BUILTIN) -# if defined(__clang__) +# if defined(__clang__) // https://clang.llvm.org/docs/LanguageExtensions.html#feature-checking-macros // https://clang.llvm.org/docs/LanguageExtensions.html#intrinsics-support-within-constant-expressions -# ifdef __has_builtin -# if __has_builtin(__builtin_popcount) && __has_builtin(__builtin_popcountl) \ - && __has_builtin(__builtin_popcountll) -# define DYNAMIC_BITSET_CAN_USE_CLANG_BUILTIN_POPCOUNT true -# endif -# if __has_builtin(__builtin_ctz) && __has_builtin(__builtin_ctzl) \ - && __has_builtin(__builtin_ctzll) -# define DYNAMIC_BITSET_CAN_USE_CLANG_BUILTIN_CTZ true -# endif -# endif -# elif defined(__GNUC__) // also defined by clang +# ifdef __has_builtin +# if __has_builtin(__builtin_popcount) && __has_builtin(__builtin_popcountl) \ + && __has_builtin(__builtin_popcountll) +# define DYNAMIC_BITSET_CAN_USE_CLANG_BUILTIN_POPCOUNT true +# endif +# if __has_builtin(__builtin_ctz) && __has_builtin(__builtin_ctzl) && __has_builtin(__builtin_ctzll) +# define DYNAMIC_BITSET_CAN_USE_CLANG_BUILTIN_CTZ true +# endif +# endif +# elif defined(__GNUC__) // also defined by clang // https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html -# define DYNAMIC_BITSET_CAN_USE_GCC_BUILTIN true -# elif defined(_MSC_VER) +# define DYNAMIC_BITSET_CAN_USE_GCC_BUILTIN true +# elif defined(_MSC_VER) // https://docs.microsoft.com/en-us/cpp/intrinsics/bitscanforward-bitscanforward64 // __popcnt16, __popcnt, __popcnt64 not used because it require to check the hardware support at runtime // (https://docs.microsoft.com/fr-fr/cpp/intrinsics/popcnt16-popcnt-popcnt64?view=msvc-160#remarks) -# if defined(_M_IX86) || defined(_M_ARM) || defined(_M_X64) || defined(_M_ARM64) -# include -# pragma intrinsic(_BitScanForward) -# define DYNAMIC_BITSET_CAN_USE_MSVC_BUILTIN_BITSCANFORWARD true -# endif -# if(defined(_M_X64) || defined(_M_ARM64)) \ - && !defined(DYNAMIC_BITSET_NO_MSVC_BUILTIN_BITSCANFORWARD64) // for testing purposes -# pragma intrinsic(_BitScanForward64) -# define DYNAMIC_BITSET_CAN_USE_MSVC_BUILTIN_BITSCANFORWARD64 true -# endif -# endif +# if defined(_M_IX86) || defined(_M_ARM) || defined(_M_X64) || defined(_M_ARM64) +# include +# pragma intrinsic(_BitScanForward) +# define DYNAMIC_BITSET_CAN_USE_MSVC_BUILTIN_BITSCANFORWARD true +# endif +# if(defined(_M_X64) || defined(_M_ARM64)) \ + && !defined(DYNAMIC_BITSET_NO_MSVC_BUILTIN_BITSCANFORWARD64) // for testing purposes +# pragma intrinsic(_BitScanForward64) +# define DYNAMIC_BITSET_CAN_USE_MSVC_BUILTIN_BITSCANFORWARD64 true +# endif +# endif #endif #if !defined(DYNAMIC_BITSET_CAN_USE_CLANG_BUILTIN_POPCOUNT) -# define DYNAMIC_BITSET_CAN_USE_CLANG_BUILTIN_POPCOUNT false +# define DYNAMIC_BITSET_CAN_USE_CLANG_BUILTIN_POPCOUNT false #endif #if !defined(DYNAMIC_BITSET_CAN_USE_CLANG_BUILTIN_CTZ) -# define DYNAMIC_BITSET_CAN_USE_CLANG_BUILTIN_CTZ false +# define DYNAMIC_BITSET_CAN_USE_CLANG_BUILTIN_CTZ false #endif #if !defined(DYNAMIC_BITSET_CAN_USE_GCC_BUILTIN) -# define DYNAMIC_BITSET_CAN_USE_GCC_BUILTIN false +# define DYNAMIC_BITSET_CAN_USE_GCC_BUILTIN false #endif #if !defined(DYNAMIC_BITSET_CAN_USE_MSVC_BUILTIN_BITSCANFORWARD) -# define DYNAMIC_BITSET_CAN_USE_MSVC_BUILTIN_BITSCANFORWARD false +# define DYNAMIC_BITSET_CAN_USE_MSVC_BUILTIN_BITSCANFORWARD false #endif #if !defined(DYNAMIC_BITSET_CAN_USE_MSVC_BUILTIN_BITSCANFORWARD64) -# define DYNAMIC_BITSET_CAN_USE_MSVC_BUILTIN_BITSCANFORWARD64 false +# define DYNAMIC_BITSET_CAN_USE_MSVC_BUILTIN_BITSCANFORWARD64 false #endif #if !defined(DYNAMIC_BITSET_CAN_USE_MSVC_BUILTIN) -# define DYNAMIC_BITSET_CAN_USE_MSVC_BUILTIN false +# define DYNAMIC_BITSET_CAN_USE_MSVC_BUILTIN false #endif #ifndef DYNAMIC_BITSET_NO_NAMESPACE @@ -148,3593 +147,3529 @@ namespace sul { #endif -/** - * @brief Dynamic bitset. - * - * @details Data structure used to store a vector of bits and apply binary operations to it. The - * bits are stored in an optimized way in an underling block type. It is highly inspired - * by std\::bitset but with a run-time changeable size. - * - * Preconditions are checked with @a assert but no exception will be thrown if one is - * violated (as with std\::bitset). - * - * @remark It is not a Container as it does not provide iterators because of the reference proxy - * class used to access the bits. - * - * @tparam Block Block type to use for storing the bits, must be an unsigned integral type - * @tparam Allocator Allocator type to use for memory management, must meet the standard - * requirements of @a Allocator - * - * @since 1.0.0 - */ -template> -class dynamic_bitset -{ - static_assert(std::is_unsigned::value, "Block is not an unsigned integral type"); - -public: - /** - * @brief Type used to represent the size of a @ref sul::dynamic_bitset. - * - * @since 1.0.0 - */ - typedef size_t size_type; - - /** - * @brief Same type as @p Block. - * - * @since 1.0.0 - */ - typedef Block block_type; - - /** - * @brief Same type as @p Allocator. - * - * @since 1.0.0 - */ - typedef Allocator allocator_type; - - /** - * @brief Number of bits that can be stored in a block. - * - * @since 1.0.0 - */ - static constexpr size_type bits_per_block = std::numeric_limits::digits; - - /** - * @brief Maximum value of @ref size_type, returned for invalid positions. - * - * @since 1.0.0 - */ - static constexpr size_type npos = std::numeric_limits::max(); - - /** - * @brief Reference to a @ref sul::dynamic_bitset bit. - * - * @details As the bits in the @ref sul::dynamic_bitset class are stored in an optimized way - * in blocks, it is not possible for the subscript operators to return a reference - * to a boolean. Hence this class is used as a proxy to enable subscript operator of - * the @ref sul::dynamic_bitset class to be used as if it was an array of bools. - * - * @since 1.0.0 - */ - class reference - { - public: - /** - * @brief Constructs a @ref reference to a bit from a @ref sul::dynamic_bitset and a - * bit position. - * - * @param bitset @ref sul::dynamic_bitset containing the bit - * @param[in] bit_pos Position of the bit to reference in the @ref sul::dynamic_bitset - * - * @complexity Constant. - * - * @since 1.0.0 - */ - constexpr reference(dynamic_bitset& bitset, size_type bit_pos); - - /** - * @brief Copy constructor. - * - * @since 1.0.0 - */ - constexpr reference(const reference&) noexcept = default; - - /** - * @brief Move constructor. - * - * @since 1.0.0 - */ - constexpr reference(reference&&) noexcept = default; - - /** - * @brief Destructor. - * - * @since 1.0.0 - */ - ~reference() noexcept = default; - - /** - * @brief Assign a value to the referenced bit. - * - * @param[in] v Value to assign to the referenced bit - * - * @return The @ref reference - * - * @complexity Constant. - * - * @since 1.0.0 - */ - constexpr reference& operator=(bool v); - - /** - * @brief Assign a value to the referenced bit from another @ref reference. - * - * @param[in] rhs @ref reference to the bit to assign value from - * - * @return The @ref reference - * - * @complexity Constant. - * - * @since 1.0.0 - */ - constexpr reference& operator=(const reference& rhs); - - /** - * @brief Assign a value to the referenced bit from another @ref reference. - * - * @param[in] rhs @ref reference to the bit to assign value from - * - * @return The @ref reference - * - * @complexity Constant. - * - * @since 1.0.0 - */ - constexpr reference& operator=(reference&& rhs) noexcept; - - /** - * @brief Apply binary operator AND to the referenced bit and a value, and assign the - * result to the referenced bit. - * - * @param[in] v Value to apply binary operator AND with - * - * @return The @ref reference - * - * @complexity Constant. - * - * @since 1.0.0 - */ - constexpr reference& operator&=(bool v); - - /** - * @brief Apply binary operator OR to the referenced bit and a value, and assign the - * result to the referenced bit. - * - * @param[in] v Value to apply binary operator OR with - * - * @return The @ref reference - * - * @complexity Constant. - * - * @since 1.0.0 - */ - constexpr reference& operator|=(bool v); - - /** - * @brief Apply binary operator XOR to the referenced bit and a value, and assign the - * result to the referenced bit. - * - * @param[in] v Value to apply binary operator XOR with - * - * @return The @ref reference - * - * @complexity Constant. - * - * @since 1.0.0 - */ - constexpr reference& operator^=(bool v); - - /** - * @brief Apply binary difference to the referenced bit and a value, and assign the - * result to the referenced bit. - * - * @details Equivalent to: - * @code - * this &= !v; - * @endcode - * - * @param[in] v Value to apply binary difference with - * - * @return The @ref reference - * - * @complexity Constant. - * - * @since 1.0.0 - */ - constexpr reference& operator-=(bool v); - - /** - * @brief Return the result of applying unary NOT operator. - * - * @return The opposite of the referenced bit - * - * @complexity Constant. - * - * @since 1.0.0 - */ - [[nodiscard]] constexpr bool operator~() const; - - /** - * @brief bool conversion operator. - * - * @complexity Constant. - * - * @since 1.0.0 - */ - [[nodiscard]] constexpr operator bool() const; - - /** - * @brief Deleted to avoid taking the address of a temporary proxy object. - * - * @since 1.0.0 - */ - constexpr void operator&() = delete; - - /** - * @brief Set the referenced bit to @a true. - * - * @return The @ref reference - * - * @complexity Constant. - * - * @since 1.0.0 - */ - constexpr reference& set(); - - /** - * @brief Reset the referenced bit to @a false. - * - * @return The @ref reference - * - * @complexity Constant. - * - * @since 1.0.0 - */ - constexpr reference& reset(); - - /** - * @brief Flip the referenced bit. - * - * @return The @ref reference - * - * @complexity Constant. - * - * @since 1.0.0 - */ - constexpr reference& flip(); - - /** - * @brief Assign the value @p v to the referenced bit. - * - * @param[in] v Value to assign to the bit - * - * @return The @ref reference - * - * @complexity Constant. - * - * @since 1.0.0 - */ - constexpr reference& assign(bool v); - - private: - block_type& m_block; - block_type m_mask; - }; - - /** - * @brief Const reference to a @ref sul::dynamic_bitset bit, type bool. - * - * @since 1.0.0 - */ - typedef bool const_reference; - - /** - * @brief Copy constructor. - * - * @since 1.0.0 - */ - constexpr dynamic_bitset(const dynamic_bitset& other) = default; - - /** - * @brief Move constructor. - * - * @since 1.0.0 - */ - constexpr dynamic_bitset(dynamic_bitset&& other) noexcept = default; - - /** - * @brief Copy assignment operator. - * - * @since 1.0.0 - */ - constexpr dynamic_bitset& operator=( - const dynamic_bitset& other) = default; - - /** - * @brief Move assignment operator. - * - * @since 1.0.0 - */ - constexpr dynamic_bitset& operator=( - dynamic_bitset&& other) noexcept = default; - - /** - * @brief Constructs an empty @ref sul::dynamic_bitset. - * - * @details A copy of @p allocator will be used for memory management. - * - * @param[in] allocator Allocator to use for memory management - * - * @complexity Constant. - * - * @since 1.0.0 - */ - constexpr explicit dynamic_bitset(const allocator_type& allocator = allocator_type()); - - /** - * @brief Constructs a @ref sul::dynamic_bitset of @p nbits bits from an initial value. - * - * @details The first bits are initialized with the bits from @p init_val, if @p nbits \> - * std\::numeric_limits\\::digits , all other bits are - * initialized to @a false. A copy of @p allocator will be used for memory - * management. - * - * @param[in] nbits Number of bits of the @ref sul::dynamic_bitset - * @param[in] init_val Value to initialize the @ref sul::dynamic_bitset with - * @param[in] allocator Allocator to use for memory management - * - * @complexity Linear in @p nbits / @ref bits_per_block. - * - * @since 1.0.0 - */ - constexpr explicit dynamic_bitset(size_type nbits, - unsigned long long init_val = 0, - const allocator_type& allocator = allocator_type()); - - /** - * @brief Constructs a @ref sul::dynamic_bitset using @p init_vals to initialize the first - * blocks. - * - * @details The size of the newly created @ref sul::dynamic_bitset is @p init_vals.size() * - * @ref bits_per_block. A copy of @p allocator will be used for memory management. - * - * @param[in] init_vals Value of the @ref sul::dynamic_bitset first blocks - * @param[in] allocator Allocator to use for memory management - * - * @complexity Linear in @p init_vals.size(). - * - * @since 1.0.0 - */ - constexpr dynamic_bitset(std::initializer_list init_vals, - const allocator_type& allocator = allocator_type()); - - /** - * @brief Constructs a @ref sul::dynamic_bitset from a string or a part of a string. - * - * @details Construct the @ref sul::dynamic_bitset using the characters from @p str in the - * range \[@p pos, std\::min(@p pos + @p n, @p str.size())\[. - * - * @param[in] str String containing the part to use - * @param[in] pos Starting position of the string part to use in @p str - * @param[in] n Number of characters of @p str to use from the starting position - * @param[in] zero Character used to represent @a false bits in @p str - * @param[in] one Character used to represent @a true bits in @p str - * @param[in] allocator Allocator to use for memory management - * - * @tparam _CharT Character type of the string - * @tparam _Traits Traits class specifying the operations on the character type of the - * string - * - * @pre @code - * pos < str.size() - * @endcode - * - * @complexity Linear in std\::min(@p n, @p str.size() - @p pos). - * - * @since 1.0.0 - */ - template - constexpr explicit dynamic_bitset( - std::basic_string_view<_CharT, _Traits> str, - typename std::basic_string_view<_CharT, _Traits>::size_type pos = 0, - typename std::basic_string_view<_CharT, _Traits>::size_type n = - std::basic_string_view<_CharT, _Traits>::npos, - _CharT zero = _CharT('0'), - _CharT one = _CharT('1'), - const allocator_type& allocator = allocator_type()); - - /** - * @brief Constructs a @ref sul::dynamic_bitset from a string or a part of a string. - * - * @details Construct the @ref sul::dynamic_bitset using the characters from @p str in the - * range \[@p pos, std\::min(@p pos + @p n, @p str.size())\[. - * - * @param[in] str String containing the part to use - * @param[in] pos Starting position of the string part to use in @p str - * @param[in] n Number of characters of @p str to use from the starting position - * @param[in] zero Character used to represent @a false bits in @p str - * @param[in] one Character used to represent @a true bits in @p str - * @param[in] allocator Allocator to use for memory management - * - * @tparam _CharT Character type of the string - * @tparam _Traits Traits class specifying the operations on the character type of the - * string - * @tparam _Alloc Allocator type used to allocate internal storage of the string - * - * @pre @code - * pos < str.size() - * @endcode - * - * @complexity Linear in std\::min(@p n, @p str.size() - @p pos). - * - * @since 1.0.0 - */ - template - constexpr explicit dynamic_bitset( - const std::basic_string<_CharT, _Traits, _Alloc>& str, - typename std::basic_string<_CharT, _Traits, _Alloc>::size_type pos = 0, - typename std::basic_string<_CharT, _Traits, _Alloc>::size_type n = - std::basic_string<_CharT, _Traits, _Alloc>::npos, - _CharT zero = _CharT('0'), - _CharT one = _CharT('1'), - const allocator_type& allocator = allocator_type()); - - /** - * @brief Constructs a @ref sul::dynamic_bitset from a string or a part of a string. - * - * @details Construct the @ref sul::dynamic_bitset using the characters from @p str in the - * range \[@p pos, std\::min(@p pos + @p n, @p _Traits\::length(@p str))\[. - * - * @param[in] str String containing the part to use - * @param[in] pos Starting position of the string part to use - * @param[in] n Number of characters to use from the starting position - * @param[in] zero Character used to represent @a false bits in the string - * @param[in] one Character used to represent 1 @a true bitsn the string - * @param[in] allocator Allocator to use for memory management - * - * @tparam _CharT Character type of the string - * @tparam _Traits Traits class specifying the operations on the character type of the - * string - * - * @pre @code - * pos < _Traits::length(str) - * @endcode - * - * @complexity Linear in std\::min(@p n, @p _Traits\::length(@p str) - @p pos). - * - * @since 1.0.0 - */ - template> - constexpr explicit dynamic_bitset( - const _CharT* str, - typename std::basic_string<_CharT>::size_type pos = 0, - typename std::basic_string<_CharT>::size_type n = std::basic_string<_CharT>::npos, - _CharT zero = _CharT('0'), - _CharT one = _CharT('1'), - const allocator_type& allocator = allocator_type()); - - /** - * @brief Destructor. - * - * @since 1.0.0 - */ - ~dynamic_bitset() noexcept = default; - - /** - * @brief Resize the @ref sul::dynamic_bitset to contain @p nbits bits. - * - * @details Bits keep the value they had before the resize and, if @p nbits is greater than - * the current size, new bit are initialized to @p value. - * - * @param[in] nbits New size of the @ref sul::dynamic_bitset - * @param[in] value Value of the new bits - * - * @complexity Linear in the difference between the current size and @p nbits. - * Additional complexity possible due to reallocation if capacity is less than @p - * nbits. - * - * @since 1.0.0 - */ - constexpr void resize(size_type nbits, bool value = false); - - /** - * @brief Clears the @ref sul::dynamic_bitset, resize it to 0. - * - * @details Equivalent to: - * @code - * this.resize(0); - * @endcode - * - * @complexity Linear in the size of the @ref sul::dynamic_bitset. - * - * @since 1.0.0 - */ - constexpr void clear(); - - /** - * @brief Add a new bit with the value @p value at the end of the @ref sul::dynamic_bitset. - * - * @details Increase the size of the bitset by one, the added bit becomes the - * most-significant bit. - * - * @param[in] value Value of the bit to add - * - * @complexity Amortized constant. - * - * @since 1.0.0 - */ - constexpr void push_back(bool value); - - /** - * @brief Remove the last bit of the @ref sul::dynamic_bitset. - * - * @details Decrease the size of the @ref sul::dynamic_bitset by one, does nothing if the - * @ref dynamic_bitset is empty. - * - * @complexity Constant. - * - * @since 1.0.0 - */ - constexpr void pop_back(); - - /** - * @brief Append a block of bits @p block at the end of the @ref sul::dynamic_bitset. - * - * @details Increase the size of the @ref sul::dynamic_bitset by @ref bits_per_block. - * - * @param[in] block Block of bits to add - * - * @complexity Amortized constant. - * - * @since 1.0.0 - */ - constexpr void append(block_type block); - - /** - * @brief Append blocks of bits from @p blocks at the end of the @ref sul::dynamic_bitset. - * - * @param[in] blocks Blocks of bits to add - * - * @complexity Linear in the size of @p blocks. Additional complexity possible due - * to reallocation if capacity is less than @ref size() + @p blocks.size() * @ref - * bits_per_block. - * - * @since 1.0.0 - */ - constexpr void append(std::initializer_list blocks); - - /** - * @brief Append blocks of bits from the range \[@p first, @p last\[ at the end of the @ref - * dynamic_bitset. - * - * @param[in] first First iterator of the range - * @param[in] last Last iterator of the range (after the last element to add) - * - * @tparam BlockInputIterator Type of the range iterators - * - * @complexity Linear in the size of the range. Additional complexity possible due - * to reallocation if capacity is less than @ref size() + std\::distance(@p first, - * @p last) * @ref bits_per_block. - * - * @since 1.0.0 - */ - template - constexpr void append(BlockInputIterator first, BlockInputIterator last); - - /** - * @brief Sets the bits to the result of binary AND on corresponding pairs of bits of *this - * and @p rhs. - * - * @param[in] rhs Right hand side @ref sul::dynamic_bitset of the operator - * - * @return A reference to the @ref sul::dynamic_bitset *this - * - * @pre @code - * size() == rhs.size() - * @endcode - * - * @complexity Linear in the size of the @ref sul::dynamic_bitset. - * - * @since 1.0.0 - */ - constexpr dynamic_bitset& operator&=( - const dynamic_bitset& rhs); - - /** - * @brief Sets the bits to the result of binary OR on corresponding pairs of bits of *this - * and @p rhs. - * - * @param[in] rhs Right hand side @ref sul::dynamic_bitset of the operator - * - * @return A reference to the @ref sul::dynamic_bitset *this - * - * @pre @code - * size() == rhs.size() - * @endcode - * - * @complexity Linear in the size of the @ref sul::dynamic_bitset. - * - * @since 1.0.0 - */ - constexpr dynamic_bitset& operator|=( - const dynamic_bitset& rhs); - - /** - * @brief Sets the bits to the result of binary XOR on corresponding pairs of bits of *this - * and @p rhs. - * - * @param[in] rhs Right hand side @ref sul::dynamic_bitset of the operator - * - * @return A reference to the @ref sul::dynamic_bitset *this - * - * @pre @code - * size() == rhs.size() - * @endcode - * - * @complexity Linear in the size of the @ref sul::dynamic_bitset. - * - * @since 1.0.0 - */ - constexpr dynamic_bitset& operator^=( - const dynamic_bitset& rhs); - - /** - * @brief Sets the bits to the result of the binary difference between the bits of *this - * and @p rhs. - * - * @details Less efficient but equivalent way to get this result: - * @code - * this &= ~rhs; - * @endcode - * - * @param[in] rhs Right hand side @ref sul::dynamic_bitset of the operator - * - * @return A reference to the @ref sul::dynamic_bitset *this - * - * @pre @code - * size() == rhs.size() - * @endcode - * - * @complexity Linear in the size of the @ref sul::dynamic_bitset. - * - * @since 1.0.0 - */ - constexpr dynamic_bitset& operator-=( - const dynamic_bitset& rhs); - - /** - * @brief Performs binary shift left of @p shift bits. - * - * @details Zeroes are shifted in, does nothing if @p shift == 0. - * - * @param[in] shift Number of positions to shift the bits - * - * @return A reference to the @ref sul::dynamic_bitset *this - * - * @complexity Linear in the size of the @ref sul::dynamic_bitset. - * - * @since 1.0.0 - */ - constexpr dynamic_bitset& operator<<=(size_type shift); - - /** - * @brief Performs binary shift right of @p shift bits. - * - * @details Zeroes are shifted in, does nothing if @p shift == 0. - * - * @param[in] shift Number of positions to shift the bits - * - * @return A reference to the @ref sul::dynamic_bitset *this - * - * @complexity Linear in the size of the @ref sul::dynamic_bitset. - * - * @since 1.0.0 - */ - constexpr dynamic_bitset& operator>>=(size_type shift); - - /** - * @brief Performs binary shift right of @p shift bits. - * - * @details Zeroes are shifted in. Does nothing if @p shift == 0.\n - * Equivalent to: - * @code - * dynamic_bitset bitset(*this); - * bitset <<= shift; - * @endcode - * - * @param[in] shift Number of positions to shift the bits - * - * @return A new @ref sul::dynamic_bitset containing the shifted bits - * - * @complexity Linear in the size of the @ref sul::dynamic_bitset. - * - * @since 1.0.0 - */ - [[nodiscard]] constexpr dynamic_bitset operator<<(size_type shift) const; - - /** - * @brief Performs binary shift left of @p shift bits. - * - * @details Zeroes are shifted in. Does nothing if @p shift == 0.\n - * Equivalent to: - * @code - * dynamic_bitset bitset(*this); - * bitset >>= shift; - * @endcode - * - * @param[in] shift Number of positions to shift the bits - * - * @return A new @ref sul::dynamic_bitset containing the shifted bits - * - * @complexity Linear in the size of the @ref sul::dynamic_bitset. - * - * @since 1.0.0 - */ - [[nodiscard]] constexpr dynamic_bitset operator>>(size_type shift) const; - - /** - * @brief Performs a unary NOT on all bits. - * - * @details Equivalent to: - * @code - * dynamic_bitset bitset(*this); - * bitset.flip(); - * @endcode - * - * @return A copy of *this with all bits flipped - * - * @complexity Linear in the size of the @ref sul::dynamic_bitset. - * - * @since 1.0.0 - */ - [[nodiscard]] constexpr dynamic_bitset operator~() const; - - /** - * @brief Set the bits of the range \[@p pos, @p pos + @p len\[ to value @p value. - * - * @details Does nothing if @p len == 0. - * - * @param[in] pos Position of the first bit of the range - * @param[in] len Length of the range - * @param[in] value Value to set the bits to - * - * @return A reference to the @ref sul::dynamic_bitset *this - * - * @pre @code - * (pos < size()) && ((len == 0) || (pos + len - 1 < size())) - * @endcode - * - * @complexity Linear in @p len. - * - * @since 1.0.0 - */ - constexpr dynamic_bitset& set(size_type pos, size_type len, bool value); - - /** - * @brief Set the bit at the position @p pos to @a true or value @p value. - * - * @param[in] pos Position of the bit to set - * @param[in] value Value to set the bit to - * - * @return A reference to the @ref sul::dynamic_bitset *this - * - * @pre @code - * pos < size() - * @endcode - * - * @complexity Constant. - * - * @since 1.0.0 - */ - constexpr dynamic_bitset& set(size_type pos, bool value = true); - - /** - * @brief Set all the bits of the @ref sul::dynamic_bitset to @a true. - * - * @return A reference to the @ref sul::dynamic_bitset *this - * - * @complexity Linear in the size of the @ref sul::dynamic_bitset. - * - * @since 1.0.0 - */ - constexpr dynamic_bitset& set(); - - /** - * @brief Reset the bits of the range \[@p pos, @p pos + @p len\[ to @a false. - * - * @param[in] pos Position of the first bit of the range - * @param[in] len Length of the range - * - * @return A reference to the @ref sul::dynamic_bitset *this - * - * @pre @code - * (pos < size()) && ((len == 0) || (pos + len - 1 < size())) - * @endcode - * - * @complexity Linear in @p len. - * - * @since 1.0.0 - */ - constexpr dynamic_bitset& reset(size_type pos, size_type len); - - /** - * @brief Reset the bit at the position @p pos to @a false. - * - * @param[in] pos Position of the bit to reset - * - * @return A reference to the @ref sul::dynamic_bitset *this - * - * @pre @code - * pos < size() - * @endcode - * - * @complexity Constant. - * - * @since 1.0.0 - */ - constexpr dynamic_bitset& reset(size_type pos); - - /** - * @brief Reset all the bits of the @ref sul::dynamic_bitset to @a false. - * - * @return A reference to the @ref sul::dynamic_bitset *this - * - * @complexity Linear in the size of the @ref sul::dynamic_bitset. - * - * @since 1.0.0 - */ - constexpr dynamic_bitset& reset(); - - /** - * @brief Flip the bits of the range \[@p pos, @p pos + @p len\[. - * - * @param[in] pos Position of the first bit of the range - * @param[in] len Length of the range - * - * @return A reference to the @ref sul::dynamic_bitset *this - * - * @pre @code - * (pos < size()) && ((len == 0) || (pos + len - 1 < size())) - * @endcode - * - * @complexity Linear in @p len. - * - * @since 1.0.0 - */ - constexpr dynamic_bitset& flip(size_type pos, size_type len); - - /** - * @brief Flip the bit at the position @p pos. - * - * @param[in] pos Position of the bit to reset - * - * @return A reference to the @ref sul::dynamic_bitset *this - * - * @pre @code - * pos < size() - * @endcode - * - * @complexity Constant. - * - * @since 1.0.0 - */ - constexpr dynamic_bitset& flip(size_type pos); - - /** - * @brief Flip all the bits of the @ref sul::dynamic_bitset. - * - * @return A reference to the @ref sul::dynamic_bitset *this - * - * @complexity Linear in the size of the @ref sul::dynamic_bitset. - * - * @since 1.0.0 - */ - constexpr dynamic_bitset& flip(); - - /** - * @brief Test the value of the bit at position @p pos. - * - * @param[in] pos Position of the bit to test - * - * @return The tested bit value - * - * @pre @code - * pos < size() - * @endcode - * - * @complexity Constant. - * - * @since 1.0.0 - */ - [[nodiscard]] constexpr bool test(size_type pos) const; - - /** - * @brief Test the value of the bit at position @p pos and set it to @a true or value @p - * value. - * - * @param[in] pos Position of the bit to test and set - * @param[in] value Value to set the bit to - * - * @return The tested bit value - * - * @pre @code - * pos < size() - * @endcode - * - * @complexity Constant. - * - * @since 1.0.0 - */ - [[nodiscard]] constexpr bool test_set(size_type pos, bool value = true); - - /** - * @brief Checks if all bits are set to @a true. - * - * @return @a true if all bits are set to @a true, otherwise @a false - * - * @remark Return @a true if the @ref sul::dynamic_bitset is empty, the logic is that you - * are checking if all bits are set to @a true, meaning none of them is set to @a - * false, and in an empty @ref sul::dynamic_bitset no bits are set to @a false. - * - * @complexity Linear in the size of the @ref sul::dynamic_bitset. - * - * @since 1.0.0 - */ - [[nodiscard]] constexpr bool all() const; - - /** - * @brief Checks if any bits are set to @a true. - * - * @return @a true if any of the bits is set to @a true, otherwise @a false - * - * @remark Return @a false if the @ref sul::dynamic_bitset is empty, the logic is you are - * checking if there is at least one bit set to @a true and in an empty @ref - * dynamic_bitset there is no bit set to @a true. - * - * @complexity Linear in the size of the @ref sul::dynamic_bitset. - * - * @since 1.0.0 - */ - [[nodiscard]] constexpr bool any() const; - - /** - * @brief Checks if none of the bits are set to @a true. - * - * @return @a true if none of the bits is set to @a true, otherwise @a false - * - * @remark Return @a true if the @ref sul::dynamic_bitset is empty, the logic is that you - * are checking if there is no bit set to @a true and in an empty @ref - * sul::dynamic_bitset there is no bit that can be set to @a true. - * - * @complexity Linear in the size of the @ref sul::dynamic_bitset. - * - * @since 1.0.0 - */ - [[nodiscard]] constexpr bool none() const; - - /** - * @brief Count the number of bits set to @a true. - * - * @details Return 0 if the @ref sul::dynamic_bitset is empty. - * - * @return The number of bits that are set to @a true - * - * @complexity Linear in the size of the @ref sul::dynamic_bitset. - * - * @since 1.0.0 - */ - [[nodiscard]] constexpr size_type count() const noexcept; - - /** - * @brief Accesses the bit at position @p pos. - * - * @param[in] pos Position of the bit to access - * - * @return A @ref reference object which allows writing to the requested bit - * - * @pre @code - * pos < size() - * @endcode - * - * @complexity Constant. - * - * @since 1.0.0 - */ - [[nodiscard]] constexpr reference operator[](size_type pos); - - /** - * @brief Accesses the bit at position @p pos. - * - * @param[in] pos Position of the bit to access - * - * @return The value of the requested bit - * - * @pre @code - * pos < size() - * @endcode - * - * @complexity Constant. - * - * @since 1.0.0 - */ - [[nodiscard]] constexpr const_reference operator[](size_type pos) const; - - /** - * @brief Give the number of bits of the @ref sul::dynamic_bitset. - * - * @return The number of bits of the @ref sul::dynamic_bitset - * - * @complexity Constant. - * - * @since 1.0.0 - */ - [[nodiscard]] constexpr size_type size() const noexcept; - - /** - * @brief Give the number of blocks used by the @ref sul::dynamic_bitset. - * - * @return The number of blocks used by the @ref sul::dynamic_bitset - * - * @complexity Constant. - * - * @since 1.0.0 - */ - [[nodiscard]] constexpr size_type num_blocks() const noexcept; - - /** - * @brief Checks if the @ref sul::dynamic_bitset is empty. - * - * @details Equivalent to: - * @code - * size() == 0; - * @endcode - * - * @return @a true if the @ref sul::dynamic_bitset is empty, @a false otherwise - * - * @complexity Constant. - * - * @since 1.0.0 - */ - [[nodiscard]] constexpr bool empty() const noexcept; - - /** - * @brief Give the number of bits that the @ref sul::dynamic_bitset has currently allocated - * space for. - * - * @return Capacity of the currently allocated storage. - * - * @complexity Constant. - * - * @since 1.0.0 - */ - [[nodiscard]] constexpr size_type capacity() const noexcept; - - /** - * @brief Increase the capacity of the @ref sul::dynamic_bitset to a value that's greater - * or equal to @p num_bits. - * - * @details If @p num_bits is greater than the current capacity, new storage is allocated and - * all @ref reference on bits of the @ref sul::dynamic_bitset are invalidated, - * otherwise the method does nothing. - * - * @param[in] num_bits New capacity of the @ref sul::dynamic_bitset - * - * @complexity At most linear in the size of the @ref sul::dynamic_bitset. - * - * @since 1.0.0 - */ - constexpr void reserve(size_type num_bits); - - /** - * @brief Requests the removal of unused capacity. - * - * @details It is a non-binding request to reduce the capacity to the size. It depends on the - * implementation of std\::vector whether the request is fulfilled.\n If - * reallocation occurs, all @ref reference on bits of the @ref sul::dynamic_bitset - * are invalidated. - * - * @complexity At most linear in the size of the @ref sul::dynamic_bitset. - * - * @since 1.0.0 - */ - constexpr void shrink_to_fit(); - - /** - * @brief Determines if this @ref sul::dynamic_bitset is a subset of @p bitset. - * - * @details This @ref sul::dynamic_bitset is a subset of @p bitset if, for every bit that is - * set in this @ref sul::dynamic_bitset, the corresponding bit in @p bitset a is - * also set.\n\n Less efficient but equivalent way to get this result: - * @code - * res = (this & ~bitset).none(); - * @endcode - * - * @param[in] bitset The @ref sul::dynamic_bitset for which to check if this @ref - * sul::dynamic_bitset is a subset - * - * @return @a true if this @ref sul::dynamic_bitset is a subset of @p bitset, @a false - * otherwise - * - * @remark The relation "is a subset of" is not symmetric (A being a subset of B doesn't - * imply that B is a subset of A) but is antisymmetric (if A is a subset of B and B - * is a subset of A, then A == B). - * - * @pre @code - * size() == bitset.size() - * @endcode - * - * @complexity Linear in the size of the @ref sul::dynamic_bitset. - * - * @since 1.0.0 - */ - [[nodiscard]] constexpr bool is_subset_of(const dynamic_bitset& bitset) const; - - /** - * @brief Determines if this @ref sul::dynamic_bitset is a proper subset of @p bitset. - * - * @details This @ref sul::dynamic_bitset is a proper subset of @p bitset if, for every bit - * that is set in this @ref sul::dynamic_bitset, the corresponding bit in @p bitset - * a is also set and if this @ref sul::dynamic_bitset is different from @p - * bitset.\n\n Less efficient but equivalent way to get this result: - * @code - * res = ((this != bitset) && (this & ~bitset).none()); - * @endcode - * - * @param[in] bitset The @ref sul::dynamic_bitset for which to check if this @ref - * sul::dynamic_bitset is a proper subset - * - * @return @a true if this @ref sul::dynamic_bitset is a proper subset of @p bitset, @a - * false otherwise - * - * @remark The relation "is a proper subset of" is asymmetric (A being a proper subset of B - * imply that B is not a proper subset of A). - * - * @pre @code - * size() == bitset.size() - * @endcode - * - * @complexity Linear in the size of the @ref sul::dynamic_bitset. - * - * @since 1.0.0 - */ - [[nodiscard]] constexpr bool is_proper_subset_of( - const dynamic_bitset& bitset) const; - - /** - * @brief Determines if this @ref sul::dynamic_bitset and @p bitset intersect. - * - * @details This @ref sul::dynamic_bitset intersects with @p bitset if for at least one bit - * set in this @ref sul::dynamic_bitset, the corresponding bit in @p bitset a is - * also set. In other words two bitsets intersect if they have at least one bit set - * in common.\n\n Less efficient but equivalent way to get this result: - * @code - * res = (this & bitset).any(); - * @endcode - * - * @param[in] bitset The @ref sul::dynamic_bitset for which to check if this @ref - * sul::dynamic_bitset intersects - * - * @return @a true if this @ref sul::dynamic_bitset intersects with @p bitset, @a false - * otherwise - * - * @pre @code - * size() == bitset.size() - * @endcode - * - * @complexity Linear in the size of the @ref sul::dynamic_bitset. - * - * @since 1.0.0 - */ - [[nodiscard]] constexpr bool intersects(const dynamic_bitset& bitset) const; - - /** - * @brief Find the position of the first bit set in the @ref sul::dynamic_bitset starting - * from the least-significant bit. - * - * @details Give the lowest index of the @ref sul::dynamic_bitset with a bit set, or @ref - * npos if no bits are set. - * - * @return The position of the first bit set, or @ref npos if no bits are set - * - * @complexity Linear in the size of the @ref sul::dynamic_bitset. - * - * @since 1.0.0 - */ - [[nodiscard]] constexpr size_type find_first() const; - - /** - * @brief Find the position of the first bit set in the range \[@p prev + 1, @ref size()\[ - * of the @ref sul::dynamic_bitset starting from the position @p prev + 1. - * - * @details Give the lowest index superior to @p prev of the @ref sul::dynamic_bitset with a - * bit set, or @ref npos if no bits are set after the index @p prev.\n If @p prev + - * 1 \>= @ref size(), return @ref npos. - * - * @param[in] prev Position of the bit preceding the search range - * - * @return The position of the first bit set after @p prev, or @ref npos if no bits are set - * after @p prev - * - * @complexity Linear in @ref size() - @p prev. - * - * @since 1.0.0 - */ - [[nodiscard]] constexpr size_type find_next(size_type prev) const; - - /** - * @brief Exchanges the bits of this @ref sul::dynamic_bitset with those of @p other. - * - * @details All @ref reference on bits of the @ref sul::dynamic_bitset are invalidated. - * - * @param other @ref sul::dynamic_bitset to exchange bits with - * - * @complexity Constant. - * - * @since 1.0.0 - */ - constexpr void swap(dynamic_bitset& other); - - /** - * @brief Gets the associated allocator. - * - * @return The associated allocator. - * - * @complexity Constant. - * - * @since 1.0.0 - */ - [[nodiscard]] constexpr allocator_type get_allocator() const; - - /** - * @brief Generate a string representation of the @ref sul::dynamic_bitset. - * - * @details Uses @p zero to represent bits with value of @a false and @p one to represent - * bits with value of @a true. The resulting string contains @ref size() characters - * with the first character corresponds to the last (@ref size() - 1th) bit and the - * last character corresponding to the first bit. - * - * @param[in] zero Character to use to represent @a false - * @param[in] one Character to use to represent @a true - * - * @tparam _CharT Character type of the string - * @tparam _Traits Traits class specifying the operations on the character type of the - * string - * @tparam _Alloc Allocator type used to allocate internal storage of the string - * - * @return The string representing the @ref sul::dynamic_bitset content - * - * @complexity Linear in the size of the @ref sul::dynamic_bitset. - * - * @since 1.0.0 - */ - template, - typename _Alloc = std::allocator<_CharT>> - [[nodiscard]] constexpr std::basic_string<_CharT, _Traits, _Alloc> to_string( - _CharT zero = _CharT('0'), - _CharT one = _CharT('1')) const; - - /** - * @brief Converts the contents of the bitset to an unsigned long integer. - * - * @details The first bit of the bitset corresponds to the least significant digit of the - * number and the last bit corresponds to the most significant digit. - * - * @return The numeric value corresponding to the bitset contents. - * - * @throws std::overflow_error if the value is too large to be represented in an unsigned - * long - * - * @complexity Constant. - * - * @since 1.3.0 - */ - [[nodiscard]] constexpr unsigned long to_ulong() const; - - /** - * @brief Converts the contents of the bitset to an unsigned long long integer. - * - * @details The first bit of the bitset corresponds to the least significant digit of the - * number and the last bit corresponds to the most significant digit. - * - * @return The numeric value corresponding to the bitset contents. - * - * @throws std::overflow_error if the value is too large to be represented in an unsigned long - * long - * - * @complexity Constant. - * - * @since 1.3.0 - */ - [[nodiscard]] constexpr unsigned long long to_ullong() const; - - /** - * @brief Iterate on the @ref sul::dynamic_bitset and call @p function with the position of - * the bits on. - * - * @details For each set bit, @p function is called as follow: - * @code - * std::invoke(std::forward(function), bit_pos, std::forward(parameters)...)) - * @endcode - * where @p bit_pos is the position of the current bit on. Thus @p function - * should take a size_t for the current set bit position as first argument, also @p - * parameters can be used to pass additional arguments to @p function when it is - * called by this method.\n\n @p function can return nothing or a bool, if it return - * a bool, the return value indicate if the iteration should continue, @a true to - * continue the iteration, @a false to stop, this make it easy to do an early exit. - * - * @param function Function to call on all bits on, take the current bit position as - * first argument and @p parameters as next arguments - * @param parameters Extra parameters for @p function - * - * @tparam Function Type of @p function, must take a size_t as first argument and @p - * Parameters as next arguments - * @tparam Parameters Type of @p parameters - * - * @complexity Linear in the size of the @ref sul::dynamic_bitset. - * - * @since 1.0.0 - */ - template - constexpr void iterate_bits_on(Function&& function, Parameters&&... parameters) const; - - /** - * @brief Return a pointer to the underlying array serving as blocks storage. - * - * @details The pointer is such that range [@ref data(); @ref data() + @ref num_blocks()) is - * always a valid range, even if the container is empty (@ref data() is not - * dereferenceable in that case). - * - * - * @post The bits past the end of the @ref sul::dynamic_bitset in the last block are - * guaranteed to be 0s, example: - * @code - * // random bitset of size 11 - * std::minstd_rand rand(std::random_device{}()); - * std::bernoulli_distribution dist; - * sul::dynamic_bitset bitset; - * for(size_t i = 0; i < 11; ++i) - * { - * bitset.push_back(dist(rand)); - * } - * - * // the bitset use 2 blocks of 8 bits - * // check that unused bits are set to 0 - * assert(*(bitset.data() + 1) >> 3 == 0); - * @endcode - * - * @remark If the @ref sul::dynamic_bitset is empty, this function may or may not return a - * null pointer. - * - * @return A pointer to the underlying array serving as blocks storage - * - * @complexity Constant. - * - * @since 1.2.0 - */ - [[nodiscard]] constexpr block_type* data() noexcept; - - /** - * @brief Return a pointer to the underlying array serving as blocks storage. - * - * @details The pointer is such that range [@ref data(); @ref data() + @ref num_blocks()) is - * always a valid range, even if the container is empty (@ref data() is not - * dereferenceable in that case). - * - * - * @post The bits past the end of the @ref sul::dynamic_bitset in the last block are - * guaranteed to be 0s, example: - * @code - * // random bitset of size 11 - * std::minstd_rand rand(std::random_device{}()); - * std::bernoulli_distribution dist; - * sul::dynamic_bitset bitset; - * for(size_t i = 0; i < 11; ++i) - * { - * bitset.push_back(dist(rand)); - * } - * - * // the bitset use 2 blocks of 8 bits - * // check that unused bits are set to 0 - * assert(*(bitset.data() + 1) >> 3 == 0); - * @endcode - * - * @remark If the @ref sul::dynamic_bitset is empty, this function may or may not return a - * null pointer. - * - * @return A pointer to the underlying array serving as blocks storage - * - * @complexity Constant. - * - * @since 1.2.0 - */ - [[nodiscard]] constexpr const block_type* data() const noexcept; - - /** - * @brief Test if two @ref sul::dynamic_bitset have the same content. - * - * @param[in] lhs The left hand side @ref sul::dynamic_bitset of the operator - * @param[in] rhs The right hand side @ref sul::dynamic_bitset of the operator - * - * @tparam Block_ Block type used by @p lhs and @p rhs for storing the bits - * @tparam Allocator_ Allocator type used by @p lhs and @p rhs for memory management - * - * @return @a true if they contain the same bits, @a false otherwise - * - * @complexity Linear in the size of the @ref sul::dynamic_bitset. - * - * @since 1.0.0 - */ - template - friend constexpr bool operator==(const dynamic_bitset& lhs, - const dynamic_bitset& rhs); - - /** - * @brief Test if @p lhs is "less than" @p rhs. The comparison of the two @ref - * dynamic_bitset is first on numbers their content represent and then on their - * size. - * - * @details The size comparison is necessary for the comparison operators to keep their - * properties. For example without the size comparison the "<=" operator (defined - * for "A <= B" by "!(B < A)") would no longer be antisymmetric (if A \<= B and B - * \<= A, then A == B) because @ref operator==() compare the @ref - * sul::dynamic_bitset as a container and not a number. For example with bitsets - * A(0011) and B(011), without the size comparison B \< A would be @a false, A \<= B - * would be @a true, B \<= A would be @a true, but A == B would be @a false, - * breaking the antisymmetric property of the operator. Thus, to respect the - * properties of the operators, the size is used as a secondary criteria for the - * comparison of @ref sul::dynamic_bitset which content represent the same number. - * Therefore, for the previous example with bitsets A(0011) and B(011), B \< A is @a - * true, A \<= B is @a false, B \<= A is @a true and A == B is @a false.\n\n If - * comparing bitsets @a A and @a B with the content of @a A representing the number - * @a a, and the content of @a B representing the number @a b, this operator would - * work as follow: - * @code - * if(a == b) - * { - * return A.size() < B.size(); - * } - * else - * { - * return a < b; - * } - * @endcode - * - * @remark The empty @ref sul::dynamic_bitset is the "lowest" of all bitset and for 0-only - * bitsets comparison, the shortest is the lowest. - * - * @param[in] lhs The left hand side @ref sul::dynamic_bitset of the operator - * @param[in] rhs The right hand side @ref sul::dynamic_bitset of the operator - * - * @tparam Block_ Block type used by @p lhs and @p rhs for storing the bits - * @tparam Allocator_ Allocator type used by @p lhs and @p rhs for memory management - * - * @return @a true if @p lhs is "less than" @p rhs - * - * @complexity Linear in the size of the @ref sul::dynamic_bitset. - * - * @since 1.0.0 - */ - template - friend constexpr bool operator<(const dynamic_bitset& lhs, - const dynamic_bitset& rhs); - -private: - template - struct dependent_false : public std::false_type - { - }; - - std::vector m_blocks; - size_type m_bits_number; - - static constexpr block_type zero_block = block_type(0); - static constexpr block_type one_block = block_type(~zero_block); - static constexpr size_type block_last_bit_index = bits_per_block - 1; - - static constexpr size_type blocks_required(size_type nbits) noexcept; - - static constexpr size_type block_index(size_type pos) noexcept; - static constexpr size_type bit_index(size_type pos) noexcept; - - static constexpr block_type bit_mask(size_type pos) noexcept; - static constexpr block_type bit_mask(size_type first, size_type last) noexcept; - - static constexpr void set_block_bits(block_type& block, - size_type first, - size_type last, - bool val = true) noexcept; - static constexpr void flip_block_bits(block_type& block, - size_type first, - size_type last) noexcept; - - static constexpr size_type block_count(const block_type& block) noexcept; - static constexpr size_type block_count(const block_type& block, size_type nbits) noexcept; - - static constexpr size_type count_block_trailing_zero(const block_type& block) noexcept; - - template - constexpr void init_from_string(std::basic_string_view<_CharT, _Traits> str, - typename std::basic_string_view<_CharT, _Traits>::size_type pos, - typename std::basic_string_view<_CharT, _Traits>::size_type n, - _CharT zero, - _CharT one); - - constexpr block_type& get_block(size_type pos); - constexpr const block_type& get_block(size_type pos) const; - constexpr block_type& last_block(); - constexpr block_type last_block() const; - - // used bits in the last block - constexpr size_type extra_bits_number() const noexcept; - // unused bits in the last block - constexpr size_type unused_bits_number() const noexcept; - - template - constexpr void apply(const dynamic_bitset& other, BinaryOperation binary_op); - template - constexpr void apply(UnaryOperation unary_op); - constexpr void apply_left_shift(size_type shift); - constexpr void apply_right_shift(size_type shift); - - // reset unused bits to 0 - constexpr void sanitize(); - - // check functions used in asserts - constexpr bool check_unused_bits() const noexcept; - constexpr bool check_size() const noexcept; - constexpr bool check_consistency() const noexcept; -}; - -// Deduction guideline for expressions like "dynamic_bitset a(32);" with an integral type as parameter -// to use the constructor with the initial size instead of the constructor with the allocator. -template>> -dynamic_bitset(integral_type) -> dynamic_bitset<>; - -//================================================================================================= -// dynamic_bitset external functions declarations -//================================================================================================= - -/** - * @brief Test if two @ref sul::dynamic_bitset content are different. - * - * @details Defined as: - * @code - * return !(lhs == rhs); - * @endcode - * see @ref sul::dynamic_bitset::operator==() for more informations. - * - * @param[in] lhs The left hand side @ref sul::dynamic_bitset of the operator - * @param[in] rhs The right hand side @ref sul::dynamic_bitset of the operator - * - * @tparam Block Block type used by @p lhs and @p rhs for storing the bits - * @tparam Allocator Allocator type used by @p lhs and @p rhs for memory management - * - * @return @a true if they does not contain the same bits, @a false otherwise - * - * @complexity Linear in the size of the @ref sul::dynamic_bitset. - * - * @since 1.0.0 - * - * @relatesalso dynamic_bitset - */ -template -constexpr bool operator!=(const dynamic_bitset& lhs, - const dynamic_bitset& rhs); - -/** - * @brief Test if @p lhs is "less than or equal to" @p rhs. The comparison of the two @ref - * sul::dynamic_bitset is first on numbers their content represent and then on their size. - * - * @details Defined as: - * @code - * return !(rhs < lhs); - * @endcode - * see @ref sul::dynamic_bitset::operator<() for more informations. - * - * @param[in] lhs The left hand side @ref sul::dynamic_bitset of the operator - * @param[in] rhs The right hand side @ref sul::dynamic_bitset of the operator - * - * @tparam Block Block type used by @p lhs and @p rhs for storing the bits - * @tparam Allocator Allocator type used by @p lhs and @p rhs for memory management - * - * @return @a true if @p lhs is "less than or equal to" @p rhs - * - * @complexity Linear in the size of the @ref sul::dynamic_bitset. - * - * @since 1.0.0 - * - * @relatesalso dynamic_bitset - */ -template -constexpr bool operator<=(const dynamic_bitset& lhs, - const dynamic_bitset& rhs); - -/** - * @brief Test if @p lhs is "greater than" @p rhs. The comparison of the two @ref - * sul::dynamic_bitset is first on numbers their content represent and then on their - * size. - * - * @details Defined as: - * @code - * return rhs < lhs; - * @endcode - * see @ref sul::dynamic_bitset::operator<() for more informations. - * - * @param[in] lhs The left hand side @ref sul::dynamic_bitset of the operator - * @param[in] rhs The right hand side @ref sul::dynamic_bitset of the operator - * - * @tparam Block Block type used by @p lhs and @p rhs for storing the bits - * @tparam Allocator Allocator type used by @p lhs and @p rhs for memory management - * - * @return @a true if @p lhs is "greater than" @p rhs - * - * @complexity Linear in the size of the @ref sul::dynamic_bitset. - * - * @since 1.0.0 - * - * @relatesalso dynamic_bitset - */ -template -constexpr bool operator>(const dynamic_bitset& lhs, - const dynamic_bitset& rhs); - -/** - * @brief Test if @p lhs is "greater than or equal to" @p rhs. The comparison of the two @ref - * sul::dynamic_bitset is first on numbers their content represent and then on their - * size. - * - * @details Defined as: - * @code - * return !(lhs < rhs); - * @endcode - * see @ref sul::dynamic_bitset::operator<() for more informations. - * - * @param[in] lhs The left hand side @ref sul::dynamic_bitset of the operator - * @param[in] rhs The right hand side @ref sul::dynamic_bitset of the operator - * - * @tparam Block Block type used by @p lhs and @p rhs for storing the bits - * @tparam Allocator Allocator type used by @p lhs and @p rhs for memory management - * - * @return @a true if @p lhs is "greater than or equal to" @p rhs - * - * @complexity Linear in the size of the @ref sul::dynamic_bitset. - * - * @since 1.0.0 - * - * @relatesalso dynamic_bitset - */ -template -constexpr bool operator>=(const dynamic_bitset& lhs, - const dynamic_bitset& rhs); - -/** - * @brief Performs binary AND on corresponding pairs of bits of @p lhs and @p rhs. - * - * @details Defined as: - * @code - * dynamic_bitset result(lhs); - * return result &= rhs; - * @endcode - * see @ref sul::dynamic_bitset::operator&=() for more informations. - * - * @param[in] lhs The left hand side @ref sul::dynamic_bitset of the operator - * @param[in] rhs The right hand side @ref sul::dynamic_bitset of the operator - * - * @tparam Block Block type used by @p lhs and @p rhs for storing the bits - * @tparam Allocator Allocator type used by @p lhs and @p rhs for memory management - * - * @return A @ref sul::dynamic_bitset with each bit being the result of a binary AND between the - * corresponding pair of bits of @p lhs and @p rhs - * - * @pre @code - * lhs.size() == rhs.size() - * @endcode - * - * @complexity Linear in the size of the @ref sul::dynamic_bitset. - * - * @since 1.0.0 - * - * @relatesalso dynamic_bitset - */ -template -constexpr dynamic_bitset operator&(const dynamic_bitset& lhs, - const dynamic_bitset& rhs); - -/** - * @brief Performs binary OR on corresponding pairs of bits of @p lhs and @p rhs. - * - * @details Defined as: - * @code - * dynamic_bitset result(lhs); - * return result |= rhs; - * @endcode - * see @ref sul::dynamic_bitset::operator|=() for more informations. - * - * @param[in] lhs The left hand side @ref sul::dynamic_bitset of the operator - * @param[in] rhs The right hand side @ref sul::dynamic_bitset of the operator - * - * @tparam Block Block type used by @p lhs and @p rhs for storing the bits - * @tparam Allocator Allocator type used by @p lhs and @p rhs for memory management - * - * @return A @ref sul::dynamic_bitset with each bit being the result of a binary OR between the - * corresponding pair of bits of @p lhs and @p rhs - * - * @pre @code - * lhs.size() == rhs.size() - * @endcode - * - * @complexity Linear in the size of the @ref sul::dynamic_bitset. - * - * @since 1.0.0 - * - * @relatesalso dynamic_bitset - */ -template -constexpr dynamic_bitset operator|(const dynamic_bitset& lhs, - const dynamic_bitset& rhs); - -/** - * @brief Performs binary XOR on corresponding pairs of bits of @p lhs and @p rhs. - * - * @details Defined as: - * @code - * dynamic_bitset result(lhs); - * return result ^= rhs; - * @endcode - * see @ref sul::dynamic_bitset::operator^=() for more informations. - * - * @param[in] lhs The left hand side @ref sul::dynamic_bitset of the operator - * @param[in] rhs The right hand side @ref sul::dynamic_bitset of the operator - * - * @tparam Block Block type used by @p lhs and @p rhs for storing the bits - * @tparam Allocator Allocator type used by @p lhs and @p rhs for memory management - * - * @return A @ref sul::dynamic_bitset with each bit being the result of a binary XOR between the - * corresponding pair of bits of @p lhs and @p rhs - * - * @pre @code - * lhs.size() == rhs.size() - * @endcode - * - * @complexity Linear in the size of the @ref sul::dynamic_bitset. - * - * @since 1.0.0 - * - * @relatesalso dynamic_bitset - */ -template -constexpr dynamic_bitset operator^(const dynamic_bitset& lhs, - const dynamic_bitset& rhs); - -/** - * @brief Performs binary difference between bits of @p lhs and @p rhs. - * - * @details Defined as: - * @code - * dynamic_bitset result(lhs); - * return result -= rhs; - * @endcode - * see @ref sul::dynamic_bitset::operator-=() for more informations. - * - * @param[in] lhs The left hand side @ref sul::dynamic_bitset of the operator - * @param[in] rhs The right hand side @ref sul::dynamic_bitset of the operator - * - * @tparam Block Block type used by @p lhs and @p rhs for storing the bits - * @tparam Allocator Allocator type used by @p lhs and @p rhs for memory management - * - * @return A @ref sul::dynamic_bitset with each bit being the result of the binary difference - * between the corresponding bits of @p lhs and @p rhs - * - * @pre @code - * lhs.size() == rhs.size() - * @endcode - * - * @complexity Linear in the size of the @ref sul::dynamic_bitset. - * - * @since 1.0.0 - * - * @relatesalso dynamic_bitset - */ -template -constexpr dynamic_bitset operator-(const dynamic_bitset& lhs, - const dynamic_bitset& rhs); - -/** - * @brief Insert a string representation of this @ref sul::dynamic_bitset to a character - * stream. - * - * @details The string representation written is the same as if generated with @ref - * sul::dynamic_bitset::to_string() with default parameter, using '1' for @a true bits - * and '0' for @a false bits. - * - * @param os Character stream to write to - * @param[in] bitset @ref sul::dynamic_bitset to write - * - * @tparam _CharT Character type of the character stream - * @tparam _Traits Traits class specifying the operations on the character type of the - * character stream - * @tparam Block Block type used by @p bitset for storing the bits - * @tparam Allocator Allocator type used by @p bitset for memory management - * - * @return @p os - * - * @complexity Linear in the size of the @ref sul::dynamic_bitset. - * - * @since 1.0.0 - * - * @relatesalso dynamic_bitset - */ -template -constexpr std::basic_ostream<_CharT, _Traits>& operator<<( - std::basic_ostream<_CharT, _Traits>& os, - const dynamic_bitset& bitset); - -/** - * @brief Extract a @ref sul::dynamic_bitset from a character stream using its string - * representation. - * - * @details The string representation expected is the same as if generated with @ref - * sul::dynamic_bitset::to_string() with default parameter, using '1' for @a true bits - * and '0' for @a false bits. On success the content of @p bitset is cleared before - * writing to it. The extraction starts by skipping leading whitespace then take the - * characters one by one and stop if @p is.good() return @a false or the next character - * is neither _CharT('0') nor _CharT('1'). - * - * @param is Character stream to read from - * @param bitset @ref sul::dynamic_bitset to write to - * - * @tparam _CharT Character type of the character stream - * @tparam _Traits Traits class specifying the operations on the character type of the - * character stream - * @tparam Block Block type used by @p bitset for storing the bits - * @tparam Allocator Allocator type used by @p bitset for memory management - * - * @return @p is - * - * @complexity Linear in the size of the @ref sul::dynamic_bitset. - * - * @since 1.0.0 - * - * @relatesalso dynamic_bitset - */ -template -constexpr std::basic_istream<_CharT, _Traits>& operator>>(std::basic_istream<_CharT, _Traits>& is, - dynamic_bitset& bitset); - -/** - * @brief Exchange the content of @p bitset1 and @p bitset2. - * - * @details Defined as: - * @code - * bitset1.swap(bitset2); - * @endcode - * see @ref sul::dynamic_bitset::swap() for more informations. - * - * @param bitset1 @ref sul::dynamic_bitset to be swapped - * @param bitset2 @ref sul::dynamic_bitset to be swapped - * - * @tparam Block Block type used by @p bitset for storing the bits - * @tparam Allocator Allocator type used by @p bitset for memory management - * - * @complexity Constant. - * - * @since 1.0.0 - * - * @relatesalso dynamic_bitset - */ -template -constexpr void swap(dynamic_bitset& bitset1, - dynamic_bitset& bitset2); - -//================================================================================================= -// dynamic_bitset::reference functions implementations -//================================================================================================= - -template -constexpr dynamic_bitset::reference::reference( - dynamic_bitset& bitset, - size_type bit_pos) - : m_block(bitset.get_block(bit_pos)), m_mask(dynamic_bitset::bit_mask(bit_pos)) -{ -} - -template -constexpr typename dynamic_bitset::reference& dynamic_bitset:: - reference::operator=(bool v) -{ - assign(v); - return *this; -} - -template -constexpr typename dynamic_bitset::reference& dynamic_bitset:: - reference::operator=(const dynamic_bitset::reference& rhs) -{ - assign(rhs); - return *this; -} - -template -constexpr typename dynamic_bitset::reference& dynamic_bitset:: - reference::operator=(dynamic_bitset::reference&& rhs) noexcept -{ - assign(rhs); - return *this; -} - -template -constexpr typename dynamic_bitset::reference& dynamic_bitset:: - reference::operator&=(bool v) -{ - if(!v) - { - reset(); - } - return *this; -} - -template -constexpr typename dynamic_bitset::reference& dynamic_bitset:: - reference::operator|=(bool v) -{ - if(v) - { - set(); - } - return *this; -} - -template -constexpr typename dynamic_bitset::reference& dynamic_bitset:: - reference::operator^=(bool v) -{ - if(v) - { - flip(); - } - return *this; -} - -template -constexpr typename dynamic_bitset::reference& dynamic_bitset:: - reference::operator-=(bool v) -{ - if(v) - { - reset(); - } - return *this; -} - -template -constexpr bool dynamic_bitset::reference::operator~() const -{ - return (m_block & m_mask) == zero_block; -} - -template -constexpr dynamic_bitset::reference::operator bool() const -{ - return (m_block & m_mask) != zero_block; -} - -template -constexpr typename dynamic_bitset::reference& dynamic_bitset:: - reference::set() -{ - m_block |= m_mask; - return *this; -} - -template -constexpr typename dynamic_bitset::reference& dynamic_bitset:: - reference::reset() -{ - m_block &= static_cast(~m_mask); - return *this; -} - -template -constexpr typename dynamic_bitset::reference& dynamic_bitset:: - reference::flip() -{ - m_block ^= m_mask; - return *this; -} - -template -constexpr typename dynamic_bitset::reference& dynamic_bitset:: - reference::assign(bool v) -{ - if(v) - { - set(); - } - else - { - reset(); - } - return *this; -} - -//================================================================================================= -// dynamic_bitset public functions implementations -//================================================================================================= - -template -constexpr dynamic_bitset::dynamic_bitset(const allocator_type& allocator) - : m_blocks(allocator), m_bits_number(0) -{ -} - -template -constexpr dynamic_bitset::dynamic_bitset(size_type nbits, - unsigned long long init_val, - const allocator_type& allocator) - : m_blocks(blocks_required(nbits), allocator), m_bits_number(nbits) -{ - if(nbits == 0 || init_val == 0) - { - return; - } - - constexpr size_t ull_bits_number = std::numeric_limits::digits; - constexpr size_t init_val_required_blocks = ull_bits_number / bits_per_block; - if constexpr(init_val_required_blocks == 1) - { - m_blocks[0] = init_val; - } - else - { - const unsigned long long block_mask = static_cast(one_block); - const size_t blocks_to_init = std::min(m_blocks.size(), init_val_required_blocks); - for(size_t i = 0; i < blocks_to_init; ++i) - { - m_blocks[i] = block_type((init_val >> (i * bits_per_block) & block_mask)); - } - } - sanitize(); -} - -template -constexpr dynamic_bitset::dynamic_bitset( - std::initializer_list init_vals, - const allocator_type& allocator) - : m_blocks(allocator), m_bits_number(0) -{ - append(init_vals); -} - -template -template -constexpr dynamic_bitset::dynamic_bitset( - std::basic_string_view<_CharT, _Traits> str, - typename std::basic_string_view<_CharT, _Traits>::size_type pos, - typename std::basic_string_view<_CharT, _Traits>::size_type n, - _CharT zero, - _CharT one, - const allocator_type& allocator) - : m_blocks(allocator), m_bits_number(0) -{ - assert(pos < str.size()); - init_from_string(str, pos, n, zero, one); -} - -template -template -constexpr dynamic_bitset::dynamic_bitset( - const std::basic_string<_CharT, _Traits, _Alloc>& str, - typename std::basic_string<_CharT, _Traits, _Alloc>::size_type pos, - typename std::basic_string<_CharT, _Traits, _Alloc>::size_type n, - _CharT zero, - _CharT one, - const allocator_type& allocator) - : m_blocks(allocator), m_bits_number(0) -{ - assert(pos < str.size()); - init_from_string(std::basic_string_view<_CharT, _Traits>(str), pos, n, zero, one); -} - -template -template -constexpr dynamic_bitset::dynamic_bitset( - const _CharT* str, - typename std::basic_string<_CharT>::size_type pos, - typename std::basic_string<_CharT>::size_type n, - _CharT zero, - _CharT one, - const allocator_type& allocator) - : m_blocks(allocator), m_bits_number(0) -{ - init_from_string(std::basic_string_view<_CharT, _Traits>(str), pos, n, zero, one); -} - -template -constexpr void dynamic_bitset::resize(size_type nbits, bool value) -{ - if(nbits == m_bits_number) - { - return; - } - - const size_type old_num_blocks = num_blocks(); - const size_type new_num_blocks = blocks_required(nbits); - - const block_type init_value = value ? one_block : zero_block; - if(new_num_blocks != old_num_blocks) - { - m_blocks.resize(new_num_blocks, init_value); - } - - if(value && nbits > m_bits_number && old_num_blocks > 0) - { - // set value of the new bits in the old last block - const size_type extra_bits = extra_bits_number(); - if(extra_bits > 0) - { - m_blocks[old_num_blocks - 1] |= static_cast(init_value << extra_bits); - } - } - - m_bits_number = nbits; - sanitize(); - assert(check_consistency()); -} - -template -constexpr void dynamic_bitset::clear() -{ - m_blocks.clear(); - m_bits_number = 0; -} - -template -constexpr void dynamic_bitset::push_back(bool value) -{ - const size_type new_last_bit = m_bits_number++; - if(m_bits_number <= m_blocks.size() * bits_per_block) - { - if(value) - { - set(new_last_bit, value); - } - } - else - { - m_blocks.push_back(block_type(value)); - } - assert(operator[](new_last_bit) == value); - assert(check_consistency()); -} - -template -constexpr void dynamic_bitset::pop_back() -{ - if(empty()) - { - return; - } - - --m_bits_number; - if(m_blocks.size() > blocks_required(m_bits_number)) - { - m_blocks.pop_back(); - // no extra bits: sanitize not required - assert(extra_bits_number() == 0); - } - else - { - sanitize(); - } - assert(check_consistency()); -} - -template -constexpr void dynamic_bitset::append(block_type block) -{ - const size_type extra_bits = extra_bits_number(); - if(extra_bits == 0) - { - m_blocks.push_back(block); - } - else - { - last_block() |= static_cast(block << extra_bits); - m_blocks.push_back(block_type(block >> (bits_per_block - extra_bits))); - } - - m_bits_number += bits_per_block; - assert(check_consistency()); -} - -template -constexpr void dynamic_bitset::append(std::initializer_list blocks) -{ - if(blocks.size() == 0) - { - return; - } - - append(std::cbegin(blocks), std::cend(blocks)); -} - -template -template -constexpr void dynamic_bitset::append(BlockInputIterator first, - BlockInputIterator last) -{ - if(first == last) - { - return; - } - - // if random access iterators, std::distance complexity is constant - if constexpr(std::is_same_v< - typename std::iterator_traits::iterator_category, - std::random_access_iterator_tag>) - { - assert(std::distance(first, last) > 0); - m_blocks.reserve(m_blocks.size() + static_cast(std::distance(first, last))); - } - - const size_type extra_bits = extra_bits_number(); - const size_type unused_bits = unused_bits_number(); - if(extra_bits == 0) - { - auto pos = m_blocks.insert(std::end(m_blocks), first, last); - assert(std::distance(pos, std::end(m_blocks)) > 0); - m_bits_number += - static_cast(std::distance(pos, std::end(m_blocks))) * bits_per_block; - } - else - { - last_block() |= static_cast(*first << extra_bits); - block_type block = block_type(*first >> unused_bits); - ++first; - while(first != last) - { - block |= static_cast(*first << extra_bits); - m_blocks.push_back(block); - m_bits_number += bits_per_block; - block = block_type(*first >> unused_bits); - ++first; - } - m_blocks.push_back(block); - m_bits_number += bits_per_block; - } - - assert(check_consistency()); -} -template -constexpr dynamic_bitset& dynamic_bitset::operator&=( - const dynamic_bitset& rhs) -{ - assert(size() == rhs.size()); - //apply(rhs, std::bit_and()); - for(size_type i = 0; i < m_blocks.size(); ++i) - { - m_blocks[i] &= rhs.m_blocks[i]; - } - return *this; -} - -template -constexpr dynamic_bitset& dynamic_bitset::operator|=( - const dynamic_bitset& rhs) -{ - assert(size() == rhs.size()); - //apply(rhs, std::bit_or()); - for(size_type i = 0; i < m_blocks.size(); ++i) - { - m_blocks[i] |= rhs.m_blocks[i]; - } - return *this; -} - -template -constexpr dynamic_bitset& dynamic_bitset::operator^=( - const dynamic_bitset& rhs) -{ - assert(size() == rhs.size()); - //apply(rhs, std::bit_xor()); - for(size_type i = 0; i < m_blocks.size(); ++i) - { - m_blocks[i] ^= rhs.m_blocks[i]; - } - return *this; -} - -template -constexpr dynamic_bitset& dynamic_bitset::operator-=( - const dynamic_bitset& rhs) -{ - assert(size() == rhs.size()); - //apply(rhs, [](const block_type& x, const block_type& y) { return (x & ~y); }); - for(size_type i = 0; i < m_blocks.size(); ++i) - { - m_blocks[i] &= static_cast(~rhs.m_blocks[i]); - } - return *this; -} - -template -constexpr dynamic_bitset& dynamic_bitset::operator<<=( - size_type shift) -{ - if(shift != 0) - { - if(shift >= m_bits_number) - { - reset(); - } - else - { - apply_left_shift(shift); - sanitize(); // unused bits can have changed, reset them to 0 - } - } - return *this; -} - -template -constexpr dynamic_bitset& dynamic_bitset::operator>>=( - size_type shift) -{ - if(shift != 0) - { - if(shift >= m_bits_number) - { - reset(); - } - else - { - apply_right_shift(shift); - } - } - return *this; -} - -template -constexpr dynamic_bitset dynamic_bitset::operator<<( - size_type shift) const -{ - return dynamic_bitset(*this) <<= shift; -} - -template -constexpr dynamic_bitset dynamic_bitset::operator>>( - size_type shift) const -{ - return dynamic_bitset(*this) >>= shift; -} - -template -constexpr dynamic_bitset dynamic_bitset::operator~() const -{ - dynamic_bitset bitset(*this); - bitset.flip(); - return bitset; -} - -template -constexpr dynamic_bitset& dynamic_bitset::set(size_type pos, - size_type len, - bool value) -{ - assert(pos < size()); - if(len == 0) - { - return *this; - } - assert(pos + len - 1 < size()); - - const size_type first_block = block_index(pos); - const size_type last_block = block_index(pos + len - 1); - const size_type first_bit_index = bit_index(pos); - const size_type last_bit_index = bit_index(pos + len - 1); - - if(first_block == last_block) - { - set_block_bits(m_blocks[first_block], first_bit_index, last_bit_index, value); - } - else - { - size_type first_full_block = first_block; - size_type last_full_block = last_block; - - if(first_bit_index != 0) - { - ++first_full_block; // first block is not full - set_block_bits(m_blocks[first_block], first_bit_index, block_last_bit_index, value); - } - - if(last_bit_index != block_last_bit_index) - { - --last_full_block; // last block is not full - set_block_bits(m_blocks[last_block], 0, last_bit_index, value); - } - - const block_type full_block = value ? one_block : zero_block; - for(size_type i = first_full_block; i <= last_full_block; ++i) - { - m_blocks[i] = full_block; - } - } - - return *this; -} - -template -constexpr dynamic_bitset& dynamic_bitset::set(size_type pos, - bool value) -{ - assert(pos < size()); - - if(value) - { - m_blocks[block_index(pos)] |= bit_mask(pos); - } - else - { - m_blocks[block_index(pos)] &= static_cast(~bit_mask(pos)); - } - - return *this; -} - -template -constexpr dynamic_bitset& dynamic_bitset::set() -{ - std::fill(std::begin(m_blocks), std::end(m_blocks), one_block); - sanitize(); - return *this; -} - -template -constexpr dynamic_bitset& dynamic_bitset::reset(size_type pos, - size_type len) -{ - return set(pos, len, false); -} - -template -constexpr dynamic_bitset& dynamic_bitset::reset(size_type pos) -{ - return set(pos, false); -} - -template -constexpr dynamic_bitset& dynamic_bitset::reset() -{ - std::fill(std::begin(m_blocks), std::end(m_blocks), zero_block); - return *this; -} - -template -constexpr dynamic_bitset& dynamic_bitset::flip(size_type pos, - size_type len) -{ - assert(pos < size()); - if(len == 0) - { - return *this; - } - assert(pos + len - 1 < size()); - - const size_type first_block = block_index(pos); - const size_type last_block = block_index(pos + len - 1); - const size_type first_bit_index = bit_index(pos); - const size_type last_bit_index = bit_index(pos + len - 1); - - if(first_block == last_block) - { - flip_block_bits(m_blocks[first_block], first_bit_index, last_bit_index); - } - else - { - size_type first_full_block = first_block; - size_type last_full_block = last_block; - - if(first_bit_index != 0) - { - ++first_full_block; // first block is not full - flip_block_bits(m_blocks[first_block], first_bit_index, block_last_bit_index); - } - - if(last_bit_index != block_last_bit_index) - { - --last_full_block; // last block is not full - flip_block_bits(m_blocks[last_block], 0, last_bit_index); - } - - for(size_type i = first_full_block; i <= last_full_block; ++i) - { - m_blocks[i] = block_type(~m_blocks[i]); - } - } - - return *this; -} - -template -constexpr dynamic_bitset& dynamic_bitset::flip(size_type pos) -{ - assert(pos < size()); - m_blocks[block_index(pos)] ^= bit_mask(pos); - return *this; -} - -template -constexpr dynamic_bitset& dynamic_bitset::flip() -{ - std::transform( - std::cbegin(m_blocks), std::cend(m_blocks), std::begin(m_blocks), std::bit_not()); - sanitize(); - return *this; -} - -template -constexpr bool dynamic_bitset::test(size_type pos) const -{ - assert(pos < size()); - return (m_blocks[block_index(pos)] & bit_mask(pos)) != zero_block; -} - -template -constexpr bool dynamic_bitset::test_set(size_type pos, bool value) -{ - bool const result = test(pos); - if(result != value) - { - set(pos, value); - } - return result; -} - -template -constexpr bool dynamic_bitset::all() const -{ - if(empty()) - { - return true; - } - - const block_type full_block = one_block; - if(extra_bits_number() == 0) - { - for(const block_type& block: m_blocks) - { - if(block != full_block) - { - return false; - } - } - } - else - { - for(size_type i = 0; i < m_blocks.size() - 1; ++i) - { - if(m_blocks[i] != full_block) - { - return false; - } - } - if(last_block() != (full_block >> unused_bits_number())) - { - return false; - } - } - return true; -} - -template -constexpr bool dynamic_bitset::any() const -{ - for(const block_type& block: m_blocks) - { - if(block != zero_block) - { - return true; - } - } - return false; -} - -template -constexpr bool dynamic_bitset::none() const -{ - return !any(); -} - -template -constexpr typename dynamic_bitset::size_type dynamic_bitset::count() - const noexcept -{ - if(empty()) - { - return 0; - } + /** + * @brief Dynamic bitset. + * + * @details Data structure used to store a vector of bits and apply binary operations to it. The + * bits are stored in an optimized way in an underling block type. It is highly inspired + * by std\::bitset but with a run-time changeable size. + * + * Preconditions are checked with @a assert but no exception will be thrown if one is + * violated (as with std\::bitset). + * + * @remark It is not a Container as it does not provide iterators because of the reference proxy + * class used to access the bits. + * + * @tparam Block Block type to use for storing the bits, must be an unsigned integral type + * @tparam Allocator Allocator type to use for memory management, must meet the standard + * requirements of @a Allocator + * + * @since 1.0.0 + */ + template> + class dynamic_bitset + { + static_assert(std::is_unsigned::value, "Block is not an unsigned integral type"); + + public: + /** + * @brief Type used to represent the size of a @ref sul::dynamic_bitset. + * + * @since 1.0.0 + */ + typedef size_t size_type; + + /** + * @brief Same type as @p Block. + * + * @since 1.0.0 + */ + typedef Block block_type; + + /** + * @brief Same type as @p Allocator. + * + * @since 1.0.0 + */ + typedef Allocator allocator_type; + + /** + * @brief Number of bits that can be stored in a block. + * + * @since 1.0.0 + */ + static constexpr size_type bits_per_block = std::numeric_limits::digits; + + /** + * @brief Maximum value of @ref size_type, returned for invalid positions. + * + * @since 1.0.0 + */ + static constexpr size_type npos = std::numeric_limits::max(); + + /** + * @brief Reference to a @ref sul::dynamic_bitset bit. + * + * @details As the bits in the @ref sul::dynamic_bitset class are stored in an optimized way + * in blocks, it is not possible for the subscript operators to return a reference + * to a boolean. Hence this class is used as a proxy to enable subscript operator of + * the @ref sul::dynamic_bitset class to be used as if it was an array of bools. + * + * @since 1.0.0 + */ + class reference + { + public: + /** + * @brief Constructs a @ref reference to a bit from a @ref sul::dynamic_bitset and a + * bit position. + * + * @param bitset @ref sul::dynamic_bitset containing the bit + * @param[in] bit_pos Position of the bit to reference in the @ref sul::dynamic_bitset + * + * @complexity Constant. + * + * @since 1.0.0 + */ + constexpr reference(dynamic_bitset& bitset, size_type bit_pos); + + /** + * @brief Copy constructor. + * + * @since 1.0.0 + */ + constexpr reference(const reference&) noexcept = default; + + /** + * @brief Move constructor. + * + * @since 1.0.0 + */ + constexpr reference(reference&&) noexcept = default; + + /** + * @brief Destructor. + * + * @since 1.0.0 + */ + ~reference() noexcept = default; + + /** + * @brief Assign a value to the referenced bit. + * + * @param[in] v Value to assign to the referenced bit + * + * @return The @ref reference + * + * @complexity Constant. + * + * @since 1.0.0 + */ + constexpr reference& operator=(bool v); + + /** + * @brief Assign a value to the referenced bit from another @ref reference. + * + * @param[in] rhs @ref reference to the bit to assign value from + * + * @return The @ref reference + * + * @complexity Constant. + * + * @since 1.0.0 + */ + constexpr reference& operator=(const reference& rhs); + + /** + * @brief Assign a value to the referenced bit from another @ref reference. + * + * @param[in] rhs @ref reference to the bit to assign value from + * + * @return The @ref reference + * + * @complexity Constant. + * + * @since 1.0.0 + */ + constexpr reference& operator=(reference&& rhs) noexcept; + + /** + * @brief Apply binary operator AND to the referenced bit and a value, and assign the + * result to the referenced bit. + * + * @param[in] v Value to apply binary operator AND with + * + * @return The @ref reference + * + * @complexity Constant. + * + * @since 1.0.0 + */ + constexpr reference& operator&=(bool v); + + /** + * @brief Apply binary operator OR to the referenced bit and a value, and assign the + * result to the referenced bit. + * + * @param[in] v Value to apply binary operator OR with + * + * @return The @ref reference + * + * @complexity Constant. + * + * @since 1.0.0 + */ + constexpr reference& operator|=(bool v); + + /** + * @brief Apply binary operator XOR to the referenced bit and a value, and assign the + * result to the referenced bit. + * + * @param[in] v Value to apply binary operator XOR with + * + * @return The @ref reference + * + * @complexity Constant. + * + * @since 1.0.0 + */ + constexpr reference& operator^=(bool v); + + /** + * @brief Apply binary difference to the referenced bit and a value, and assign the + * result to the referenced bit. + * + * @details Equivalent to: + * @code + * this &= !v; + * @endcode + * + * @param[in] v Value to apply binary difference with + * + * @return The @ref reference + * + * @complexity Constant. + * + * @since 1.0.0 + */ + constexpr reference& operator-=(bool v); + + /** + * @brief Return the result of applying unary NOT operator. + * + * @return The opposite of the referenced bit + * + * @complexity Constant. + * + * @since 1.0.0 + */ + [[nodiscard]] constexpr bool operator~() const; + + /** + * @brief bool conversion operator. + * + * @complexity Constant. + * + * @since 1.0.0 + */ + [[nodiscard]] constexpr operator bool() const; + + /** + * @brief Deleted to avoid taking the address of a temporary proxy object. + * + * @since 1.0.0 + */ + constexpr void operator&() = delete; + + /** + * @brief Set the referenced bit to @a true. + * + * @return The @ref reference + * + * @complexity Constant. + * + * @since 1.0.0 + */ + constexpr reference& set(); + + /** + * @brief Reset the referenced bit to @a false. + * + * @return The @ref reference + * + * @complexity Constant. + * + * @since 1.0.0 + */ + constexpr reference& reset(); + + /** + * @brief Flip the referenced bit. + * + * @return The @ref reference + * + * @complexity Constant. + * + * @since 1.0.0 + */ + constexpr reference& flip(); + + /** + * @brief Assign the value @p v to the referenced bit. + * + * @param[in] v Value to assign to the bit + * + * @return The @ref reference + * + * @complexity Constant. + * + * @since 1.0.0 + */ + constexpr reference& assign(bool v); + + private: + block_type& m_block; + block_type m_mask; + }; + + /** + * @brief Const reference to a @ref sul::dynamic_bitset bit, type bool. + * + * @since 1.0.0 + */ + typedef bool const_reference; + + /** + * @brief Copy constructor. + * + * @since 1.0.0 + */ + constexpr dynamic_bitset(const dynamic_bitset& other) = default; + + /** + * @brief Move constructor. + * + * @since 1.0.0 + */ + constexpr dynamic_bitset(dynamic_bitset&& other) noexcept = default; + + /** + * @brief Copy assignment operator. + * + * @since 1.0.0 + */ + constexpr dynamic_bitset& operator=(const dynamic_bitset& other) = default; + + /** + * @brief Move assignment operator. + * + * @since 1.0.0 + */ + constexpr dynamic_bitset& + operator=(dynamic_bitset&& other) noexcept = default; + + /** + * @brief Constructs an empty @ref sul::dynamic_bitset. + * + * @details A copy of @p allocator will be used for memory management. + * + * @param[in] allocator Allocator to use for memory management + * + * @complexity Constant. + * + * @since 1.0.0 + */ + constexpr explicit dynamic_bitset(const allocator_type& allocator = allocator_type()); + + /** + * @brief Constructs a @ref sul::dynamic_bitset of @p nbits bits from an initial value. + * + * @details The first bits are initialized with the bits from @p init_val, if @p nbits \> + * std\::numeric_limits\\::digits , all other bits are + * initialized to @a false. A copy of @p allocator will be used for memory + * management. + * + * @param[in] nbits Number of bits of the @ref sul::dynamic_bitset + * @param[in] init_val Value to initialize the @ref sul::dynamic_bitset with + * @param[in] allocator Allocator to use for memory management + * + * @complexity Linear in @p nbits / @ref bits_per_block. + * + * @since 1.0.0 + */ + constexpr explicit dynamic_bitset(size_type nbits, + unsigned long long init_val = 0, + const allocator_type& allocator = allocator_type()); + + /** + * @brief Constructs a @ref sul::dynamic_bitset using @p init_vals to initialize the first + * blocks. + * + * @details The size of the newly created @ref sul::dynamic_bitset is @p init_vals.size() * + * @ref bits_per_block. A copy of @p allocator will be used for memory management. + * + * @param[in] init_vals Value of the @ref sul::dynamic_bitset first blocks + * @param[in] allocator Allocator to use for memory management + * + * @complexity Linear in @p init_vals.size(). + * + * @since 1.0.0 + */ + constexpr dynamic_bitset(std::initializer_list init_vals, + const allocator_type& allocator = allocator_type()); + + /** + * @brief Constructs a @ref sul::dynamic_bitset from a string or a part of a string. + * + * @details Construct the @ref sul::dynamic_bitset using the characters from @p str in the + * range \[@p pos, std\::min(@p pos + @p n, @p str.size())\[. + * + * @param[in] str String containing the part to use + * @param[in] pos Starting position of the string part to use in @p str + * @param[in] n Number of characters of @p str to use from the starting position + * @param[in] zero Character used to represent @a false bits in @p str + * @param[in] one Character used to represent @a true bits in @p str + * @param[in] allocator Allocator to use for memory management + * + * @tparam _CharT Character type of the string + * @tparam _Traits Traits class specifying the operations on the character type of the + * string + * + * @pre @code + * pos < str.size() + * @endcode + * + * @complexity Linear in std\::min(@p n, @p str.size() - @p pos). + * + * @since 1.0.0 + */ + template + constexpr explicit dynamic_bitset( + std::basic_string_view<_CharT, _Traits> str, + typename std::basic_string_view<_CharT, _Traits>::size_type pos = 0, + typename std::basic_string_view<_CharT, _Traits>::size_type n = std::basic_string_view<_CharT, _Traits>::npos, + _CharT zero = _CharT('0'), + _CharT one = _CharT('1'), + const allocator_type& allocator = allocator_type()); + + /** + * @brief Constructs a @ref sul::dynamic_bitset from a string or a part of a string. + * + * @details Construct the @ref sul::dynamic_bitset using the characters from @p str in the + * range \[@p pos, std\::min(@p pos + @p n, @p str.size())\[. + * + * @param[in] str String containing the part to use + * @param[in] pos Starting position of the string part to use in @p str + * @param[in] n Number of characters of @p str to use from the starting position + * @param[in] zero Character used to represent @a false bits in @p str + * @param[in] one Character used to represent @a true bits in @p str + * @param[in] allocator Allocator to use for memory management + * + * @tparam _CharT Character type of the string + * @tparam _Traits Traits class specifying the operations on the character type of the + * string + * @tparam _Alloc Allocator type used to allocate internal storage of the string + * + * @pre @code + * pos < str.size() + * @endcode + * + * @complexity Linear in std\::min(@p n, @p str.size() - @p pos). + * + * @since 1.0.0 + */ + template + constexpr explicit dynamic_bitset(const std::basic_string<_CharT, _Traits, _Alloc>& str, + typename std::basic_string<_CharT, _Traits, _Alloc>::size_type pos = 0, + typename std::basic_string<_CharT, _Traits, _Alloc>::size_type n = + std::basic_string<_CharT, _Traits, _Alloc>::npos, + _CharT zero = _CharT('0'), + _CharT one = _CharT('1'), + const allocator_type& allocator = allocator_type()); + + /** + * @brief Constructs a @ref sul::dynamic_bitset from a string or a part of a string. + * + * @details Construct the @ref sul::dynamic_bitset using the characters from @p str in the + * range \[@p pos, std\::min(@p pos + @p n, @p _Traits\::length(@p str))\[. + * + * @param[in] str String containing the part to use + * @param[in] pos Starting position of the string part to use + * @param[in] n Number of characters to use from the starting position + * @param[in] zero Character used to represent @a false bits in the string + * @param[in] one Character used to represent 1 @a true bitsn the string + * @param[in] allocator Allocator to use for memory management + * + * @tparam _CharT Character type of the string + * @tparam _Traits Traits class specifying the operations on the character type of the + * string + * + * @pre @code + * pos < _Traits::length(str) + * @endcode + * + * @complexity Linear in std\::min(@p n, @p _Traits\::length(@p str) - @p pos). + * + * @since 1.0.0 + */ + template> + constexpr explicit dynamic_bitset( + const _CharT* str, + typename std::basic_string<_CharT>::size_type pos = 0, + typename std::basic_string<_CharT>::size_type n = std::basic_string<_CharT>::npos, + _CharT zero = _CharT('0'), + _CharT one = _CharT('1'), + const allocator_type& allocator = allocator_type()); + + /** + * @brief Destructor. + * + * @since 1.0.0 + */ + ~dynamic_bitset() noexcept = default; + + /** + * @brief Resize the @ref sul::dynamic_bitset to contain @p nbits bits. + * + * @details Bits keep the value they had before the resize and, if @p nbits is greater than + * the current size, new bit are initialized to @p value. + * + * @param[in] nbits New size of the @ref sul::dynamic_bitset + * @param[in] value Value of the new bits + * + * @complexity Linear in the difference between the current size and @p nbits. + * Additional complexity possible due to reallocation if capacity is less than @p + * nbits. + * + * @since 1.0.0 + */ + constexpr void resize(size_type nbits, bool value = false); + + /** + * @brief Clears the @ref sul::dynamic_bitset, resize it to 0. + * + * @details Equivalent to: + * @code + * this.resize(0); + * @endcode + * + * @complexity Linear in the size of the @ref sul::dynamic_bitset. + * + * @since 1.0.0 + */ + constexpr void clear(); + + /** + * @brief Add a new bit with the value @p value at the end of the @ref sul::dynamic_bitset. + * + * @details Increase the size of the bitset by one, the added bit becomes the + * most-significant bit. + * + * @param[in] value Value of the bit to add + * + * @complexity Amortized constant. + * + * @since 1.0.0 + */ + constexpr void push_back(bool value); + + /** + * @brief Remove the last bit of the @ref sul::dynamic_bitset. + * + * @details Decrease the size of the @ref sul::dynamic_bitset by one, does nothing if the + * @ref dynamic_bitset is empty. + * + * @complexity Constant. + * + * @since 1.0.0 + */ + constexpr void pop_back(); + + /** + * @brief Append a block of bits @p block at the end of the @ref sul::dynamic_bitset. + * + * @details Increase the size of the @ref sul::dynamic_bitset by @ref bits_per_block. + * + * @param[in] block Block of bits to add + * + * @complexity Amortized constant. + * + * @since 1.0.0 + */ + constexpr void append(block_type block); + + /** + * @brief Append blocks of bits from @p blocks at the end of the @ref sul::dynamic_bitset. + * + * @param[in] blocks Blocks of bits to add + * + * @complexity Linear in the size of @p blocks. Additional complexity possible due + * to reallocation if capacity is less than @ref size() + @p blocks.size() * @ref + * bits_per_block. + * + * @since 1.0.0 + */ + constexpr void append(std::initializer_list blocks); + + /** + * @brief Append blocks of bits from the range \[@p first, @p last\[ at the end of the @ref + * dynamic_bitset. + * + * @param[in] first First iterator of the range + * @param[in] last Last iterator of the range (after the last element to add) + * + * @tparam BlockInputIterator Type of the range iterators + * + * @complexity Linear in the size of the range. Additional complexity possible due + * to reallocation if capacity is less than @ref size() + std\::distance(@p first, + * @p last) * @ref bits_per_block. + * + * @since 1.0.0 + */ + template + constexpr void append(BlockInputIterator first, BlockInputIterator last); + + /** + * @brief Sets the bits to the result of binary AND on corresponding pairs of bits of *this + * and @p rhs. + * + * @param[in] rhs Right hand side @ref sul::dynamic_bitset of the operator + * + * @return A reference to the @ref sul::dynamic_bitset *this + * + * @pre @code + * size() == rhs.size() + * @endcode + * + * @complexity Linear in the size of the @ref sul::dynamic_bitset. + * + * @since 1.0.0 + */ + constexpr dynamic_bitset& operator&=(const dynamic_bitset& rhs); + + /** + * @brief Sets the bits to the result of binary OR on corresponding pairs of bits of *this + * and @p rhs. + * + * @param[in] rhs Right hand side @ref sul::dynamic_bitset of the operator + * + * @return A reference to the @ref sul::dynamic_bitset *this + * + * @pre @code + * size() == rhs.size() + * @endcode + * + * @complexity Linear in the size of the @ref sul::dynamic_bitset. + * + * @since 1.0.0 + */ + constexpr dynamic_bitset& operator|=(const dynamic_bitset& rhs); + + /** + * @brief Sets the bits to the result of binary XOR on corresponding pairs of bits of *this + * and @p rhs. + * + * @param[in] rhs Right hand side @ref sul::dynamic_bitset of the operator + * + * @return A reference to the @ref sul::dynamic_bitset *this + * + * @pre @code + * size() == rhs.size() + * @endcode + * + * @complexity Linear in the size of the @ref sul::dynamic_bitset. + * + * @since 1.0.0 + */ + constexpr dynamic_bitset& operator^=(const dynamic_bitset& rhs); + + /** + * @brief Sets the bits to the result of the binary difference between the bits of *this + * and @p rhs. + * + * @details Less efficient but equivalent way to get this result: + * @code + * this &= ~rhs; + * @endcode + * + * @param[in] rhs Right hand side @ref sul::dynamic_bitset of the operator + * + * @return A reference to the @ref sul::dynamic_bitset *this + * + * @pre @code + * size() == rhs.size() + * @endcode + * + * @complexity Linear in the size of the @ref sul::dynamic_bitset. + * + * @since 1.0.0 + */ + constexpr dynamic_bitset& operator-=(const dynamic_bitset& rhs); + + /** + * @brief Performs binary shift left of @p shift bits. + * + * @details Zeroes are shifted in, does nothing if @p shift == 0. + * + * @param[in] shift Number of positions to shift the bits + * + * @return A reference to the @ref sul::dynamic_bitset *this + * + * @complexity Linear in the size of the @ref sul::dynamic_bitset. + * + * @since 1.0.0 + */ + constexpr dynamic_bitset& operator<<=(size_type shift); + + /** + * @brief Performs binary shift right of @p shift bits. + * + * @details Zeroes are shifted in, does nothing if @p shift == 0. + * + * @param[in] shift Number of positions to shift the bits + * + * @return A reference to the @ref sul::dynamic_bitset *this + * + * @complexity Linear in the size of the @ref sul::dynamic_bitset. + * + * @since 1.0.0 + */ + constexpr dynamic_bitset& operator>>=(size_type shift); + + /** + * @brief Performs binary shift right of @p shift bits. + * + * @details Zeroes are shifted in. Does nothing if @p shift == 0.\n + * Equivalent to: + * @code + * dynamic_bitset bitset(*this); + * bitset <<= shift; + * @endcode + * + * @param[in] shift Number of positions to shift the bits + * + * @return A new @ref sul::dynamic_bitset containing the shifted bits + * + * @complexity Linear in the size of the @ref sul::dynamic_bitset. + * + * @since 1.0.0 + */ + [[nodiscard]] constexpr dynamic_bitset operator<<(size_type shift) const; + + /** + * @brief Performs binary shift left of @p shift bits. + * + * @details Zeroes are shifted in. Does nothing if @p shift == 0.\n + * Equivalent to: + * @code + * dynamic_bitset bitset(*this); + * bitset >>= shift; + * @endcode + * + * @param[in] shift Number of positions to shift the bits + * + * @return A new @ref sul::dynamic_bitset containing the shifted bits + * + * @complexity Linear in the size of the @ref sul::dynamic_bitset. + * + * @since 1.0.0 + */ + [[nodiscard]] constexpr dynamic_bitset operator>>(size_type shift) const; + + /** + * @brief Performs a unary NOT on all bits. + * + * @details Equivalent to: + * @code + * dynamic_bitset bitset(*this); + * bitset.flip(); + * @endcode + * + * @return A copy of *this with all bits flipped + * + * @complexity Linear in the size of the @ref sul::dynamic_bitset. + * + * @since 1.0.0 + */ + [[nodiscard]] constexpr dynamic_bitset operator~() const; + + /** + * @brief Set the bits of the range \[@p pos, @p pos + @p len\[ to value @p value. + * + * @details Does nothing if @p len == 0. + * + * @param[in] pos Position of the first bit of the range + * @param[in] len Length of the range + * @param[in] value Value to set the bits to + * + * @return A reference to the @ref sul::dynamic_bitset *this + * + * @pre @code + * (pos < size()) && ((len == 0) || (pos + len - 1 < size())) + * @endcode + * + * @complexity Linear in @p len. + * + * @since 1.0.0 + */ + constexpr dynamic_bitset& set(size_type pos, size_type len, bool value); + + /** + * @brief Set the bit at the position @p pos to @a true or value @p value. + * + * @param[in] pos Position of the bit to set + * @param[in] value Value to set the bit to + * + * @return A reference to the @ref sul::dynamic_bitset *this + * + * @pre @code + * pos < size() + * @endcode + * + * @complexity Constant. + * + * @since 1.0.0 + */ + constexpr dynamic_bitset& set(size_type pos, bool value = true); + + /** + * @brief Set all the bits of the @ref sul::dynamic_bitset to @a true. + * + * @return A reference to the @ref sul::dynamic_bitset *this + * + * @complexity Linear in the size of the @ref sul::dynamic_bitset. + * + * @since 1.0.0 + */ + constexpr dynamic_bitset& set(); + + /** + * @brief Reset the bits of the range \[@p pos, @p pos + @p len\[ to @a false. + * + * @param[in] pos Position of the first bit of the range + * @param[in] len Length of the range + * + * @return A reference to the @ref sul::dynamic_bitset *this + * + * @pre @code + * (pos < size()) && ((len == 0) || (pos + len - 1 < size())) + * @endcode + * + * @complexity Linear in @p len. + * + * @since 1.0.0 + */ + constexpr dynamic_bitset& reset(size_type pos, size_type len); + + /** + * @brief Reset the bit at the position @p pos to @a false. + * + * @param[in] pos Position of the bit to reset + * + * @return A reference to the @ref sul::dynamic_bitset *this + * + * @pre @code + * pos < size() + * @endcode + * + * @complexity Constant. + * + * @since 1.0.0 + */ + constexpr dynamic_bitset& reset(size_type pos); + + /** + * @brief Reset all the bits of the @ref sul::dynamic_bitset to @a false. + * + * @return A reference to the @ref sul::dynamic_bitset *this + * + * @complexity Linear in the size of the @ref sul::dynamic_bitset. + * + * @since 1.0.0 + */ + constexpr dynamic_bitset& reset(); + + /** + * @brief Flip the bits of the range \[@p pos, @p pos + @p len\[. + * + * @param[in] pos Position of the first bit of the range + * @param[in] len Length of the range + * + * @return A reference to the @ref sul::dynamic_bitset *this + * + * @pre @code + * (pos < size()) && ((len == 0) || (pos + len - 1 < size())) + * @endcode + * + * @complexity Linear in @p len. + * + * @since 1.0.0 + */ + constexpr dynamic_bitset& flip(size_type pos, size_type len); + + /** + * @brief Flip the bit at the position @p pos. + * + * @param[in] pos Position of the bit to reset + * + * @return A reference to the @ref sul::dynamic_bitset *this + * + * @pre @code + * pos < size() + * @endcode + * + * @complexity Constant. + * + * @since 1.0.0 + */ + constexpr dynamic_bitset& flip(size_type pos); + + /** + * @brief Flip all the bits of the @ref sul::dynamic_bitset. + * + * @return A reference to the @ref sul::dynamic_bitset *this + * + * @complexity Linear in the size of the @ref sul::dynamic_bitset. + * + * @since 1.0.0 + */ + constexpr dynamic_bitset& flip(); + + /** + * @brief Test the value of the bit at position @p pos. + * + * @param[in] pos Position of the bit to test + * + * @return The tested bit value + * + * @pre @code + * pos < size() + * @endcode + * + * @complexity Constant. + * + * @since 1.0.0 + */ + [[nodiscard]] constexpr bool test(size_type pos) const; + + /** + * @brief Test the value of the bit at position @p pos and set it to @a true or value @p + * value. + * + * @param[in] pos Position of the bit to test and set + * @param[in] value Value to set the bit to + * + * @return The tested bit value + * + * @pre @code + * pos < size() + * @endcode + * + * @complexity Constant. + * + * @since 1.0.0 + */ + [[nodiscard]] constexpr bool test_set(size_type pos, bool value = true); + + /** + * @brief Checks if all bits are set to @a true. + * + * @return @a true if all bits are set to @a true, otherwise @a false + * + * @remark Return @a true if the @ref sul::dynamic_bitset is empty, the logic is that you + * are checking if all bits are set to @a true, meaning none of them is set to @a + * false, and in an empty @ref sul::dynamic_bitset no bits are set to @a false. + * + * @complexity Linear in the size of the @ref sul::dynamic_bitset. + * + * @since 1.0.0 + */ + [[nodiscard]] constexpr bool all() const; + + /** + * @brief Checks if any bits are set to @a true. + * + * @return @a true if any of the bits is set to @a true, otherwise @a false + * + * @remark Return @a false if the @ref sul::dynamic_bitset is empty, the logic is you are + * checking if there is at least one bit set to @a true and in an empty @ref + * dynamic_bitset there is no bit set to @a true. + * + * @complexity Linear in the size of the @ref sul::dynamic_bitset. + * + * @since 1.0.0 + */ + [[nodiscard]] constexpr bool any() const; + + /** + * @brief Checks if none of the bits are set to @a true. + * + * @return @a true if none of the bits is set to @a true, otherwise @a false + * + * @remark Return @a true if the @ref sul::dynamic_bitset is empty, the logic is that you + * are checking if there is no bit set to @a true and in an empty @ref + * sul::dynamic_bitset there is no bit that can be set to @a true. + * + * @complexity Linear in the size of the @ref sul::dynamic_bitset. + * + * @since 1.0.0 + */ + [[nodiscard]] constexpr bool none() const; + + /** + * @brief Count the number of bits set to @a true. + * + * @details Return 0 if the @ref sul::dynamic_bitset is empty. + * + * @return The number of bits that are set to @a true + * + * @complexity Linear in the size of the @ref sul::dynamic_bitset. + * + * @since 1.0.0 + */ + [[nodiscard]] constexpr size_type count() const noexcept; + + /** + * @brief Accesses the bit at position @p pos. + * + * @param[in] pos Position of the bit to access + * + * @return A @ref reference object which allows writing to the requested bit + * + * @pre @code + * pos < size() + * @endcode + * + * @complexity Constant. + * + * @since 1.0.0 + */ + [[nodiscard]] constexpr reference operator[](size_type pos); + + /** + * @brief Accesses the bit at position @p pos. + * + * @param[in] pos Position of the bit to access + * + * @return The value of the requested bit + * + * @pre @code + * pos < size() + * @endcode + * + * @complexity Constant. + * + * @since 1.0.0 + */ + [[nodiscard]] constexpr const_reference operator[](size_type pos) const; + + /** + * @brief Give the number of bits of the @ref sul::dynamic_bitset. + * + * @return The number of bits of the @ref sul::dynamic_bitset + * + * @complexity Constant. + * + * @since 1.0.0 + */ + [[nodiscard]] constexpr size_type size() const noexcept; + + /** + * @brief Give the number of blocks used by the @ref sul::dynamic_bitset. + * + * @return The number of blocks used by the @ref sul::dynamic_bitset + * + * @complexity Constant. + * + * @since 1.0.0 + */ + [[nodiscard]] constexpr size_type num_blocks() const noexcept; + + /** + * @brief Checks if the @ref sul::dynamic_bitset is empty. + * + * @details Equivalent to: + * @code + * size() == 0; + * @endcode + * + * @return @a true if the @ref sul::dynamic_bitset is empty, @a false otherwise + * + * @complexity Constant. + * + * @since 1.0.0 + */ + [[nodiscard]] constexpr bool empty() const noexcept; + + /** + * @brief Give the number of bits that the @ref sul::dynamic_bitset has currently allocated + * space for. + * + * @return Capacity of the currently allocated storage. + * + * @complexity Constant. + * + * @since 1.0.0 + */ + [[nodiscard]] constexpr size_type capacity() const noexcept; + + /** + * @brief Increase the capacity of the @ref sul::dynamic_bitset to a value that's greater + * or equal to @p num_bits. + * + * @details If @p num_bits is greater than the current capacity, new storage is allocated and + * all @ref reference on bits of the @ref sul::dynamic_bitset are invalidated, + * otherwise the method does nothing. + * + * @param[in] num_bits New capacity of the @ref sul::dynamic_bitset + * + * @complexity At most linear in the size of the @ref sul::dynamic_bitset. + * + * @since 1.0.0 + */ + constexpr void reserve(size_type num_bits); + + /** + * @brief Requests the removal of unused capacity. + * + * @details It is a non-binding request to reduce the capacity to the size. It depends on the + * implementation of std\::vector whether the request is fulfilled.\n If + * reallocation occurs, all @ref reference on bits of the @ref sul::dynamic_bitset + * are invalidated. + * + * @complexity At most linear in the size of the @ref sul::dynamic_bitset. + * + * @since 1.0.0 + */ + constexpr void shrink_to_fit(); + + /** + * @brief Determines if this @ref sul::dynamic_bitset is a subset of @p bitset. + * + * @details This @ref sul::dynamic_bitset is a subset of @p bitset if, for every bit that is + * set in this @ref sul::dynamic_bitset, the corresponding bit in @p bitset a is + * also set.\n\n Less efficient but equivalent way to get this result: + * @code + * res = (this & ~bitset).none(); + * @endcode + * + * @param[in] bitset The @ref sul::dynamic_bitset for which to check if this @ref + * sul::dynamic_bitset is a subset + * + * @return @a true if this @ref sul::dynamic_bitset is a subset of @p bitset, @a false + * otherwise + * + * @remark The relation "is a subset of" is not symmetric (A being a subset of B doesn't + * imply that B is a subset of A) but is antisymmetric (if A is a subset of B and B + * is a subset of A, then A == B). + * + * @pre @code + * size() == bitset.size() + * @endcode + * + * @complexity Linear in the size of the @ref sul::dynamic_bitset. + * + * @since 1.0.0 + */ + [[nodiscard]] constexpr bool is_subset_of(const dynamic_bitset& bitset) const; + + /** + * @brief Determines if this @ref sul::dynamic_bitset is a proper subset of @p bitset. + * + * @details This @ref sul::dynamic_bitset is a proper subset of @p bitset if, for every bit + * that is set in this @ref sul::dynamic_bitset, the corresponding bit in @p bitset + * a is also set and if this @ref sul::dynamic_bitset is different from @p + * bitset.\n\n Less efficient but equivalent way to get this result: + * @code + * res = ((this != bitset) && (this & ~bitset).none()); + * @endcode + * + * @param[in] bitset The @ref sul::dynamic_bitset for which to check if this @ref + * sul::dynamic_bitset is a proper subset + * + * @return @a true if this @ref sul::dynamic_bitset is a proper subset of @p bitset, @a + * false otherwise + * + * @remark The relation "is a proper subset of" is asymmetric (A being a proper subset of B + * imply that B is not a proper subset of A). + * + * @pre @code + * size() == bitset.size() + * @endcode + * + * @complexity Linear in the size of the @ref sul::dynamic_bitset. + * + * @since 1.0.0 + */ + [[nodiscard]] constexpr bool is_proper_subset_of(const dynamic_bitset& bitset) const; + + /** + * @brief Determines if this @ref sul::dynamic_bitset and @p bitset intersect. + * + * @details This @ref sul::dynamic_bitset intersects with @p bitset if for at least one bit + * set in this @ref sul::dynamic_bitset, the corresponding bit in @p bitset a is + * also set. In other words two bitsets intersect if they have at least one bit set + * in common.\n\n Less efficient but equivalent way to get this result: + * @code + * res = (this & bitset).any(); + * @endcode + * + * @param[in] bitset The @ref sul::dynamic_bitset for which to check if this @ref + * sul::dynamic_bitset intersects + * + * @return @a true if this @ref sul::dynamic_bitset intersects with @p bitset, @a false + * otherwise + * + * @pre @code + * size() == bitset.size() + * @endcode + * + * @complexity Linear in the size of the @ref sul::dynamic_bitset. + * + * @since 1.0.0 + */ + [[nodiscard]] constexpr bool intersects(const dynamic_bitset& bitset) const; + + /** + * @brief Find the position of the first bit set in the @ref sul::dynamic_bitset starting + * from the least-significant bit. + * + * @details Give the lowest index of the @ref sul::dynamic_bitset with a bit set, or @ref + * npos if no bits are set. + * + * @return The position of the first bit set, or @ref npos if no bits are set + * + * @complexity Linear in the size of the @ref sul::dynamic_bitset. + * + * @since 1.0.0 + */ + [[nodiscard]] constexpr size_type find_first() const; + + /** + * @brief Find the position of the first bit set in the range \[@p prev + 1, @ref size()\[ + * of the @ref sul::dynamic_bitset starting from the position @p prev + 1. + * + * @details Give the lowest index superior to @p prev of the @ref sul::dynamic_bitset with a + * bit set, or @ref npos if no bits are set after the index @p prev.\n If @p prev + + * 1 \>= @ref size(), return @ref npos. + * + * @param[in] prev Position of the bit preceding the search range + * + * @return The position of the first bit set after @p prev, or @ref npos if no bits are set + * after @p prev + * + * @complexity Linear in @ref size() - @p prev. + * + * @since 1.0.0 + */ + [[nodiscard]] constexpr size_type find_next(size_type prev) const; + + /** + * @brief Exchanges the bits of this @ref sul::dynamic_bitset with those of @p other. + * + * @details All @ref reference on bits of the @ref sul::dynamic_bitset are invalidated. + * + * @param other @ref sul::dynamic_bitset to exchange bits with + * + * @complexity Constant. + * + * @since 1.0.0 + */ + constexpr void swap(dynamic_bitset& other); + + /** + * @brief Gets the associated allocator. + * + * @return The associated allocator. + * + * @complexity Constant. + * + * @since 1.0.0 + */ + [[nodiscard]] constexpr allocator_type get_allocator() const; + + /** + * @brief Generate a string representation of the @ref sul::dynamic_bitset. + * + * @details Uses @p zero to represent bits with value of @a false and @p one to represent + * bits with value of @a true. The resulting string contains @ref size() characters + * with the first character corresponds to the last (@ref size() - 1th) bit and the + * last character corresponding to the first bit. + * + * @param[in] zero Character to use to represent @a false + * @param[in] one Character to use to represent @a true + * + * @tparam _CharT Character type of the string + * @tparam _Traits Traits class specifying the operations on the character type of the + * string + * @tparam _Alloc Allocator type used to allocate internal storage of the string + * + * @return The string representing the @ref sul::dynamic_bitset content + * + * @complexity Linear in the size of the @ref sul::dynamic_bitset. + * + * @since 1.0.0 + */ + template, + typename _Alloc = std::allocator<_CharT>> + [[nodiscard]] constexpr std::basic_string<_CharT, _Traits, _Alloc> to_string(_CharT zero = _CharT('0'), + _CharT one = _CharT('1')) const; + + /** + * @brief Converts the contents of the bitset to an unsigned long integer. + * + * @details The first bit of the bitset corresponds to the least significant digit of the + * number and the last bit corresponds to the most significant digit. + * + * @return The numeric value corresponding to the bitset contents. + * + * @throws std::overflow_error if the value is too large to be represented in an unsigned + * long + * + * @complexity Constant. + * + * @since 1.3.0 + */ + [[nodiscard]] constexpr unsigned long to_ulong() const; + + /** + * @brief Converts the contents of the bitset to an unsigned long long integer. + * + * @details The first bit of the bitset corresponds to the least significant digit of the + * number and the last bit corresponds to the most significant digit. + * + * @return The numeric value corresponding to the bitset contents. + * + * @throws std::overflow_error if the value is too large to be represented in an unsigned long + * long + * + * @complexity Constant. + * + * @since 1.3.0 + */ + [[nodiscard]] constexpr unsigned long long to_ullong() const; + + /** + * @brief Iterate on the @ref sul::dynamic_bitset and call @p function with the position of + * the bits on. + * + * @details For each set bit, @p function is called as follow: + * @code + * std::invoke(std::forward(function), bit_pos, std::forward(parameters)...)) + * @endcode + * where @p bit_pos is the position of the current bit on. Thus @p function + * should take a size_t for the current set bit position as first argument, also @p + * parameters can be used to pass additional arguments to @p function when it is + * called by this method.\n\n @p function can return nothing or a bool, if it return + * a bool, the return value indicate if the iteration should continue, @a true to + * continue the iteration, @a false to stop, this make it easy to do an early exit. + * + * @param function Function to call on all bits on, take the current bit position as + * first argument and @p parameters as next arguments + * @param parameters Extra parameters for @p function + * + * @tparam Function Type of @p function, must take a size_t as first argument and @p + * Parameters as next arguments + * @tparam Parameters Type of @p parameters + * + * @complexity Linear in the size of the @ref sul::dynamic_bitset. + * + * @since 1.0.0 + */ + template + constexpr void iterate_bits_on(Function&& function, Parameters&&... parameters) const; + + /** + * @brief Return a pointer to the underlying array serving as blocks storage. + * + * @details The pointer is such that range [@ref data(); @ref data() + @ref num_blocks()) is + * always a valid range, even if the container is empty (@ref data() is not + * dereferenceable in that case). + * + * + * @post The bits past the end of the @ref sul::dynamic_bitset in the last block are + * guaranteed to be 0s, example: + * @code + * // random bitset of size 11 + * std::minstd_rand rand(std::random_device{}()); + * std::bernoulli_distribution dist; + * sul::dynamic_bitset bitset; + * for(size_t i = 0; i < 11; ++i) + * { + * bitset.push_back(dist(rand)); + * } + * + * // the bitset use 2 blocks of 8 bits + * // check that unused bits are set to 0 + * assert(*(bitset.data() + 1) >> 3 == 0); + * @endcode + * + * @remark If the @ref sul::dynamic_bitset is empty, this function may or may not return a + * null pointer. + * + * @return A pointer to the underlying array serving as blocks storage + * + * @complexity Constant. + * + * @since 1.2.0 + */ + [[nodiscard]] constexpr block_type* data() noexcept; + + /** + * @brief Return a pointer to the underlying array serving as blocks storage. + * + * @details The pointer is such that range [@ref data(); @ref data() + @ref num_blocks()) is + * always a valid range, even if the container is empty (@ref data() is not + * dereferenceable in that case). + * + * + * @post The bits past the end of the @ref sul::dynamic_bitset in the last block are + * guaranteed to be 0s, example: + * @code + * // random bitset of size 11 + * std::minstd_rand rand(std::random_device{}()); + * std::bernoulli_distribution dist; + * sul::dynamic_bitset bitset; + * for(size_t i = 0; i < 11; ++i) + * { + * bitset.push_back(dist(rand)); + * } + * + * // the bitset use 2 blocks of 8 bits + * // check that unused bits are set to 0 + * assert(*(bitset.data() + 1) >> 3 == 0); + * @endcode + * + * @remark If the @ref sul::dynamic_bitset is empty, this function may or may not return a + * null pointer. + * + * @return A pointer to the underlying array serving as blocks storage + * + * @complexity Constant. + * + * @since 1.2.0 + */ + [[nodiscard]] constexpr const block_type* data() const noexcept; + + /** + * @brief Test if two @ref sul::dynamic_bitset have the same content. + * + * @param[in] lhs The left hand side @ref sul::dynamic_bitset of the operator + * @param[in] rhs The right hand side @ref sul::dynamic_bitset of the operator + * + * @tparam Block_ Block type used by @p lhs and @p rhs for storing the bits + * @tparam Allocator_ Allocator type used by @p lhs and @p rhs for memory management + * + * @return @a true if they contain the same bits, @a false otherwise + * + * @complexity Linear in the size of the @ref sul::dynamic_bitset. + * + * @since 1.0.0 + */ + template + friend constexpr bool operator==(const dynamic_bitset& lhs, + const dynamic_bitset& rhs); + + /** + * @brief Test if @p lhs is "less than" @p rhs. The comparison of the two @ref + * dynamic_bitset is first on numbers their content represent and then on their + * size. + * + * @details The size comparison is necessary for the comparison operators to keep their + * properties. For example without the size comparison the "<=" operator (defined + * for "A <= B" by "!(B < A)") would no longer be antisymmetric (if A \<= B and B + * \<= A, then A == B) because @ref operator==() compare the @ref + * sul::dynamic_bitset as a container and not a number. For example with bitsets + * A(0011) and B(011), without the size comparison B \< A would be @a false, A \<= B + * would be @a true, B \<= A would be @a true, but A == B would be @a false, + * breaking the antisymmetric property of the operator. Thus, to respect the + * properties of the operators, the size is used as a secondary criteria for the + * comparison of @ref sul::dynamic_bitset which content represent the same number. + * Therefore, for the previous example with bitsets A(0011) and B(011), B \< A is @a + * true, A \<= B is @a false, B \<= A is @a true and A == B is @a false.\n\n If + * comparing bitsets @a A and @a B with the content of @a A representing the number + * @a a, and the content of @a B representing the number @a b, this operator would + * work as follow: + * @code + * if(a == b) + * { + * return A.size() < B.size(); + * } + * else + * { + * return a < b; + * } + * @endcode + * + * @remark The empty @ref sul::dynamic_bitset is the "lowest" of all bitset and for 0-only + * bitsets comparison, the shortest is the lowest. + * + * @param[in] lhs The left hand side @ref sul::dynamic_bitset of the operator + * @param[in] rhs The right hand side @ref sul::dynamic_bitset of the operator + * + * @tparam Block_ Block type used by @p lhs and @p rhs for storing the bits + * @tparam Allocator_ Allocator type used by @p lhs and @p rhs for memory management + * + * @return @a true if @p lhs is "less than" @p rhs + * + * @complexity Linear in the size of the @ref sul::dynamic_bitset. + * + * @since 1.0.0 + */ + template + friend constexpr bool operator<(const dynamic_bitset& lhs, + const dynamic_bitset& rhs); + + private: + template + struct dependent_false : public std::false_type + { + }; + + std::vector m_blocks; + size_type m_bits_number; + + static constexpr block_type zero_block = block_type(0); + static constexpr block_type one_block = block_type(~zero_block); + static constexpr size_type block_last_bit_index = bits_per_block - 1; + + static constexpr size_type blocks_required(size_type nbits) noexcept; + + static constexpr size_type block_index(size_type pos) noexcept; + static constexpr size_type bit_index(size_type pos) noexcept; + + static constexpr block_type bit_mask(size_type pos) noexcept; + static constexpr block_type bit_mask(size_type first, size_type last) noexcept; + + static constexpr void + set_block_bits(block_type& block, size_type first, size_type last, bool val = true) noexcept; + static constexpr void flip_block_bits(block_type& block, size_type first, size_type last) noexcept; + + static constexpr size_type block_count(const block_type& block) noexcept; + static constexpr size_type block_count(const block_type& block, size_type nbits) noexcept; + + static constexpr size_type count_block_trailing_zero(const block_type& block) noexcept; + + template + constexpr void init_from_string(std::basic_string_view<_CharT, _Traits> str, + typename std::basic_string_view<_CharT, _Traits>::size_type pos, + typename std::basic_string_view<_CharT, _Traits>::size_type n, + _CharT zero, + _CharT one); + + constexpr block_type& get_block(size_type pos); + constexpr const block_type& get_block(size_type pos) const; + constexpr block_type& last_block(); + constexpr block_type last_block() const; + + // used bits in the last block + constexpr size_type extra_bits_number() const noexcept; + // unused bits in the last block + constexpr size_type unused_bits_number() const noexcept; + + template + constexpr void apply(const dynamic_bitset& other, BinaryOperation binary_op); + template + constexpr void apply(UnaryOperation unary_op); + constexpr void apply_left_shift(size_type shift); + constexpr void apply_right_shift(size_type shift); + + // reset unused bits to 0 + constexpr void sanitize(); + + // check functions used in asserts + constexpr bool check_unused_bits() const noexcept; + constexpr bool check_size() const noexcept; + constexpr bool check_consistency() const noexcept; + }; + + // Deduction guideline for expressions like "dynamic_bitset a(32);" with an integral type as parameter + // to use the constructor with the initial size instead of the constructor with the allocator. + template>> + dynamic_bitset(integral_type) -> dynamic_bitset<>; + + //================================================================================================= + // dynamic_bitset external functions declarations + //================================================================================================= + + /** + * @brief Test if two @ref sul::dynamic_bitset content are different. + * + * @details Defined as: + * @code + * return !(lhs == rhs); + * @endcode + * see @ref sul::dynamic_bitset::operator==() for more informations. + * + * @param[in] lhs The left hand side @ref sul::dynamic_bitset of the operator + * @param[in] rhs The right hand side @ref sul::dynamic_bitset of the operator + * + * @tparam Block Block type used by @p lhs and @p rhs for storing the bits + * @tparam Allocator Allocator type used by @p lhs and @p rhs for memory management + * + * @return @a true if they does not contain the same bits, @a false otherwise + * + * @complexity Linear in the size of the @ref sul::dynamic_bitset. + * + * @since 1.0.0 + * + * @relatesalso dynamic_bitset + */ + template + constexpr bool operator!=(const dynamic_bitset& lhs, const dynamic_bitset& rhs); + + /** + * @brief Test if @p lhs is "less than or equal to" @p rhs. The comparison of the two @ref + * sul::dynamic_bitset is first on numbers their content represent and then on their size. + * + * @details Defined as: + * @code + * return !(rhs < lhs); + * @endcode + * see @ref sul::dynamic_bitset::operator<() for more informations. + * + * @param[in] lhs The left hand side @ref sul::dynamic_bitset of the operator + * @param[in] rhs The right hand side @ref sul::dynamic_bitset of the operator + * + * @tparam Block Block type used by @p lhs and @p rhs for storing the bits + * @tparam Allocator Allocator type used by @p lhs and @p rhs for memory management + * + * @return @a true if @p lhs is "less than or equal to" @p rhs + * + * @complexity Linear in the size of the @ref sul::dynamic_bitset. + * + * @since 1.0.0 + * + * @relatesalso dynamic_bitset + */ + template + constexpr bool operator<=(const dynamic_bitset& lhs, const dynamic_bitset& rhs); + + /** + * @brief Test if @p lhs is "greater than" @p rhs. The comparison of the two @ref + * sul::dynamic_bitset is first on numbers their content represent and then on their + * size. + * + * @details Defined as: + * @code + * return rhs < lhs; + * @endcode + * see @ref sul::dynamic_bitset::operator<() for more informations. + * + * @param[in] lhs The left hand side @ref sul::dynamic_bitset of the operator + * @param[in] rhs The right hand side @ref sul::dynamic_bitset of the operator + * + * @tparam Block Block type used by @p lhs and @p rhs for storing the bits + * @tparam Allocator Allocator type used by @p lhs and @p rhs for memory management + * + * @return @a true if @p lhs is "greater than" @p rhs + * + * @complexity Linear in the size of the @ref sul::dynamic_bitset. + * + * @since 1.0.0 + * + * @relatesalso dynamic_bitset + */ + template + constexpr bool operator>(const dynamic_bitset& lhs, const dynamic_bitset& rhs); + + /** + * @brief Test if @p lhs is "greater than or equal to" @p rhs. The comparison of the two @ref + * sul::dynamic_bitset is first on numbers their content represent and then on their + * size. + * + * @details Defined as: + * @code + * return !(lhs < rhs); + * @endcode + * see @ref sul::dynamic_bitset::operator<() for more informations. + * + * @param[in] lhs The left hand side @ref sul::dynamic_bitset of the operator + * @param[in] rhs The right hand side @ref sul::dynamic_bitset of the operator + * + * @tparam Block Block type used by @p lhs and @p rhs for storing the bits + * @tparam Allocator Allocator type used by @p lhs and @p rhs for memory management + * + * @return @a true if @p lhs is "greater than or equal to" @p rhs + * + * @complexity Linear in the size of the @ref sul::dynamic_bitset. + * + * @since 1.0.0 + * + * @relatesalso dynamic_bitset + */ + template + constexpr bool operator>=(const dynamic_bitset& lhs, const dynamic_bitset& rhs); + + /** + * @brief Performs binary AND on corresponding pairs of bits of @p lhs and @p rhs. + * + * @details Defined as: + * @code + * dynamic_bitset result(lhs); + * return result &= rhs; + * @endcode + * see @ref sul::dynamic_bitset::operator&=() for more informations. + * + * @param[in] lhs The left hand side @ref sul::dynamic_bitset of the operator + * @param[in] rhs The right hand side @ref sul::dynamic_bitset of the operator + * + * @tparam Block Block type used by @p lhs and @p rhs for storing the bits + * @tparam Allocator Allocator type used by @p lhs and @p rhs for memory management + * + * @return A @ref sul::dynamic_bitset with each bit being the result of a binary AND between the + * corresponding pair of bits of @p lhs and @p rhs + * + * @pre @code + * lhs.size() == rhs.size() + * @endcode + * + * @complexity Linear in the size of the @ref sul::dynamic_bitset. + * + * @since 1.0.0 + * + * @relatesalso dynamic_bitset + */ + template + constexpr dynamic_bitset operator&(const dynamic_bitset& lhs, + const dynamic_bitset& rhs); + + /** + * @brief Performs binary OR on corresponding pairs of bits of @p lhs and @p rhs. + * + * @details Defined as: + * @code + * dynamic_bitset result(lhs); + * return result |= rhs; + * @endcode + * see @ref sul::dynamic_bitset::operator|=() for more informations. + * + * @param[in] lhs The left hand side @ref sul::dynamic_bitset of the operator + * @param[in] rhs The right hand side @ref sul::dynamic_bitset of the operator + * + * @tparam Block Block type used by @p lhs and @p rhs for storing the bits + * @tparam Allocator Allocator type used by @p lhs and @p rhs for memory management + * + * @return A @ref sul::dynamic_bitset with each bit being the result of a binary OR between the + * corresponding pair of bits of @p lhs and @p rhs + * + * @pre @code + * lhs.size() == rhs.size() + * @endcode + * + * @complexity Linear in the size of the @ref sul::dynamic_bitset. + * + * @since 1.0.0 + * + * @relatesalso dynamic_bitset + */ + template + constexpr dynamic_bitset operator|(const dynamic_bitset& lhs, + const dynamic_bitset& rhs); + + /** + * @brief Performs binary XOR on corresponding pairs of bits of @p lhs and @p rhs. + * + * @details Defined as: + * @code + * dynamic_bitset result(lhs); + * return result ^= rhs; + * @endcode + * see @ref sul::dynamic_bitset::operator^=() for more informations. + * + * @param[in] lhs The left hand side @ref sul::dynamic_bitset of the operator + * @param[in] rhs The right hand side @ref sul::dynamic_bitset of the operator + * + * @tparam Block Block type used by @p lhs and @p rhs for storing the bits + * @tparam Allocator Allocator type used by @p lhs and @p rhs for memory management + * + * @return A @ref sul::dynamic_bitset with each bit being the result of a binary XOR between the + * corresponding pair of bits of @p lhs and @p rhs + * + * @pre @code + * lhs.size() == rhs.size() + * @endcode + * + * @complexity Linear in the size of the @ref sul::dynamic_bitset. + * + * @since 1.0.0 + * + * @relatesalso dynamic_bitset + */ + template + constexpr dynamic_bitset operator^(const dynamic_bitset& lhs, + const dynamic_bitset& rhs); + + /** + * @brief Performs binary difference between bits of @p lhs and @p rhs. + * + * @details Defined as: + * @code + * dynamic_bitset result(lhs); + * return result -= rhs; + * @endcode + * see @ref sul::dynamic_bitset::operator-=() for more informations. + * + * @param[in] lhs The left hand side @ref sul::dynamic_bitset of the operator + * @param[in] rhs The right hand side @ref sul::dynamic_bitset of the operator + * + * @tparam Block Block type used by @p lhs and @p rhs for storing the bits + * @tparam Allocator Allocator type used by @p lhs and @p rhs for memory management + * + * @return A @ref sul::dynamic_bitset with each bit being the result of the binary difference + * between the corresponding bits of @p lhs and @p rhs + * + * @pre @code + * lhs.size() == rhs.size() + * @endcode + * + * @complexity Linear in the size of the @ref sul::dynamic_bitset. + * + * @since 1.0.0 + * + * @relatesalso dynamic_bitset + */ + template + constexpr dynamic_bitset operator-(const dynamic_bitset& lhs, + const dynamic_bitset& rhs); + + /** + * @brief Insert a string representation of this @ref sul::dynamic_bitset to a character + * stream. + * + * @details The string representation written is the same as if generated with @ref + * sul::dynamic_bitset::to_string() with default parameter, using '1' for @a true bits + * and '0' for @a false bits. + * + * @param os Character stream to write to + * @param[in] bitset @ref sul::dynamic_bitset to write + * + * @tparam _CharT Character type of the character stream + * @tparam _Traits Traits class specifying the operations on the character type of the + * character stream + * @tparam Block Block type used by @p bitset for storing the bits + * @tparam Allocator Allocator type used by @p bitset for memory management + * + * @return @p os + * + * @complexity Linear in the size of the @ref sul::dynamic_bitset. + * + * @since 1.0.0 + * + * @relatesalso dynamic_bitset + */ + template + constexpr std::basic_ostream<_CharT, _Traits>& operator<<(std::basic_ostream<_CharT, _Traits>& os, + const dynamic_bitset& bitset); + + /** + * @brief Extract a @ref sul::dynamic_bitset from a character stream using its string + * representation. + * + * @details The string representation expected is the same as if generated with @ref + * sul::dynamic_bitset::to_string() with default parameter, using '1' for @a true bits + * and '0' for @a false bits. On success the content of @p bitset is cleared before + * writing to it. The extraction starts by skipping leading whitespace then take the + * characters one by one and stop if @p is.good() return @a false or the next character + * is neither _CharT('0') nor _CharT('1'). + * + * @param is Character stream to read from + * @param bitset @ref sul::dynamic_bitset to write to + * + * @tparam _CharT Character type of the character stream + * @tparam _Traits Traits class specifying the operations on the character type of the + * character stream + * @tparam Block Block type used by @p bitset for storing the bits + * @tparam Allocator Allocator type used by @p bitset for memory management + * + * @return @p is + * + * @complexity Linear in the size of the @ref sul::dynamic_bitset. + * + * @since 1.0.0 + * + * @relatesalso dynamic_bitset + */ + template + constexpr std::basic_istream<_CharT, _Traits>& operator>>(std::basic_istream<_CharT, _Traits>& is, + dynamic_bitset& bitset); + + /** + * @brief Exchange the content of @p bitset1 and @p bitset2. + * + * @details Defined as: + * @code + * bitset1.swap(bitset2); + * @endcode + * see @ref sul::dynamic_bitset::swap() for more informations. + * + * @param bitset1 @ref sul::dynamic_bitset to be swapped + * @param bitset2 @ref sul::dynamic_bitset to be swapped + * + * @tparam Block Block type used by @p bitset for storing the bits + * @tparam Allocator Allocator type used by @p bitset for memory management + * + * @complexity Constant. + * + * @since 1.0.0 + * + * @relatesalso dynamic_bitset + */ + template + constexpr void swap(dynamic_bitset& bitset1, dynamic_bitset& bitset2); + + //================================================================================================= + // dynamic_bitset::reference functions implementations + //================================================================================================= + + template + constexpr dynamic_bitset::reference::reference(dynamic_bitset& bitset, + size_type bit_pos) + : m_block(bitset.get_block(bit_pos)) + , m_mask(dynamic_bitset::bit_mask(bit_pos)) + { + } + + template + constexpr typename dynamic_bitset::reference& + dynamic_bitset::reference::operator=(bool v) + { + assign(v); + return *this; + } + + template + constexpr typename dynamic_bitset::reference& + dynamic_bitset::reference::operator=(const dynamic_bitset::reference& rhs) + { + assign(rhs); + return *this; + } + + template + constexpr typename dynamic_bitset::reference& + dynamic_bitset::reference::operator=(dynamic_bitset::reference&& rhs) noexcept + { + assign(rhs); + return *this; + } + + template + constexpr typename dynamic_bitset::reference& + dynamic_bitset::reference::operator&=(bool v) + { + if(!v) + { + reset(); + } + return *this; + } + + template + constexpr typename dynamic_bitset::reference& + dynamic_bitset::reference::operator|=(bool v) + { + if(v) + { + set(); + } + return *this; + } + + template + constexpr typename dynamic_bitset::reference& + dynamic_bitset::reference::operator^=(bool v) + { + if(v) + { + flip(); + } + return *this; + } + + template + constexpr typename dynamic_bitset::reference& + dynamic_bitset::reference::operator-=(bool v) + { + if(v) + { + reset(); + } + return *this; + } + + template + constexpr bool dynamic_bitset::reference::operator~() const + { + return (m_block & m_mask) == zero_block; + } + + template + constexpr dynamic_bitset::reference::operator bool() const + { + return (m_block & m_mask) != zero_block; + } + + template + constexpr typename dynamic_bitset::reference& dynamic_bitset::reference::set() + { + m_block |= m_mask; + return *this; + } + + template + constexpr typename dynamic_bitset::reference& dynamic_bitset::reference::reset() + { + m_block &= static_cast(~m_mask); + return *this; + } + + template + constexpr typename dynamic_bitset::reference& dynamic_bitset::reference::flip() + { + m_block ^= m_mask; + return *this; + } + + template + constexpr typename dynamic_bitset::reference& + dynamic_bitset::reference::assign(bool v) + { + if(v) + { + set(); + } + else + { + reset(); + } + return *this; + } + + //================================================================================================= + // dynamic_bitset public functions implementations + //================================================================================================= + + template + constexpr dynamic_bitset::dynamic_bitset(const allocator_type& allocator) + : m_blocks(allocator) + , m_bits_number(0) + { + } + + template + constexpr dynamic_bitset::dynamic_bitset(size_type nbits, + unsigned long long init_val, + const allocator_type& allocator) + : m_blocks(blocks_required(nbits), allocator) + , m_bits_number(nbits) + { + if(nbits == 0 || init_val == 0) + { + return; + } + + constexpr size_t ull_bits_number = std::numeric_limits::digits; + constexpr size_t init_val_required_blocks = ull_bits_number / bits_per_block; + if constexpr(init_val_required_blocks == 1) + { + m_blocks[0] = init_val; + } + else + { + const unsigned long long block_mask = static_cast(one_block); + const size_t blocks_to_init = std::min(m_blocks.size(), init_val_required_blocks); + for(size_t i = 0; i < blocks_to_init; ++i) + { + m_blocks[i] = block_type((init_val >> (i * bits_per_block) & block_mask)); + } + } + sanitize(); + } + + template + constexpr dynamic_bitset::dynamic_bitset(std::initializer_list init_vals, + const allocator_type& allocator) + : m_blocks(allocator) + , m_bits_number(0) + { + append(init_vals); + } + + template + template + constexpr dynamic_bitset::dynamic_bitset( + std::basic_string_view<_CharT, _Traits> str, + typename std::basic_string_view<_CharT, _Traits>::size_type pos, + typename std::basic_string_view<_CharT, _Traits>::size_type n, + _CharT zero, + _CharT one, + const allocator_type& allocator) + : m_blocks(allocator) + , m_bits_number(0) + { + assert(pos < str.size()); + init_from_string(str, pos, n, zero, one); + } + + template + template + constexpr dynamic_bitset::dynamic_bitset( + const std::basic_string<_CharT, _Traits, _Alloc>& str, + typename std::basic_string<_CharT, _Traits, _Alloc>::size_type pos, + typename std::basic_string<_CharT, _Traits, _Alloc>::size_type n, + _CharT zero, + _CharT one, + const allocator_type& allocator) + : m_blocks(allocator) + , m_bits_number(0) + { + assert(pos < str.size()); + init_from_string(std::basic_string_view<_CharT, _Traits>(str), pos, n, zero, one); + } + + template + template + constexpr dynamic_bitset::dynamic_bitset(const _CharT* str, + typename std::basic_string<_CharT>::size_type pos, + typename std::basic_string<_CharT>::size_type n, + _CharT zero, + _CharT one, + const allocator_type& allocator) + : m_blocks(allocator) + , m_bits_number(0) + { + init_from_string(std::basic_string_view<_CharT, _Traits>(str), pos, n, zero, one); + } + + template + constexpr void dynamic_bitset::resize(size_type nbits, bool value) + { + if(nbits == m_bits_number) + { + return; + } + + const size_type old_num_blocks = num_blocks(); + const size_type new_num_blocks = blocks_required(nbits); + + const block_type init_value = value ? one_block : zero_block; + if(new_num_blocks != old_num_blocks) + { + m_blocks.resize(new_num_blocks, init_value); + } + + if(value && nbits > m_bits_number && old_num_blocks > 0) + { + // set value of the new bits in the old last block + const size_type extra_bits = extra_bits_number(); + if(extra_bits > 0) + { + m_blocks[old_num_blocks - 1] |= static_cast(init_value << extra_bits); + } + } + + m_bits_number = nbits; + sanitize(); + assert(check_consistency()); + } + + template + constexpr void dynamic_bitset::clear() + { + m_blocks.clear(); + m_bits_number = 0; + } + + template + constexpr void dynamic_bitset::push_back(bool value) + { + const size_type new_last_bit = m_bits_number++; + if(m_bits_number <= m_blocks.size() * bits_per_block) + { + if(value) + { + set(new_last_bit, value); + } + } + else + { + m_blocks.push_back(block_type(value)); + } + assert(operator[](new_last_bit) == value); + assert(check_consistency()); + } + + template + constexpr void dynamic_bitset::pop_back() + { + if(empty()) + { + return; + } + + --m_bits_number; + if(m_blocks.size() > blocks_required(m_bits_number)) + { + m_blocks.pop_back(); + // no extra bits: sanitize not required + assert(extra_bits_number() == 0); + } + else + { + sanitize(); + } + assert(check_consistency()); + } + + template + constexpr void dynamic_bitset::append(block_type block) + { + const size_type extra_bits = extra_bits_number(); + if(extra_bits == 0) + { + m_blocks.push_back(block); + } + else + { + last_block() |= static_cast(block << extra_bits); + m_blocks.push_back(block_type(block >> (bits_per_block - extra_bits))); + } + + m_bits_number += bits_per_block; + assert(check_consistency()); + } + + template + constexpr void dynamic_bitset::append(std::initializer_list blocks) + { + if(blocks.size() == 0) + { + return; + } + + append(std::cbegin(blocks), std::cend(blocks)); + } + + template + template + constexpr void dynamic_bitset::append(BlockInputIterator first, BlockInputIterator last) + { + if(first == last) + { + return; + } + + // if random access iterators, std::distance complexity is constant + if constexpr(std::is_same_v::iterator_category, + std::random_access_iterator_tag>) + { + assert(std::distance(first, last) > 0); + m_blocks.reserve(m_blocks.size() + static_cast(std::distance(first, last))); + } + + const size_type extra_bits = extra_bits_number(); + const size_type unused_bits = unused_bits_number(); + if(extra_bits == 0) + { + auto pos = m_blocks.insert(std::end(m_blocks), first, last); + assert(std::distance(pos, std::end(m_blocks)) > 0); + m_bits_number += static_cast(std::distance(pos, std::end(m_blocks))) * bits_per_block; + } + else + { + last_block() |= static_cast(*first << extra_bits); + block_type block = block_type(*first >> unused_bits); + ++first; + while(first != last) + { + block |= static_cast(*first << extra_bits); + m_blocks.push_back(block); + m_bits_number += bits_per_block; + block = block_type(*first >> unused_bits); + ++first; + } + m_blocks.push_back(block); + m_bits_number += bits_per_block; + } + + assert(check_consistency()); + } + + template + constexpr dynamic_bitset& + dynamic_bitset::operator&=(const dynamic_bitset& rhs) + { + assert(size() == rhs.size()); + // apply(rhs, std::bit_and()); + for(size_type i = 0; i < m_blocks.size(); ++i) + { + m_blocks[i] &= rhs.m_blocks[i]; + } + return *this; + } + + template + constexpr dynamic_bitset& + dynamic_bitset::operator|=(const dynamic_bitset& rhs) + { + assert(size() == rhs.size()); + // apply(rhs, std::bit_or()); + for(size_type i = 0; i < m_blocks.size(); ++i) + { + m_blocks[i] |= rhs.m_blocks[i]; + } + return *this; + } + + template + constexpr dynamic_bitset& + dynamic_bitset::operator^=(const dynamic_bitset& rhs) + { + assert(size() == rhs.size()); + // apply(rhs, std::bit_xor()); + for(size_type i = 0; i < m_blocks.size(); ++i) + { + m_blocks[i] ^= rhs.m_blocks[i]; + } + return *this; + } + + template + constexpr dynamic_bitset& + dynamic_bitset::operator-=(const dynamic_bitset& rhs) + { + assert(size() == rhs.size()); + // apply(rhs, [](const block_type& x, const block_type& y) { return (x & ~y); }); + for(size_type i = 0; i < m_blocks.size(); ++i) + { + m_blocks[i] &= static_cast(~rhs.m_blocks[i]); + } + return *this; + } + + template + constexpr dynamic_bitset& dynamic_bitset::operator<<=(size_type shift) + { + if(shift != 0) + { + if(shift >= m_bits_number) + { + reset(); + } + else + { + apply_left_shift(shift); + sanitize(); // unused bits can have changed, reset them to 0 + } + } + return *this; + } + + template + constexpr dynamic_bitset& dynamic_bitset::operator>>=(size_type shift) + { + if(shift != 0) + { + if(shift >= m_bits_number) + { + reset(); + } + else + { + apply_right_shift(shift); + } + } + return *this; + } + + template + constexpr dynamic_bitset dynamic_bitset::operator<<(size_type shift) const + { + return dynamic_bitset(*this) <<= shift; + } + + template + constexpr dynamic_bitset dynamic_bitset::operator>>(size_type shift) const + { + return dynamic_bitset(*this) >>= shift; + } + + template + constexpr dynamic_bitset dynamic_bitset::operator~() const + { + dynamic_bitset bitset(*this); + bitset.flip(); + return bitset; + } + + template + constexpr dynamic_bitset& + dynamic_bitset::set(size_type pos, size_type len, bool value) + { + assert(pos < size()); + if(len == 0) + { + return *this; + } + assert(pos + len - 1 < size()); + + const size_type first_block = block_index(pos); + const size_type last_block = block_index(pos + len - 1); + const size_type first_bit_index = bit_index(pos); + const size_type last_bit_index = bit_index(pos + len - 1); + + if(first_block == last_block) + { + set_block_bits(m_blocks[first_block], first_bit_index, last_bit_index, value); + } + else + { + size_type first_full_block = first_block; + size_type last_full_block = last_block; + + if(first_bit_index != 0) + { + ++first_full_block; // first block is not full + set_block_bits(m_blocks[first_block], first_bit_index, block_last_bit_index, value); + } + + if(last_bit_index != block_last_bit_index) + { + --last_full_block; // last block is not full + set_block_bits(m_blocks[last_block], 0, last_bit_index, value); + } + + const block_type full_block = value ? one_block : zero_block; + for(size_type i = first_full_block; i <= last_full_block; ++i) + { + m_blocks[i] = full_block; + } + } + + return *this; + } + + template + constexpr dynamic_bitset& dynamic_bitset::set(size_type pos, bool value) + { + assert(pos < size()); + + if(value) + { + m_blocks[block_index(pos)] |= bit_mask(pos); + } + else + { + m_blocks[block_index(pos)] &= static_cast(~bit_mask(pos)); + } + + return *this; + } + + template + constexpr dynamic_bitset& dynamic_bitset::set() + { + std::fill(std::begin(m_blocks), std::end(m_blocks), one_block); + sanitize(); + return *this; + } + + template + constexpr dynamic_bitset& dynamic_bitset::reset(size_type pos, size_type len) + { + return set(pos, len, false); + } + + template + constexpr dynamic_bitset& dynamic_bitset::reset(size_type pos) + { + return set(pos, false); + } + + template + constexpr dynamic_bitset& dynamic_bitset::reset() + { + std::fill(std::begin(m_blocks), std::end(m_blocks), zero_block); + return *this; + } + + template + constexpr dynamic_bitset& dynamic_bitset::flip(size_type pos, size_type len) + { + assert(pos < size()); + if(len == 0) + { + return *this; + } + assert(pos + len - 1 < size()); + + const size_type first_block = block_index(pos); + const size_type last_block = block_index(pos + len - 1); + const size_type first_bit_index = bit_index(pos); + const size_type last_bit_index = bit_index(pos + len - 1); + + if(first_block == last_block) + { + flip_block_bits(m_blocks[first_block], first_bit_index, last_bit_index); + } + else + { + size_type first_full_block = first_block; + size_type last_full_block = last_block; + + if(first_bit_index != 0) + { + ++first_full_block; // first block is not full + flip_block_bits(m_blocks[first_block], first_bit_index, block_last_bit_index); + } + + if(last_bit_index != block_last_bit_index) + { + --last_full_block; // last block is not full + flip_block_bits(m_blocks[last_block], 0, last_bit_index); + } + + for(size_type i = first_full_block; i <= last_full_block; ++i) + { + m_blocks[i] = block_type(~m_blocks[i]); + } + } + + return *this; + } + + template + constexpr dynamic_bitset& dynamic_bitset::flip(size_type pos) + { + assert(pos < size()); + m_blocks[block_index(pos)] ^= bit_mask(pos); + return *this; + } + + template + constexpr dynamic_bitset& dynamic_bitset::flip() + { + std::transform(std::cbegin(m_blocks), std::cend(m_blocks), std::begin(m_blocks), std::bit_not()); + sanitize(); + return *this; + } + + template + constexpr bool dynamic_bitset::test(size_type pos) const + { + assert(pos < size()); + return (m_blocks[block_index(pos)] & bit_mask(pos)) != zero_block; + } + + template + constexpr bool dynamic_bitset::test_set(size_type pos, bool value) + { + bool const result = test(pos); + if(result != value) + { + set(pos, value); + } + return result; + } + + template + constexpr bool dynamic_bitset::all() const + { + if(empty()) + { + return true; + } + + const block_type full_block = one_block; + if(extra_bits_number() == 0) + { + for(const block_type& block: m_blocks) + { + if(block != full_block) + { + return false; + } + } + } + else + { + for(size_type i = 0; i < m_blocks.size() - 1; ++i) + { + if(m_blocks[i] != full_block) + { + return false; + } + } + if(last_block() != (full_block >> unused_bits_number())) + { + return false; + } + } + return true; + } + + template + constexpr bool dynamic_bitset::any() const + { + for(const block_type& block: m_blocks) + { + if(block != zero_block) + { + return true; + } + } + return false; + } + + template + constexpr bool dynamic_bitset::none() const + { + return !any(); + } + + template + constexpr typename dynamic_bitset::size_type + dynamic_bitset::count() const noexcept + { + if(empty()) + { + return 0; + } #if DYNAMIC_BITSET_CAN_USE_LIBPOPCNT - const size_type count = - static_cast(popcnt(m_blocks.data(), m_blocks.size() * sizeof(block_type))); + const size_type count = static_cast(popcnt(m_blocks.data(), m_blocks.size() * sizeof(block_type))); #else - size_type count = 0; - - // full blocks - for(size_type i = 0; i < m_blocks.size() - 1; ++i) - { - count += block_count(m_blocks[i]); - } - - // last block - const block_type& block = last_block(); - const size_type extra_bits = extra_bits_number(); - if(extra_bits == 0) - { - count += block_count(block); - } - else - { - count += block_count(block, extra_bits); - } + size_type count = 0; + + // full blocks + for(size_type i = 0; i < m_blocks.size() - 1; ++i) + { + count += block_count(m_blocks[i]); + } + + // last block + const block_type& block = last_block(); + const size_type extra_bits = extra_bits_number(); + if(extra_bits == 0) + { + count += block_count(block); + } + else + { + count += block_count(block, extra_bits); + } #endif - return count; -} - -template -constexpr typename dynamic_bitset::reference dynamic_bitset:: -operator[](size_type pos) -{ - assert(pos < size()); - return dynamic_bitset::reference(*this, pos); -} - -template -constexpr typename dynamic_bitset::const_reference dynamic_bitset< - Block, - Allocator>::operator[](size_type pos) const -{ - return test(pos); -} - -template -constexpr typename dynamic_bitset::size_type dynamic_bitset::size() - const noexcept -{ - return m_bits_number; -} - -template -constexpr typename dynamic_bitset::size_type dynamic_bitset:: - num_blocks() const noexcept -{ - return m_blocks.size(); -} - -template -constexpr bool dynamic_bitset::empty() const noexcept -{ - return size() == 0; -} - -template -constexpr typename dynamic_bitset::size_type dynamic_bitset::capacity() - const noexcept -{ - return m_blocks.capacity() * bits_per_block; -} - -template -constexpr void dynamic_bitset::reserve(size_type num_bits) -{ - m_blocks.reserve(blocks_required(num_bits)); -} - -template -constexpr void dynamic_bitset::shrink_to_fit() -{ - m_blocks.shrink_to_fit(); -} - -template -constexpr bool dynamic_bitset::is_subset_of( - const dynamic_bitset& bitset) const -{ - assert(size() == bitset.size()); - for(size_type i = 0; i < m_blocks.size(); ++i) - { - if((m_blocks[i] & ~bitset.m_blocks[i]) != zero_block) - { - return false; - } - } - return true; -} - -template -constexpr bool dynamic_bitset::is_proper_subset_of( - const dynamic_bitset& bitset) const -{ - assert(size() == bitset.size()); - bool is_proper = false; - for(size_type i = 0; i < m_blocks.size(); ++i) - { - const block_type& self_block = m_blocks[i]; - const block_type& other_block = bitset.m_blocks[i]; - - if((self_block & ~other_block) != zero_block) - { - return false; - } - if((~self_block & other_block) != zero_block) - { - is_proper = true; - } - } - return is_proper; -} - -template -constexpr bool dynamic_bitset::intersects( - const dynamic_bitset& bitset) const -{ - const size_type min_blocks_number = std::min(m_blocks.size(), bitset.m_blocks.size()); - for(size_type i = 0; i < min_blocks_number; ++i) - { - if((m_blocks[i] & bitset.m_blocks[i]) != zero_block) - { - return true; - } - } - return false; -} - -template -constexpr typename dynamic_bitset::size_type dynamic_bitset:: - find_first() const -{ - for(size_type i = 0; i < m_blocks.size(); ++i) - { - if(m_blocks[i] != zero_block) - { - return i * bits_per_block + count_block_trailing_zero(m_blocks[i]); - } - } - return npos; -} - -template -constexpr typename dynamic_bitset::size_type dynamic_bitset:: - find_next(size_type prev) const -{ - if(empty() || prev >= (size() - 1)) - { - return npos; - } - - const size_type first_bit = prev + 1; - const size_type first_block = block_index(first_bit); - const size_type first_bit_index = bit_index(first_bit); - const block_type first_block_shifted = block_type(m_blocks[first_block] >> first_bit_index); - - if(first_block_shifted != zero_block) - { - return first_bit + count_block_trailing_zero(first_block_shifted); - } - else - { - for(size_type i = first_block + 1; i < m_blocks.size(); ++i) - { - if(m_blocks[i] != zero_block) - { - return i * bits_per_block + count_block_trailing_zero(m_blocks[i]); - } - } - } - return npos; -} - -template -constexpr void dynamic_bitset::swap(dynamic_bitset& other) -{ - std::swap(m_blocks, other.m_blocks); - std::swap(m_bits_number, other.m_bits_number); -} - -template -constexpr typename dynamic_bitset::allocator_type dynamic_bitset< - Block, - Allocator>::get_allocator() const -{ - return m_blocks.get_allocator(); -} - -template -template -constexpr std::basic_string<_CharT, _Traits, _Alloc> dynamic_bitset::to_string( - _CharT zero, - _CharT one) const -{ - const size_type len = size(); - std::basic_string<_CharT, _Traits, _Alloc> str(len, zero); - for(size_type i_block = 0; i_block < m_blocks.size(); ++i_block) - { - if(m_blocks[i_block] == zero_block) - { - continue; - } - block_type mask = block_type(1); - const size_type limit = - i_block * bits_per_block < len ? len - i_block * bits_per_block : bits_per_block; - for(size_type i_bit = 0; i_bit < limit; ++i_bit) - { - if((m_blocks[i_block] & mask) != zero_block) - { - _Traits::assign(str[len - (i_block * bits_per_block + i_bit + 1)], one); - } - // mask <<= 1; not used because it trigger -Wconversion because of integral promotion for block_type smaller than int - mask = static_cast(mask << 1); - } - } - return str; -} - -template -constexpr unsigned long dynamic_bitset::to_ulong() const -{ - if(m_bits_number == 0) - { - return 0; - } - - constexpr size_t ul_bits_number = std::numeric_limits::digits; - if(find_next(ul_bits_number - 1) != npos) - { - throw std::overflow_error("sul::dynamic_bitset::to_ulong"); - } - - unsigned long result = 0; - const size_type result_bits_number = std::min(ul_bits_number, m_bits_number); - for(size_type i_block = 0; i_block <= block_index(result_bits_number - 1); ++i_block) - { - result |= (static_cast(m_blocks[i_block]) << (i_block * bits_per_block)); - } - - return result; -} - -template -constexpr unsigned long long dynamic_bitset::to_ullong() const -{ - if(m_bits_number == 0) - { - return 0; - } - - constexpr size_t ull_bits_number = std::numeric_limits::digits; - if(find_next(ull_bits_number - 1) != npos) - { - throw std::overflow_error("sul::dynamic_bitset::to_ullong"); - } - - unsigned long long result = 0; - const size_type result_bits_number = std::min(ull_bits_number, m_bits_number); - for(size_type i_block = 0; i_block <= block_index(result_bits_number - 1); ++i_block) - { - result |= - (static_cast(m_blocks[i_block]) << (i_block * bits_per_block)); - } - - return result; -} - -template -template -constexpr void dynamic_bitset::iterate_bits_on(Function&& function, - Parameters&&... parameters) const -{ - if constexpr(!std::is_invocable_v) - { - static_assert(dependent_false::value, "Function take invalid arguments"); - // function should take (size_t, parameters...) as arguments - } - - if constexpr(std::is_same_v, void>) - { - size_type i_bit = find_first(); - while(i_bit != npos) - { - std::invoke( - std::forward(function), i_bit, std::forward(parameters)...); - i_bit = find_next(i_bit); - } - } - else if constexpr(std::is_convertible_v, - bool>) - { - size_type i_bit = find_first(); - while(i_bit != npos) - { - if(!std::invoke( - std::forward(function), i_bit, std::forward(parameters)...)) - { - break; - } - i_bit = find_next(i_bit); - } - } - else - { - static_assert(dependent_false::value, "Function have invalid return type"); - // return type should be void, or convertible to bool - } -} - -template -constexpr typename dynamic_bitset::block_type* dynamic_bitset:: - data() noexcept -{ - return m_blocks.data(); -} - -template -constexpr const typename dynamic_bitset::block_type* dynamic_bitset< - Block, - Allocator>::data() const noexcept -{ - return m_blocks.data(); -} - -template -[[nodiscard]] constexpr bool operator==(const dynamic_bitset& lhs, - const dynamic_bitset& rhs) -{ - return (lhs.m_bits_number == rhs.m_bits_number) && (lhs.m_blocks == rhs.m_blocks); -} - -template -[[nodiscard]] constexpr bool operator<(const dynamic_bitset& lhs, - const dynamic_bitset& rhs) -{ - using size_type = typename dynamic_bitset::size_type; - using block_type = typename dynamic_bitset::block_type; - const size_type lhs_size = lhs.size(); - const size_type rhs_size = rhs.size(); - const size_type lhs_blocks_size = lhs.m_blocks.size(); - const size_type rhs_blocks_size = rhs.m_blocks.size(); - - if(lhs_size == rhs_size) - { - // if comparison of two empty bitsets - if(lhs_size == 0) - { - return false; - } - - for(size_type i = lhs_blocks_size - 1; i > 0; --i) - { - if(lhs.m_blocks[i] != rhs.m_blocks[i]) - { - return lhs.m_blocks[i] < rhs.m_blocks[i]; - } - } - return lhs.m_blocks[0] < rhs.m_blocks[0]; - } - - // empty bitset inferior to 0-only bitset - if(lhs_size == 0) - { - return true; - } - if(rhs_size == 0) - { - return false; - } - - const bool rhs_longer = rhs_size > lhs_size; - const dynamic_bitset& longest_bitset = rhs_longer ? rhs : lhs; - const size_type longest_blocks_size = std::max(lhs_blocks_size, rhs_blocks_size); - const size_type shortest_blocks_size = std::min(lhs_blocks_size, rhs_blocks_size); - for(size_type i = longest_blocks_size - 1; i >= shortest_blocks_size; --i) - { - if(longest_bitset.m_blocks[i] != block_type(0)) - { - return rhs_longer; - } - } - - for(size_type i = shortest_blocks_size - 1; i > 0; --i) - { - if(lhs.m_blocks[i] != rhs.m_blocks[i]) - { - return lhs.m_blocks[i] < rhs.m_blocks[i]; - } - } - if(lhs.m_blocks[0] != rhs.m_blocks[0]) - { - return lhs.m_blocks[0] < rhs.m_blocks[0]; - } - return lhs_size < rhs_size; -} - -//================================================================================================= -// dynamic_bitset private functions implementations -//================================================================================================= - -template -constexpr typename dynamic_bitset::size_type dynamic_bitset:: - blocks_required(size_type nbits) noexcept -{ - return nbits / bits_per_block + static_cast(nbits % bits_per_block > 0); -} - -template -constexpr typename dynamic_bitset::size_type dynamic_bitset:: - block_index(size_type pos) noexcept -{ - return pos / bits_per_block; -} - -template -constexpr typename dynamic_bitset::size_type dynamic_bitset:: - bit_index(size_type pos) noexcept -{ - return pos % bits_per_block; -} - -template -constexpr typename dynamic_bitset::block_type dynamic_bitset:: - bit_mask(size_type pos) noexcept -{ - return block_type(block_type(1) << bit_index(pos)); -} - -template -constexpr typename dynamic_bitset::block_type dynamic_bitset:: - bit_mask(size_type first, size_type last) noexcept -{ - first = bit_index(first); - last = bit_index(last); - if(last == (block_last_bit_index)) - { - return block_type(one_block << first); - } - else - { - return block_type(((block_type(1) << (last + 1)) - 1) ^ ((block_type(1) << first) - 1)); - } -} - -template -constexpr void dynamic_bitset::set_block_bits(block_type& block, - size_type first, - size_type last, - bool val) noexcept -{ - if(val) - { - block |= bit_mask(first, last); - } - else - { - block &= static_cast(~bit_mask(first, last)); - } -} - -template -constexpr void dynamic_bitset::flip_block_bits(block_type& block, - size_type first, - size_type last) noexcept -{ - block ^= bit_mask(first, last); -} - -template -constexpr typename dynamic_bitset::size_type dynamic_bitset:: - block_count(const block_type& block) noexcept -{ + return count; + } + + template + constexpr typename dynamic_bitset::reference + dynamic_bitset::operator[](size_type pos) + { + assert(pos < size()); + return dynamic_bitset::reference(*this, pos); + } + + template + constexpr typename dynamic_bitset::const_reference + dynamic_bitset::operator[](size_type pos) const + { + return test(pos); + } + + template + constexpr typename dynamic_bitset::size_type + dynamic_bitset::size() const noexcept + { + return m_bits_number; + } + + template + constexpr typename dynamic_bitset::size_type + dynamic_bitset::num_blocks() const noexcept + { + return m_blocks.size(); + } + + template + constexpr bool dynamic_bitset::empty() const noexcept + { + return size() == 0; + } + + template + constexpr typename dynamic_bitset::size_type + dynamic_bitset::capacity() const noexcept + { + return m_blocks.capacity() * bits_per_block; + } + + template + constexpr void dynamic_bitset::reserve(size_type num_bits) + { + m_blocks.reserve(blocks_required(num_bits)); + } + + template + constexpr void dynamic_bitset::shrink_to_fit() + { + m_blocks.shrink_to_fit(); + } + + template + constexpr bool dynamic_bitset::is_subset_of(const dynamic_bitset& bitset) const + { + assert(size() == bitset.size()); + for(size_type i = 0; i < m_blocks.size(); ++i) + { + if((m_blocks[i] & ~bitset.m_blocks[i]) != zero_block) + { + return false; + } + } + return true; + } + + template + constexpr bool + dynamic_bitset::is_proper_subset_of(const dynamic_bitset& bitset) const + { + assert(size() == bitset.size()); + bool is_proper = false; + for(size_type i = 0; i < m_blocks.size(); ++i) + { + const block_type& self_block = m_blocks[i]; + const block_type& other_block = bitset.m_blocks[i]; + + if((self_block & ~other_block) != zero_block) + { + return false; + } + if((~self_block & other_block) != zero_block) + { + is_proper = true; + } + } + return is_proper; + } + + template + constexpr bool dynamic_bitset::intersects(const dynamic_bitset& bitset) const + { + const size_type min_blocks_number = std::min(m_blocks.size(), bitset.m_blocks.size()); + for(size_type i = 0; i < min_blocks_number; ++i) + { + if((m_blocks[i] & bitset.m_blocks[i]) != zero_block) + { + return true; + } + } + return false; + } + + template + constexpr typename dynamic_bitset::size_type dynamic_bitset::find_first() const + { + for(size_type i = 0; i < m_blocks.size(); ++i) + { + if(m_blocks[i] != zero_block) + { + return i * bits_per_block + count_block_trailing_zero(m_blocks[i]); + } + } + return npos; + } + + template + constexpr typename dynamic_bitset::size_type + dynamic_bitset::find_next(size_type prev) const + { + if(empty() || prev >= (size() - 1)) + { + return npos; + } + + const size_type first_bit = prev + 1; + const size_type first_block = block_index(first_bit); + const size_type first_bit_index = bit_index(first_bit); + const block_type first_block_shifted = block_type(m_blocks[first_block] >> first_bit_index); + + if(first_block_shifted != zero_block) + { + return first_bit + count_block_trailing_zero(first_block_shifted); + } + else + { + for(size_type i = first_block + 1; i < m_blocks.size(); ++i) + { + if(m_blocks[i] != zero_block) + { + return i * bits_per_block + count_block_trailing_zero(m_blocks[i]); + } + } + } + return npos; + } + + template + constexpr void dynamic_bitset::swap(dynamic_bitset& other) + { + std::swap(m_blocks, other.m_blocks); + std::swap(m_bits_number, other.m_bits_number); + } + + template + constexpr typename dynamic_bitset::allocator_type + dynamic_bitset::get_allocator() const + { + return m_blocks.get_allocator(); + } + + template + template + constexpr std::basic_string<_CharT, _Traits, _Alloc> dynamic_bitset::to_string(_CharT zero, + _CharT one) const + { + const size_type len = size(); + std::basic_string<_CharT, _Traits, _Alloc> str(len, zero); + for(size_type i_block = 0; i_block < m_blocks.size(); ++i_block) + { + if(m_blocks[i_block] == zero_block) + { + continue; + } + block_type mask = block_type(1); + const size_type limit = i_block * bits_per_block < len ? len - i_block * bits_per_block : bits_per_block; + for(size_type i_bit = 0; i_bit < limit; ++i_bit) + { + if((m_blocks[i_block] & mask) != zero_block) + { + _Traits::assign(str[len - (i_block * bits_per_block + i_bit + 1)], one); + } + // mask <<= 1; not used because it trigger -Wconversion + // because of integral promotion for block_type smaller than int + mask = static_cast(mask << 1); + } + } + return str; + } + + template + constexpr unsigned long dynamic_bitset::to_ulong() const + { + if(m_bits_number == 0) + { + return 0; + } + + constexpr size_t ul_bits_number = std::numeric_limits::digits; + if(find_next(ul_bits_number - 1) != npos) + { + throw std::overflow_error("sul::dynamic_bitset::to_ulong"); + } + + unsigned long result = 0; + const size_type result_bits_number = std::min(ul_bits_number, m_bits_number); + for(size_type i_block = 0; i_block <= block_index(result_bits_number - 1); ++i_block) + { + result |= (static_cast(m_blocks[i_block]) << (i_block * bits_per_block)); + } + + return result; + } + + template + constexpr unsigned long long dynamic_bitset::to_ullong() const + { + if(m_bits_number == 0) + { + return 0; + } + + constexpr size_t ull_bits_number = std::numeric_limits::digits; + if(find_next(ull_bits_number - 1) != npos) + { + throw std::overflow_error("sul::dynamic_bitset::to_ullong"); + } + + unsigned long long result = 0; + const size_type result_bits_number = std::min(ull_bits_number, m_bits_number); + for(size_type i_block = 0; i_block <= block_index(result_bits_number - 1); ++i_block) + { + result |= (static_cast(m_blocks[i_block]) << (i_block * bits_per_block)); + } + + return result; + } + + template + template + constexpr void dynamic_bitset::iterate_bits_on(Function&& function, + Parameters&&... parameters) const + { + if constexpr(!std::is_invocable_v) + { + static_assert(dependent_false::value, "Function take invalid arguments"); + // function should take (size_t, parameters...) as arguments + } + + if constexpr(std::is_same_v, void>) + { + size_type i_bit = find_first(); + while(i_bit != npos) + { + std::invoke(std::forward(function), i_bit, std::forward(parameters)...); + i_bit = find_next(i_bit); + } + } + else if constexpr(std::is_convertible_v, bool>) + { + size_type i_bit = find_first(); + while(i_bit != npos) + { + if(!std::invoke(std::forward(function), i_bit, std::forward(parameters)...)) + { + break; + } + i_bit = find_next(i_bit); + } + } + else + { + static_assert(dependent_false::value, "Function have invalid return type"); + // return type should be void, or convertible to bool + } + } + + template + constexpr typename dynamic_bitset::block_type* dynamic_bitset::data() noexcept + { + return m_blocks.data(); + } + + template + constexpr const typename dynamic_bitset::block_type* + dynamic_bitset::data() const noexcept + { + return m_blocks.data(); + } + + template + [[nodiscard]] constexpr bool operator==(const dynamic_bitset& lhs, + const dynamic_bitset& rhs) + { + return (lhs.m_bits_number == rhs.m_bits_number) && (lhs.m_blocks == rhs.m_blocks); + } + + template + [[nodiscard]] constexpr bool operator<(const dynamic_bitset& lhs, + const dynamic_bitset& rhs) + { + using size_type = typename dynamic_bitset::size_type; + using block_type = typename dynamic_bitset::block_type; + const size_type lhs_size = lhs.size(); + const size_type rhs_size = rhs.size(); + const size_type lhs_blocks_size = lhs.m_blocks.size(); + const size_type rhs_blocks_size = rhs.m_blocks.size(); + + if(lhs_size == rhs_size) + { + // if comparison of two empty bitsets + if(lhs_size == 0) + { + return false; + } + + for(size_type i = lhs_blocks_size - 1; i > 0; --i) + { + if(lhs.m_blocks[i] != rhs.m_blocks[i]) + { + return lhs.m_blocks[i] < rhs.m_blocks[i]; + } + } + return lhs.m_blocks[0] < rhs.m_blocks[0]; + } + + // empty bitset inferior to 0-only bitset + if(lhs_size == 0) + { + return true; + } + if(rhs_size == 0) + { + return false; + } + + const bool rhs_longer = rhs_size > lhs_size; + const dynamic_bitset& longest_bitset = rhs_longer ? rhs : lhs; + const size_type longest_blocks_size = std::max(lhs_blocks_size, rhs_blocks_size); + const size_type shortest_blocks_size = std::min(lhs_blocks_size, rhs_blocks_size); + for(size_type i = longest_blocks_size - 1; i >= shortest_blocks_size; --i) + { + if(longest_bitset.m_blocks[i] != block_type(0)) + { + return rhs_longer; + } + } + + for(size_type i = shortest_blocks_size - 1; i > 0; --i) + { + if(lhs.m_blocks[i] != rhs.m_blocks[i]) + { + return lhs.m_blocks[i] < rhs.m_blocks[i]; + } + } + if(lhs.m_blocks[0] != rhs.m_blocks[0]) + { + return lhs.m_blocks[0] < rhs.m_blocks[0]; + } + return lhs_size < rhs_size; + } + + //================================================================================================= + // dynamic_bitset private functions implementations + //================================================================================================= + + template + constexpr typename dynamic_bitset::size_type + dynamic_bitset::blocks_required(size_type nbits) noexcept + { + return nbits / bits_per_block + static_cast(nbits % bits_per_block > 0); + } + + template + constexpr typename dynamic_bitset::size_type + dynamic_bitset::block_index(size_type pos) noexcept + { + return pos / bits_per_block; + } + + template + constexpr typename dynamic_bitset::size_type + dynamic_bitset::bit_index(size_type pos) noexcept + { + return pos % bits_per_block; + } + + template + constexpr typename dynamic_bitset::block_type + dynamic_bitset::bit_mask(size_type pos) noexcept + { + return block_type(block_type(1) << bit_index(pos)); + } + + template + constexpr typename dynamic_bitset::block_type + dynamic_bitset::bit_mask(size_type first, size_type last) noexcept + { + first = bit_index(first); + last = bit_index(last); + if(last == (block_last_bit_index)) + { + return block_type(one_block << first); + } + else + { + return block_type(((block_type(1) << (last + 1)) - 1) ^ ((block_type(1) << first) - 1)); + } + } + + template + constexpr void dynamic_bitset::set_block_bits(block_type& block, + size_type first, + size_type last, + bool val) noexcept + { + if(val) + { + block |= bit_mask(first, last); + } + else + { + block &= static_cast(~bit_mask(first, last)); + } + } + + template + constexpr void + dynamic_bitset::flip_block_bits(block_type& block, size_type first, size_type last) noexcept + { + block ^= bit_mask(first, last); + } + + template + constexpr typename dynamic_bitset::size_type + dynamic_bitset::block_count(const block_type& block) noexcept + { #if DYNAMIC_BITSET_CAN_USE_STD_BITOPS - return static_cast(std::popcount(block)); + return static_cast(std::popcount(block)); #else - if(block == zero_block) - { - return 0; - } - -# if DYNAMIC_BITSET_CAN_USE_GCC_BUILTIN || DYNAMIC_BITSET_CAN_USE_CLANG_BUILTIN_POPCOUNT - constexpr size_t u_bits_number = std::numeric_limits::digits; - constexpr size_t ul_bits_number = std::numeric_limits::digits; - constexpr size_t ull_bits_number = std::numeric_limits::digits; - if constexpr(bits_per_block <= u_bits_number) - { - return static_cast(__builtin_popcount(static_cast(block))); - } - else if constexpr(bits_per_block <= ul_bits_number) - { - return static_cast(__builtin_popcountl(static_cast(block))); - } - else if constexpr(bits_per_block <= ull_bits_number) - { - return static_cast(__builtin_popcountll(static_cast(block))); - } -# endif - - size_type count = 0; - block_type mask = 1; - for(size_type bit_index = 0; bit_index < bits_per_block; ++bit_index) - { - count += static_cast((block & mask) != zero_block); - // mask <<= 1; not used because it trigger -Wconversion because of integral promotion for block_type smaller than int - mask = static_cast(mask << 1); - } - return count; + if(block == zero_block) + { + return 0; + } + +# if DYNAMIC_BITSET_CAN_USE_GCC_BUILTIN || DYNAMIC_BITSET_CAN_USE_CLANG_BUILTIN_POPCOUNT + constexpr size_t u_bits_number = std::numeric_limits::digits; + constexpr size_t ul_bits_number = std::numeric_limits::digits; + constexpr size_t ull_bits_number = std::numeric_limits::digits; + if constexpr(bits_per_block <= u_bits_number) + { + return static_cast(__builtin_popcount(static_cast(block))); + } + else if constexpr(bits_per_block <= ul_bits_number) + { + return static_cast(__builtin_popcountl(static_cast(block))); + } + else if constexpr(bits_per_block <= ull_bits_number) + { + return static_cast(__builtin_popcountll(static_cast(block))); + } +# endif + + size_type count = 0; + block_type mask = 1; + for(size_type bit_index = 0; bit_index < bits_per_block; ++bit_index) + { + count += static_cast((block & mask) != zero_block); + // mask <<= 1; not used because it trigger -Wconversion + // because of integral promotion for block_type smaller than int + mask = static_cast(mask << 1); + } + return count; #endif -} + } -template -constexpr typename dynamic_bitset::size_type dynamic_bitset:: - block_count(const block_type& block, size_type nbits) noexcept -{ - assert(nbits <= bits_per_block); + template + constexpr typename dynamic_bitset::size_type + dynamic_bitset::block_count(const block_type& block, size_type nbits) noexcept + { + assert(nbits <= bits_per_block); #if DYNAMIC_BITSET_CAN_USE_STD_BITOPS - const block_type shifted_block = block_type(block << (bits_per_block - nbits)); - return static_cast(std::popcount(shifted_block)); + const block_type shifted_block = block_type(block << (bits_per_block - nbits)); + return static_cast(std::popcount(shifted_block)); #else - const block_type shifted_block = block_type(block << (bits_per_block - nbits)); - if(shifted_block == zero_block) - { - return 0; - } - -# if DYNAMIC_BITSET_CAN_USE_GCC_BUILTIN || DYNAMIC_BITSET_CAN_USE_CLANG_BUILTIN_POPCOUNT - constexpr size_t u_bits_number = std::numeric_limits::digits; - constexpr size_t ul_bits_number = std::numeric_limits::digits; - constexpr size_t ull_bits_number = std::numeric_limits::digits; - if constexpr(bits_per_block <= u_bits_number) - { - return static_cast(__builtin_popcount(static_cast(shifted_block))); - } - else if constexpr(bits_per_block <= ul_bits_number) - { - return static_cast( - __builtin_popcountl(static_cast(shifted_block))); - } - else if constexpr(bits_per_block <= ull_bits_number) - { - return static_cast( - __builtin_popcountll(static_cast(shifted_block))); - } -# endif - - size_type count = 0; - block_type mask = 1; - for(size_type bit_index = 0; bit_index < nbits; ++bit_index) - { - count += static_cast((block & mask) != zero_block); - // mask <<= 1; not used because it trigger -Wconversion because of integral promotion for block_type smaller than int - mask = static_cast(mask << 1); - } - - return count; + const block_type shifted_block = block_type(block << (bits_per_block - nbits)); + if(shifted_block == zero_block) + { + return 0; + } + +# if DYNAMIC_BITSET_CAN_USE_GCC_BUILTIN || DYNAMIC_BITSET_CAN_USE_CLANG_BUILTIN_POPCOUNT + constexpr size_t u_bits_number = std::numeric_limits::digits; + constexpr size_t ul_bits_number = std::numeric_limits::digits; + constexpr size_t ull_bits_number = std::numeric_limits::digits; + if constexpr(bits_per_block <= u_bits_number) + { + return static_cast(__builtin_popcount(static_cast(shifted_block))); + } + else if constexpr(bits_per_block <= ul_bits_number) + { + return static_cast(__builtin_popcountl(static_cast(shifted_block))); + } + else if constexpr(bits_per_block <= ull_bits_number) + { + return static_cast(__builtin_popcountll(static_cast(shifted_block))); + } +# endif + + size_type count = 0; + block_type mask = 1; + for(size_type bit_index = 0; bit_index < nbits; ++bit_index) + { + count += static_cast((block & mask) != zero_block); + // mask <<= 1; not used because it trigger -Wconversion + // because of integral promotion for block_type smaller than int + mask = static_cast(mask << 1); + } + + return count; #endif -} + } -template -constexpr typename dynamic_bitset::size_type dynamic_bitset:: - count_block_trailing_zero(const block_type& block) noexcept -{ - assert(block != zero_block); + template + constexpr typename dynamic_bitset::size_type + dynamic_bitset::count_block_trailing_zero(const block_type& block) noexcept + { + assert(block != zero_block); #if DYNAMIC_BITSET_CAN_USE_STD_BITOPS - return static_cast(std::countr_zero(block)); + return static_cast(std::countr_zero(block)); #else -# if DYNAMIC_BITSET_CAN_USE_GCC_BUILTIN || DYNAMIC_BITSET_CAN_USE_CLANG_BUILTIN_CTZ - constexpr size_t u_bits_number = std::numeric_limits::digits; - constexpr size_t ul_bits_number = std::numeric_limits::digits; - constexpr size_t ull_bits_number = std::numeric_limits::digits; - if constexpr(bits_per_block <= u_bits_number) - { - return static_cast(__builtin_ctz(static_cast(block))); - } - else if constexpr(bits_per_block <= ul_bits_number) - { - return static_cast(__builtin_ctzl(static_cast(block))); - } - else if constexpr(bits_per_block <= ull_bits_number) - { - return static_cast(__builtin_ctzll(static_cast(block))); - } - -# elif DYNAMIC_BITSET_CAN_USE_MSVC_BUILTIN_BITSCANFORWARD - constexpr size_t ul_bits_number = std::numeric_limits::digits; - constexpr size_t ui64_bits_number = std::numeric_limits::digits; - if constexpr(bits_per_block <= ul_bits_number) - { - unsigned long index = std::numeric_limits::max(); - _BitScanForward(&index, static_cast(block)); - return static_cast(index); - } - else if constexpr(bits_per_block <= ui64_bits_number) - { -# if DYNAMIC_BITSET_CAN_USE_MSVC_BUILTIN_BITSCANFORWARD64 - unsigned long index = std::numeric_limits::max(); - _BitScanForward64(&index, static_cast(block)); - return static_cast(index); -# else - constexpr unsigned long max_ul = std::numeric_limits::max(); - unsigned long low = block & max_ul; - if(low != 0) - { - unsigned long index = std::numeric_limits::max(); - _BitScanForward(&index, low); - return static_cast(index); - } - unsigned long high = block >> ul_bits_number; - unsigned long index = std::numeric_limits::max(); - _BitScanForward(&index, high); - return static_cast(ul_bits_number + index); -# endif - } -# endif - - block_type mask = block_type(1); - for(size_type i = 0; i < bits_per_block; ++i) - { - if((block & mask) != zero_block) - { - return i; - } - // mask <<= 1; not used because it trigger -Wconversion because of integral promotion for block_type smaller than int - mask = static_cast(mask << 1); - } - assert(false); // LCOV_EXCL_LINE: unreachable - return npos; // LCOV_EXCL_LINE: unreachable +# if DYNAMIC_BITSET_CAN_USE_GCC_BUILTIN || DYNAMIC_BITSET_CAN_USE_CLANG_BUILTIN_CTZ + constexpr size_t u_bits_number = std::numeric_limits::digits; + constexpr size_t ul_bits_number = std::numeric_limits::digits; + constexpr size_t ull_bits_number = std::numeric_limits::digits; + if constexpr(bits_per_block <= u_bits_number) + { + return static_cast(__builtin_ctz(static_cast(block))); + } + else if constexpr(bits_per_block <= ul_bits_number) + { + return static_cast(__builtin_ctzl(static_cast(block))); + } + else if constexpr(bits_per_block <= ull_bits_number) + { + return static_cast(__builtin_ctzll(static_cast(block))); + } + +# elif DYNAMIC_BITSET_CAN_USE_MSVC_BUILTIN_BITSCANFORWARD + constexpr size_t ul_bits_number = std::numeric_limits::digits; + constexpr size_t ui64_bits_number = std::numeric_limits::digits; + if constexpr(bits_per_block <= ul_bits_number) + { + unsigned long index = std::numeric_limits::max(); + _BitScanForward(&index, static_cast(block)); + return static_cast(index); + } + else if constexpr(bits_per_block <= ui64_bits_number) + { +# if DYNAMIC_BITSET_CAN_USE_MSVC_BUILTIN_BITSCANFORWARD64 + unsigned long index = std::numeric_limits::max(); + _BitScanForward64(&index, static_cast(block)); + return static_cast(index); +# else + constexpr unsigned long max_ul = std::numeric_limits::max(); + unsigned long low = block & max_ul; + if(low != 0) + { + unsigned long index = std::numeric_limits::max(); + _BitScanForward(&index, low); + return static_cast(index); + } + unsigned long high = block >> ul_bits_number; + unsigned long index = std::numeric_limits::max(); + _BitScanForward(&index, high); + return static_cast(ul_bits_number + index); +# endif + } +# endif + + block_type mask = block_type(1); + for(size_type i = 0; i < bits_per_block; ++i) + { + if((block & mask) != zero_block) + { + return i; + } + // mask <<= 1; not used because it trigger -Wconversion + // because of integral promotion for block_type smaller than int + mask = static_cast(mask << 1); + } + assert(false); // LCOV_EXCL_LINE: unreachable + return npos; // LCOV_EXCL_LINE: unreachable #endif -} - -template -template -constexpr void dynamic_bitset::init_from_string( - std::basic_string_view<_CharT, _Traits> str, - typename std::basic_string_view<_CharT, _Traits>::size_type pos, - typename std::basic_string_view<_CharT, _Traits>::size_type n, - [[maybe_unused]] _CharT zero, - _CharT one) -{ - assert(pos < str.size()); - - const size_type size = std::min(n, str.size() - pos); - m_bits_number = size; - - m_blocks.clear(); - m_blocks.resize(blocks_required(size)); - for(size_t i = 0; i < size; ++i) - { - const _CharT c = str[(pos + size - 1) - i]; - assert(c == zero || c == one); - if(c == one) - { - set(i); - } - } -} - -template -constexpr typename dynamic_bitset::block_type& dynamic_bitset:: - get_block(size_type pos) -{ - return m_blocks[block_index(pos)]; -} - -template -constexpr const typename dynamic_bitset::block_type& dynamic_bitset< - Block, - Allocator>::get_block(size_type pos) const -{ - return m_blocks[block_index(pos)]; -} - -template -constexpr typename dynamic_bitset::block_type& dynamic_bitset:: - last_block() -{ - return m_blocks[m_blocks.size() - 1]; -} - -template -constexpr typename dynamic_bitset::block_type dynamic_bitset:: - last_block() const -{ - return m_blocks[m_blocks.size() - 1]; -} - -template -constexpr typename dynamic_bitset::size_type dynamic_bitset:: - extra_bits_number() const noexcept -{ - return bit_index(m_bits_number); -} - -template -constexpr typename dynamic_bitset::size_type dynamic_bitset:: - unused_bits_number() const noexcept -{ - return bits_per_block - extra_bits_number(); -} - -template -template -constexpr void dynamic_bitset::apply( - const dynamic_bitset& other, - BinaryOperation binary_op) -{ - assert(num_blocks() == other.num_blocks()); - std::transform(std::cbegin(m_blocks), - std::cend(m_blocks), - std::cbegin(other.m_blocks), - std::begin(m_blocks), - binary_op); -} - -template -template -constexpr void dynamic_bitset::apply(UnaryOperation unary_op) -{ - std::transform(std::cbegin(m_blocks), std::cend(m_blocks), std::begin(m_blocks), unary_op); -} - -template -constexpr void dynamic_bitset::apply_left_shift(size_type shift) -{ - assert(shift > 0); - assert(shift < capacity()); - - const size_type blocks_shift = shift / bits_per_block; - const size_type bits_offset = shift % bits_per_block; - - if(bits_offset == 0) - { - for(size_type i = m_blocks.size() - 1; i >= blocks_shift; --i) - { - m_blocks[i] = m_blocks[i - blocks_shift]; - } - } - else - { - const size_type reverse_bits_offset = bits_per_block - bits_offset; - for(size_type i = m_blocks.size() - 1; i > blocks_shift; --i) - { - m_blocks[i] = - block_type((m_blocks[i - blocks_shift] << bits_offset) - | block_type(m_blocks[i - blocks_shift - 1] >> reverse_bits_offset)); - } - m_blocks[blocks_shift] = block_type(m_blocks[0] << bits_offset); - } - - // set bit that came at the right to 0 in unmodified blocks - std::fill(std::begin(m_blocks), - std::begin(m_blocks) - + static_cast(blocks_shift), - zero_block); -} - -template -constexpr void dynamic_bitset::apply_right_shift(size_type shift) -{ - assert(shift > 0); - assert(shift < capacity()); - - const size_type blocks_shift = shift / bits_per_block; - const size_type bits_offset = shift % bits_per_block; - const size_type last_block_to_shift = m_blocks.size() - blocks_shift - 1; - - if(bits_offset == 0) - { - for(size_type i = 0; i <= last_block_to_shift; ++i) - { - m_blocks[i] = m_blocks[i + blocks_shift]; - } - } - else - { - const size_type reverse_bits_offset = bits_per_block - bits_offset; - for(size_type i = 0; i < last_block_to_shift; ++i) - { - m_blocks[i] = - block_type((m_blocks[i + blocks_shift] >> bits_offset) - | block_type(m_blocks[i + blocks_shift + 1] << reverse_bits_offset)); - } - m_blocks[last_block_to_shift] = block_type(m_blocks[m_blocks.size() - 1] >> bits_offset); - } - - // set bit that came at the left to 0 in unmodified blocks - std::fill( - std::begin(m_blocks) - + static_cast(last_block_to_shift + 1), - std::end(m_blocks), - zero_block); -} - -template -constexpr void dynamic_bitset::sanitize() -{ - size_type shift = m_bits_number % bits_per_block; - if(shift > 0) - { - last_block() &= static_cast(~(one_block << shift)); - } -} - -template -constexpr bool dynamic_bitset::check_unused_bits() const noexcept -{ - const size_type extra_bits = extra_bits_number(); - if(extra_bits > 0) - { - return (last_block() & (one_block << extra_bits)) == zero_block; - } - return true; -} - -template -constexpr bool dynamic_bitset::check_size() const noexcept -{ - return blocks_required(size()) == m_blocks.size(); -} - -template -constexpr bool dynamic_bitset::check_consistency() const noexcept -{ - return check_unused_bits() && check_size(); -} - -//================================================================================================= -// dynamic_bitset external functions implementations -//================================================================================================= - -template -constexpr bool operator!=(const dynamic_bitset& lhs, - const dynamic_bitset& rhs) -{ - return !(lhs == rhs); -} - -template -constexpr bool operator<=(const dynamic_bitset& lhs, - const dynamic_bitset& rhs) -{ - return !(rhs < lhs); -} - -template -constexpr bool operator>(const dynamic_bitset& lhs, - const dynamic_bitset& rhs) -{ - return rhs < lhs; -} - -template -constexpr bool operator>=(const dynamic_bitset& lhs, - const dynamic_bitset& rhs) -{ - return !(lhs < rhs); -} - -template -constexpr dynamic_bitset operator&(const dynamic_bitset& lhs, - const dynamic_bitset& rhs) -{ - dynamic_bitset result(lhs); - return result &= rhs; -} - -template -constexpr dynamic_bitset operator|(const dynamic_bitset& lhs, - const dynamic_bitset& rhs) -{ - dynamic_bitset result(lhs); - return result |= rhs; -} - -template -constexpr dynamic_bitset operator^(const dynamic_bitset& lhs, - const dynamic_bitset& rhs) -{ - dynamic_bitset result(lhs); - return result ^= rhs; -} - -template -constexpr dynamic_bitset operator-(const dynamic_bitset& lhs, - const dynamic_bitset& rhs) -{ - dynamic_bitset result(lhs); - return result -= rhs; -} - -template -constexpr std::basic_ostream<_CharT, _Traits>& operator<<( - std::basic_ostream<_CharT, _Traits>& os, - const dynamic_bitset& bitset) -{ - // A better implementation is possible - return os << bitset.template to_string<_CharT, _Traits>(); -} - -template -constexpr std::basic_istream<_CharT, _Traits>& operator>>(std::basic_istream<_CharT, _Traits>& is, - dynamic_bitset& bitset) -{ - // A better implementation is possible - constexpr _CharT zero = _CharT('0'); - constexpr _CharT one = _CharT('1'); - typename std::basic_istream<_CharT, _Traits>::sentry s(is); - if(!s) - { - return is; - } - - dynamic_bitset reverse_bitset; - _CharT val; - is.get(val); - while(is.good()) - { - if(val == one) - { - reverse_bitset.push_back(true); - } - else if(val == zero) - { - reverse_bitset.push_back(false); - } - else - { - is.unget(); - break; - } - is.get(val); - } - - bitset.clear(); - if(!reverse_bitset.empty()) - { - for(typename dynamic_bitset::size_type i = reverse_bitset.size() - 1; - i > 0; - --i) - { - bitset.push_back(reverse_bitset.test(i)); - } - bitset.push_back(reverse_bitset.test(0)); - } - - return is; -} - -template -constexpr void swap(dynamic_bitset& bitset1, - dynamic_bitset& bitset2) -{ - bitset1.swap(bitset2); -} + } + + template + template + constexpr void + dynamic_bitset::init_from_string(std::basic_string_view<_CharT, _Traits> str, + typename std::basic_string_view<_CharT, _Traits>::size_type pos, + typename std::basic_string_view<_CharT, _Traits>::size_type n, + [[maybe_unused]] _CharT zero, + _CharT one) + { + assert(pos < str.size()); + + const size_type size = std::min(n, str.size() - pos); + m_bits_number = size; + + m_blocks.clear(); + m_blocks.resize(blocks_required(size)); + for(size_t i = 0; i < size; ++i) + { + const _CharT c = str[(pos + size - 1) - i]; + assert(c == zero || c == one); + if(c == one) + { + set(i); + } + } + } + + template + constexpr typename dynamic_bitset::block_type& + dynamic_bitset::get_block(size_type pos) + { + return m_blocks[block_index(pos)]; + } + + template + constexpr const typename dynamic_bitset::block_type& + dynamic_bitset::get_block(size_type pos) const + { + return m_blocks[block_index(pos)]; + } + + template + constexpr typename dynamic_bitset::block_type& dynamic_bitset::last_block() + { + return m_blocks[m_blocks.size() - 1]; + } + + template + constexpr typename dynamic_bitset::block_type dynamic_bitset::last_block() const + { + return m_blocks[m_blocks.size() - 1]; + } + + template + constexpr typename dynamic_bitset::size_type + dynamic_bitset::extra_bits_number() const noexcept + { + return bit_index(m_bits_number); + } + + template + constexpr typename dynamic_bitset::size_type + dynamic_bitset::unused_bits_number() const noexcept + { + return bits_per_block - extra_bits_number(); + } + + template + template + constexpr void dynamic_bitset::apply(const dynamic_bitset& other, + BinaryOperation binary_op) + { + assert(num_blocks() == other.num_blocks()); + std::transform( + std::cbegin(m_blocks), std::cend(m_blocks), std::cbegin(other.m_blocks), std::begin(m_blocks), binary_op); + } + + template + template + constexpr void dynamic_bitset::apply(UnaryOperation unary_op) + { + std::transform(std::cbegin(m_blocks), std::cend(m_blocks), std::begin(m_blocks), unary_op); + } + + template + constexpr void dynamic_bitset::apply_left_shift(size_type shift) + { + assert(shift > 0); + assert(shift < capacity()); + + const size_type blocks_shift = shift / bits_per_block; + const size_type bits_offset = shift % bits_per_block; + + if(bits_offset == 0) + { + for(size_type i = m_blocks.size() - 1; i >= blocks_shift; --i) + { + m_blocks[i] = m_blocks[i - blocks_shift]; + } + } + else + { + const size_type reverse_bits_offset = bits_per_block - bits_offset; + for(size_type i = m_blocks.size() - 1; i > blocks_shift; --i) + { + m_blocks[i] = block_type((m_blocks[i - blocks_shift] << bits_offset) + | block_type(m_blocks[i - blocks_shift - 1] >> reverse_bits_offset)); + } + m_blocks[blocks_shift] = block_type(m_blocks[0] << bits_offset); + } + + // set bit that came at the right to 0 in unmodified blocks + std::fill(std::begin(m_blocks), + std::begin(m_blocks) + static_cast(blocks_shift), + zero_block); + } + + template + constexpr void dynamic_bitset::apply_right_shift(size_type shift) + { + assert(shift > 0); + assert(shift < capacity()); + + const size_type blocks_shift = shift / bits_per_block; + const size_type bits_offset = shift % bits_per_block; + const size_type last_block_to_shift = m_blocks.size() - blocks_shift - 1; + + if(bits_offset == 0) + { + for(size_type i = 0; i <= last_block_to_shift; ++i) + { + m_blocks[i] = m_blocks[i + blocks_shift]; + } + } + else + { + const size_type reverse_bits_offset = bits_per_block - bits_offset; + for(size_type i = 0; i < last_block_to_shift; ++i) + { + m_blocks[i] = block_type((m_blocks[i + blocks_shift] >> bits_offset) + | block_type(m_blocks[i + blocks_shift + 1] << reverse_bits_offset)); + } + m_blocks[last_block_to_shift] = block_type(m_blocks[m_blocks.size() - 1] >> bits_offset); + } + + // set bit that came at the left to 0 in unmodified blocks + std::fill(std::begin(m_blocks) + + static_cast(last_block_to_shift + 1), + std::end(m_blocks), + zero_block); + } + + template + constexpr void dynamic_bitset::sanitize() + { + size_type shift = m_bits_number % bits_per_block; + if(shift > 0) + { + last_block() &= static_cast(~(one_block << shift)); + } + } + + template + constexpr bool dynamic_bitset::check_unused_bits() const noexcept + { + const size_type extra_bits = extra_bits_number(); + if(extra_bits > 0) + { + return (last_block() & (one_block << extra_bits)) == zero_block; + } + return true; + } + + template + constexpr bool dynamic_bitset::check_size() const noexcept + { + return blocks_required(size()) == m_blocks.size(); + } + + template + constexpr bool dynamic_bitset::check_consistency() const noexcept + { + return check_unused_bits() && check_size(); + } + + //================================================================================================= + // dynamic_bitset external functions implementations + //================================================================================================= + + template + constexpr bool operator!=(const dynamic_bitset& lhs, const dynamic_bitset& rhs) + { + return !(lhs == rhs); + } + + template + constexpr bool operator<=(const dynamic_bitset& lhs, const dynamic_bitset& rhs) + { + return !(rhs < lhs); + } + + template + constexpr bool operator>(const dynamic_bitset& lhs, const dynamic_bitset& rhs) + { + return rhs < lhs; + } + + template + constexpr bool operator>=(const dynamic_bitset& lhs, const dynamic_bitset& rhs) + { + return !(lhs < rhs); + } + + template + constexpr dynamic_bitset operator&(const dynamic_bitset& lhs, + const dynamic_bitset& rhs) + { + dynamic_bitset result(lhs); + return result &= rhs; + } + + template + constexpr dynamic_bitset operator|(const dynamic_bitset& lhs, + const dynamic_bitset& rhs) + { + dynamic_bitset result(lhs); + return result |= rhs; + } + + template + constexpr dynamic_bitset operator^(const dynamic_bitset& lhs, + const dynamic_bitset& rhs) + { + dynamic_bitset result(lhs); + return result ^= rhs; + } + + template + constexpr dynamic_bitset operator-(const dynamic_bitset& lhs, + const dynamic_bitset& rhs) + { + dynamic_bitset result(lhs); + return result -= rhs; + } + + template + constexpr std::basic_ostream<_CharT, _Traits>& operator<<(std::basic_ostream<_CharT, _Traits>& os, + const dynamic_bitset& bitset) + { + // A better implementation is possible + return os << bitset.template to_string<_CharT, _Traits>(); + } + + template + constexpr std::basic_istream<_CharT, _Traits>& operator>>(std::basic_istream<_CharT, _Traits>& is, + dynamic_bitset& bitset) + { + // A better implementation is possible + constexpr _CharT zero = _CharT('0'); + constexpr _CharT one = _CharT('1'); + typename std::basic_istream<_CharT, _Traits>::sentry s(is); + if(!s) + { + return is; + } + + dynamic_bitset reverse_bitset; + _CharT val; + is.get(val); + while(is.good()) + { + if(val == one) + { + reverse_bitset.push_back(true); + } + else if(val == zero) + { + reverse_bitset.push_back(false); + } + else + { + is.unget(); + break; + } + is.get(val); + } + + bitset.clear(); + if(!reverse_bitset.empty()) + { + for(typename dynamic_bitset::size_type i = reverse_bitset.size() - 1; i > 0; --i) + { + bitset.push_back(reverse_bitset.test(i)); + } + bitset.push_back(reverse_bitset.test(0)); + } + + return is; + } + + template + constexpr void swap(dynamic_bitset& bitset1, dynamic_bitset& bitset2) + { + bitset1.swap(bitset2); + } #ifndef DYNAMIC_BITSET_NO_NAMESPACE } // namespace sul #endif -#endif //SUL_DYNAMIC_BITSET_HPP +#endif // SUL_DYNAMIC_BITSET_HPP diff --git a/tests/include/MultiTakeGenerator.hpp b/tests/include/MultiTakeGenerator.hpp index 99cdfc2..31b37ca 100644 --- a/tests/include/MultiTakeGenerator.hpp +++ b/tests/include/MultiTakeGenerator.hpp @@ -11,116 +11,115 @@ #include #include -#include #include +#include template -constexpr Catch::Generators::GeneratorWrapper> multitake( - size_t target, - Catch::Generators::GeneratorWrapper&&... generators); +constexpr Catch::Generators::GeneratorWrapper> +multitake(size_t target, Catch::Generators::GeneratorWrapper&&... generators); template class MultiTakeGenerator : public Catch::Generators::IGenerator> { public: - explicit constexpr MultiTakeGenerator(size_t target, - Catch::Generators::GeneratorWrapper&&... generators); + explicit constexpr MultiTakeGenerator(size_t target, Catch::Generators::GeneratorWrapper&&... generators); - constexpr std::tuple const& get() const override; + constexpr std::tuple const& get() const override; - constexpr bool next() override; + constexpr bool next() override; private: - std::tuple...> m_generators; - std::tuple m_current; - size_t m_returned; - size_t m_target; + std::tuple...> m_generators; + std::tuple m_current; + size_t m_returned; + size_t m_target; - constexpr bool generators_next(); + constexpr bool generators_next(); - template - constexpr bool generators_next_impl(std::index_sequence); + template + constexpr bool generators_next_impl(std::index_sequence); - constexpr std::tuple generators_get(); + constexpr std::tuple generators_get(); - template - constexpr std::tuple generators_get_impl(std::index_sequence); + template + constexpr std::tuple generators_get_impl(std::index_sequence); }; template -constexpr MultiTakeGenerator::MultiTakeGenerator( - size_t target, - Catch::Generators::GeneratorWrapper&&... generators) - : m_generators(std::move(generators)...), m_current(), m_returned(0), m_target(target) +constexpr MultiTakeGenerator::MultiTakeGenerator(size_t target, + Catch::Generators::GeneratorWrapper&&... generators) + : m_generators(std::move(generators)...) + , m_current() + , m_returned(0) + , m_target(target) { - assert(target != 0 && "Empty generators are not allowed"); - next(); + assert(target != 0 && "Empty generators are not allowed"); + next(); } template constexpr std::tuple const& MultiTakeGenerator::get() const { - return m_current; + return m_current; } template constexpr bool MultiTakeGenerator::next() { - ++m_returned; - if(m_returned >= m_target) - { - return false; - } - - const bool success = generators_next(); - // If one of the underlying generators does not contain enough values - // then we cut short as well - if(!success) - { - m_returned = m_target; - } - else - { - // update current - m_current = generators_get(); - } - return success; + ++m_returned; + if(m_returned >= m_target) + { + return false; + } + + const bool success = generators_next(); + // If one of the underlying generators does not contain enough values + // then we cut short as well + if(!success) + { + m_returned = m_target; + } + else + { + // update current + m_current = generators_get(); + } + return success; } template constexpr bool MultiTakeGenerator::generators_next() { - return generators_next_impl(std::make_index_sequence()); + return generators_next_impl(std::make_index_sequence()); } template template constexpr bool MultiTakeGenerator::generators_next_impl(std::index_sequence) { - return (std::get(m_generators).next() && ...); + return (std::get(m_generators).next() && ...); } template constexpr std::tuple MultiTakeGenerator::generators_get() { - return generators_get_impl(std::make_index_sequence()); + return generators_get_impl(std::make_index_sequence()); } template template constexpr std::tuple MultiTakeGenerator::generators_get_impl(std::index_sequence) { - return std::make_tuple(std::get(m_generators).get()...); + return std::make_tuple(std::get(m_generators).get()...); } template -constexpr Catch::Generators::GeneratorWrapper> multitake( - size_t target, - Catch::Generators::GeneratorWrapper&&... generators) +constexpr Catch::Generators::GeneratorWrapper> +multitake(size_t target, Catch::Generators::GeneratorWrapper&&... generators) { - return Catch::Generators::GeneratorWrapper>( - Catch::Detail::make_unique>(target, std::move(generators)...)); + return Catch::Generators::GeneratorWrapper>( + Catch::Detail::make_unique>(target, std::move(generators)...)); } -#endif //DYNAMIC_BITSET_MULTITAKEGENERATOR_HPP +#endif // DYNAMIC_BITSET_MULTITAKEGENERATOR_HPP diff --git a/tests/include/RandomBitsetStringGenerator.hpp b/tests/include/RandomBitsetStringGenerator.hpp index 0854ca4..71c9f3a 100644 --- a/tests/include/RandomBitsetStringGenerator.hpp +++ b/tests/include/RandomBitsetStringGenerator.hpp @@ -14,83 +14,82 @@ #include -Catch::Generators::GeneratorWrapper randomBitsetString( - uint32_t seed = Catch::Generators::Detail::getSeed()); +Catch::Generators::GeneratorWrapper +randomBitsetString(uint32_t seed = Catch::Generators::Detail::getSeed()); -Catch::Generators::GeneratorWrapper randomBitsetString( - std::string::size_type min_size, - std::string::size_type max_size, - uint32_t seed = Catch::Generators::Detail::getSeed()); +Catch::Generators::GeneratorWrapper +randomBitsetString(std::string::size_type min_size, + std::string::size_type max_size, + uint32_t seed = Catch::Generators::Detail::getSeed()); class RandomBitsetStringGenerator : public Catch::Generators::IGenerator { public: - typedef std::string::size_type size_type; - static constexpr size_type default_min_size = 1; - static constexpr size_type default_max_size = 256; + typedef std::string::size_type size_type; + static constexpr size_type default_min_size = 1; + static constexpr size_type default_max_size = 256; - explicit RandomBitsetStringGenerator(uint32_t seed = Catch::Generators::Detail::getSeed()); - RandomBitsetStringGenerator(size_type min_size, - size_type max_size, - uint32_t seed = Catch::Generators::Detail::getSeed()); + explicit RandomBitsetStringGenerator(uint32_t seed = Catch::Generators::Detail::getSeed()); + RandomBitsetStringGenerator(size_type min_size, + size_type max_size, + uint32_t seed = Catch::Generators::Detail::getSeed()); - const std::string& get() const override; - bool next() override; + const std::string& get() const override; + bool next() override; private: - Catch::SimplePcg32 m_rand; - Catch::uniform_integer_distribution m_size_dist; - Catch::uniform_integer_distribution m_bit_dist; - std::string m_current_bitset; + Catch::SimplePcg32 m_rand; + Catch::uniform_integer_distribution m_size_dist; + Catch::uniform_integer_distribution m_bit_dist; + std::string m_current_bitset; }; inline RandomBitsetStringGenerator::RandomBitsetStringGenerator(uint32_t seed) - : m_rand(seed) - , m_size_dist(default_min_size, default_max_size) - , m_bit_dist('0', '1') - , m_current_bitset() + : m_rand(seed) + , m_size_dist(default_min_size, default_max_size) + , m_bit_dist('0', '1') + , m_current_bitset() { - next(); + next(); } -inline RandomBitsetStringGenerator::RandomBitsetStringGenerator(size_type min_size, - size_type max_size, - uint32_t seed) - : m_rand(seed), m_size_dist(min_size, max_size), m_bit_dist('0', '1'), m_current_bitset() +inline RandomBitsetStringGenerator::RandomBitsetStringGenerator(size_type min_size, size_type max_size, uint32_t seed) + : m_rand(seed) + , m_size_dist(min_size, max_size) + , m_bit_dist('0', '1') + , m_current_bitset() { - next(); + next(); } inline const std::string& RandomBitsetStringGenerator::get() const { - return m_current_bitset; + return m_current_bitset; } inline bool RandomBitsetStringGenerator::next() { - const size_type bitset_size = m_size_dist(m_rand); - m_current_bitset.clear(); - m_current_bitset.reserve(bitset_size); - for(size_t i = 0; i < bitset_size; ++i) - { - m_current_bitset.push_back(m_bit_dist(m_rand)); - } - return true; + const size_type bitset_size = m_size_dist(m_rand); + m_current_bitset.clear(); + m_current_bitset.reserve(bitset_size); + for(size_t i = 0; i < bitset_size; ++i) + { + m_current_bitset.push_back(m_bit_dist(m_rand)); + } + return true; } inline Catch::Generators::GeneratorWrapper randomBitsetString(uint32_t seed) { - return Catch::Generators::GeneratorWrapper( - Catch::Detail::make_unique(seed)); + return Catch::Generators::GeneratorWrapper( + Catch::Detail::make_unique(seed)); } -inline Catch::Generators::GeneratorWrapper randomBitsetString( - std::string::size_type min_size, - std::string::size_type max_size, - uint32_t seed) +inline Catch::Generators::GeneratorWrapper +randomBitsetString(std::string::size_type min_size, std::string::size_type max_size, uint32_t seed) { - return Catch::Generators::GeneratorWrapper( - Catch::Detail::make_unique(min_size, max_size, seed)); + return Catch::Generators::GeneratorWrapper( + Catch::Detail::make_unique(min_size, max_size, seed)); } -#endif //DYNAMIC_BITSET_RANDOMBITSETSTRINGGENERATOR_HPP +#endif // DYNAMIC_BITSET_RANDOMBITSETSTRINGGENERATOR_HPP diff --git a/tests/include/RandomChunkGenerator.hpp b/tests/include/RandomChunkGenerator.hpp index ef29fec..6eeb0ba 100644 --- a/tests/include/RandomChunkGenerator.hpp +++ b/tests/include/RandomChunkGenerator.hpp @@ -15,100 +15,98 @@ #include template -constexpr Catch::Generators::GeneratorWrapper> randomChunk( - typename std::vector::size_type min_chunk_size, - typename std::vector::size_type max_chunk_size, - Catch::Generators::GeneratorWrapper&& generator, - uint32_t seed = Catch::Generators::Detail::getSeed()); +constexpr Catch::Generators::GeneratorWrapper> +randomChunk(typename std::vector::size_type min_chunk_size, + typename std::vector::size_type max_chunk_size, + Catch::Generators::GeneratorWrapper&& generator, + uint32_t seed = Catch::Generators::Detail::getSeed()); template class RandomChunkGenerator final : public Catch::Generators::IGenerator> { public: - using size_type = typename std::vector::size_type; + using size_type = typename std::vector::size_type; - constexpr RandomChunkGenerator(size_type min_chunk_size, - size_type max_chunk_size, - Catch::Generators::GeneratorWrapper&& generator, - uint32_t seed = Catch::Generators::Detail::getSeed()); + constexpr RandomChunkGenerator(size_type min_chunk_size, + size_type max_chunk_size, + Catch::Generators::GeneratorWrapper&& generator, + uint32_t seed = Catch::Generators::Detail::getSeed()); - constexpr std::vector const& get() const override; + constexpr std::vector const& get() const override; - constexpr bool next() override; + constexpr bool next() override; private: - Catch::SimplePcg32 m_rand; - Catch::uniform_integer_distribution m_size_dist; - std::vector m_chunk; - Catch::Generators::GeneratorWrapper m_generator; + Catch::SimplePcg32 m_rand; + Catch::uniform_integer_distribution m_size_dist; + std::vector m_chunk; + Catch::Generators::GeneratorWrapper m_generator; }; template -constexpr RandomChunkGenerator::RandomChunkGenerator( - size_type min_chunk_size, - size_type max_chunk_size, - Catch::Generators::GeneratorWrapper&& generator, - uint32_t seed) - : m_rand(seed) - , m_size_dist(min_chunk_size, max_chunk_size) - , m_chunk() - , m_generator(std::move(generator)) +constexpr RandomChunkGenerator::RandomChunkGenerator(size_type min_chunk_size, + size_type max_chunk_size, + Catch::Generators::GeneratorWrapper&& generator, + uint32_t seed) + : m_rand(seed) + , m_size_dist(min_chunk_size, max_chunk_size) + , m_chunk() + , m_generator(std::move(generator)) { - const size_type size = m_size_dist(m_rand); - m_chunk.reserve(size); - if(size == 0) - { - return; - } + const size_type size = m_size_dist(m_rand); + m_chunk.reserve(size); + if(size == 0) + { + return; + } - m_chunk.push_back(m_generator.get()); - for(size_type i = 1; i < min_chunk_size; ++i) - { - assert(m_generator.next() && "Not enough values to initialize the first chunk"); - m_chunk.push_back(m_generator.get()); - } - for(size_type i = min_chunk_size; i < size; ++i) - { - if(m_generator.next()) - { - m_chunk.push_back(m_generator.get()); - } - } + m_chunk.push_back(m_generator.get()); + for(size_type i = 1; i < min_chunk_size; ++i) + { + assert(m_generator.next() && "Not enough values to initialize the first chunk"); + m_chunk.push_back(m_generator.get()); + } + for(size_type i = min_chunk_size; i < size; ++i) + { + if(m_generator.next()) + { + m_chunk.push_back(m_generator.get()); + } + } } template constexpr const std::vector& RandomChunkGenerator::get() const { - return m_chunk; + return m_chunk; } template constexpr bool RandomChunkGenerator::next() { - const size_type size = m_size_dist(m_rand); - m_chunk.clear(); - m_chunk.reserve(size); - for(size_type i = 0; i < size; ++i) - { - if(!m_generator.next()) - { - return false; - } - m_chunk.push_back(m_generator.get()); - } - return true; + const size_type size = m_size_dist(m_rand); + m_chunk.clear(); + m_chunk.reserve(size); + for(size_type i = 0; i < size; ++i) + { + if(!m_generator.next()) + { + return false; + } + m_chunk.push_back(m_generator.get()); + } + return true; } template -constexpr Catch::Generators::GeneratorWrapper> randomChunk( - typename std::vector::size_type min_chunk_size, - typename std::vector::size_type max_chunk_size, - Catch::Generators::GeneratorWrapper&& generator, - uint32_t seed) +constexpr Catch::Generators::GeneratorWrapper> +randomChunk(typename std::vector::size_type min_chunk_size, + typename std::vector::size_type max_chunk_size, + Catch::Generators::GeneratorWrapper&& generator, + uint32_t seed) { - return Catch::Generators::GeneratorWrapper>( - Catch::Detail::make_unique>( - min_chunk_size, max_chunk_size, std::move(generator), seed)); + return Catch::Generators::GeneratorWrapper>( + Catch::Detail::make_unique>(min_chunk_size, max_chunk_size, std::move(generator), seed)); } -#endif //DYNAMIC_BITSET_RANDOMCHUNKGENERATOR_HPP +#endif // DYNAMIC_BITSET_RANDOMCHUNKGENERATOR_HPP diff --git a/tests/include/RandomDynamicBitsetGenerator.hpp b/tests/include/RandomDynamicBitsetGenerator.hpp index 5e97edb..f120996 100644 --- a/tests/include/RandomDynamicBitsetGenerator.hpp +++ b/tests/include/RandomDynamicBitsetGenerator.hpp @@ -16,94 +16,94 @@ #include template -constexpr Catch::Generators::GeneratorWrapper> randomDynamicBitset( - uint32_t seed = Catch::Generators::Detail::getSeed()); +constexpr Catch::Generators::GeneratorWrapper> +randomDynamicBitset(uint32_t seed = Catch::Generators::Detail::getSeed()); template -constexpr Catch::Generators::GeneratorWrapper> randomDynamicBitset( - typename sul::dynamic_bitset::size_type min_size, - typename sul::dynamic_bitset::size_type max_size, - uint32_t seed = Catch::Generators::Detail::getSeed()); +constexpr Catch::Generators::GeneratorWrapper> +randomDynamicBitset(typename sul::dynamic_bitset::size_type min_size, + typename sul::dynamic_bitset::size_type max_size, + uint32_t seed = Catch::Generators::Detail::getSeed()); template -class RandomDynamicBitsetGenerator - : public Catch::Generators::IGenerator> +class RandomDynamicBitsetGenerator : public Catch::Generators::IGenerator> { public: - typedef typename sul::dynamic_bitset::size_type size_type; - static constexpr size_type default_min_size = 1; - static constexpr size_type default_max_size = 8 * std::numeric_limits::digits; + typedef typename sul::dynamic_bitset::size_type size_type; + static constexpr size_type default_min_size = 1; + static constexpr size_type default_max_size = 8 * std::numeric_limits::digits; - constexpr explicit RandomDynamicBitsetGenerator( - uint32_t seed = Catch::Generators::Detail::getSeed()); - constexpr RandomDynamicBitsetGenerator(size_type min_size, - size_type max_size, - uint32_t seed = Catch::Generators::Detail::getSeed()); + constexpr explicit RandomDynamicBitsetGenerator(uint32_t seed = Catch::Generators::Detail::getSeed()); + constexpr RandomDynamicBitsetGenerator(size_type min_size, + size_type max_size, + uint32_t seed = Catch::Generators::Detail::getSeed()); - constexpr const sul::dynamic_bitset& get() const override; - constexpr bool next() override; + constexpr const sul::dynamic_bitset& get() const override; + constexpr bool next() override; private: - std::minstd_rand m_rand; - std::uniform_int_distribution m_size_dist; - std::uniform_int_distribution m_block_dist; - sul::dynamic_bitset m_current_bitset; + std::minstd_rand m_rand; + std::uniform_int_distribution m_size_dist; + std::uniform_int_distribution m_block_dist; + sul::dynamic_bitset m_current_bitset; }; template constexpr RandomDynamicBitsetGenerator::RandomDynamicBitsetGenerator(uint32_t seed) - : m_rand(seed) - , m_size_dist(default_min_size, default_max_size) - , m_block_dist() - , m_current_bitset() + : m_rand(seed) + , m_size_dist(default_min_size, default_max_size) + , m_block_dist() + , m_current_bitset() { - next(); + next(); } template constexpr RandomDynamicBitsetGenerator::RandomDynamicBitsetGenerator(size_type min_size, size_type max_size, uint32_t seed) - : m_rand(seed), m_size_dist(min_size, max_size), m_block_dist(), m_current_bitset() + : m_rand(seed) + , m_size_dist(min_size, max_size) + , m_block_dist() + , m_current_bitset() { - next(); + next(); } template constexpr const sul::dynamic_bitset& RandomDynamicBitsetGenerator::get() const { - return m_current_bitset; + return m_current_bitset; } template constexpr bool RandomDynamicBitsetGenerator::next() { - const size_type bitset_size = m_size_dist(m_rand); - m_current_bitset.clear(); - for(size_t i = 0; i < (bitset_size / m_current_bitset.bits_per_block) + 1; ++i) - { - m_current_bitset.append(m_block_dist(m_rand)); - } - m_current_bitset.resize(bitset_size); - return true; + const size_type bitset_size = m_size_dist(m_rand); + m_current_bitset.clear(); + for(size_t i = 0; i < (bitset_size / m_current_bitset.bits_per_block) + 1; ++i) + { + m_current_bitset.append(m_block_dist(m_rand)); + } + m_current_bitset.resize(bitset_size); + return true; } template -constexpr Catch::Generators::GeneratorWrapper> randomDynamicBitset( - uint32_t seed) +constexpr Catch::Generators::GeneratorWrapper> randomDynamicBitset(uint32_t seed) { - return Catch::Generators::GeneratorWrapper>( - Catch::Detail::make_unique>(seed)); + return Catch::Generators::GeneratorWrapper>( + Catch::Detail::make_unique>(seed)); } template -constexpr Catch::Generators::GeneratorWrapper> randomDynamicBitset( - typename sul::dynamic_bitset::size_type min_size, - typename sul::dynamic_bitset::size_type max_size, - uint32_t seed) +constexpr Catch::Generators::GeneratorWrapper> +randomDynamicBitset(typename sul::dynamic_bitset::size_type min_size, + typename sul::dynamic_bitset::size_type max_size, + uint32_t seed) { - return Catch::Generators::GeneratorWrapper>( - Catch::Detail::make_unique>(min_size, max_size, seed)); + return Catch::Generators::GeneratorWrapper>( + Catch::Detail::make_unique>(min_size, max_size, seed)); } -#endif //DYNAMIC_BITSET_RANDOMDYNAMICBITSETGENERATOR_HPP +#endif // DYNAMIC_BITSET_RANDOMDYNAMICBITSETGENERATOR_HPP diff --git a/tests/include/config.hpp b/tests/include/config.hpp index 70051ee..b81871f 100644 --- a/tests/include/config.hpp +++ b/tests/include/config.hpp @@ -11,4 +11,4 @@ constexpr size_t RANDOM_VECTORS_TO_TEST = 100; constexpr size_t RANDOM_VARIATIONS_TO_TEST = 10; -#endif //DYNAMIC_BITSET_CONFIG_HPP +#endif // DYNAMIC_BITSET_CONFIG_HPP diff --git a/tests/include/utils.hpp b/tests/include/utils.hpp index dafa176..6e56d2f 100644 --- a/tests/include/utils.hpp +++ b/tests/include/utils.hpp @@ -24,38 +24,36 @@ static constexpr T one_block = T(~zero_block); template constexpr bool bit_value(T value, size_t bit_pos) noexcept { - static_assert(std::is_unsigned::value, "T is not an unsigned integral type"); - assert(bit_pos < bits_number); - return (value & (T(1) << bit_pos)) != T(0); + static_assert(std::is_unsigned::value, "T is not an unsigned integral type"); + assert(bit_pos < bits_number); + return (value & (T(1) << bit_pos)) != T(0); } template constexpr bool check_unused_bits(const sul::dynamic_bitset& bitset) noexcept { - const size_t extra_bits = bitset.size() % sul::dynamic_bitset::bits_per_block; - if(extra_bits > 0) - { - assert(bitset.data() != nullptr); - assert(bitset.num_blocks() > 0); - return (*(bitset.data() + bitset.num_blocks() - 1) & (one_block << extra_bits)) - == zero_block; - } - return true; + const size_t extra_bits = bitset.size() % sul::dynamic_bitset::bits_per_block; + if(extra_bits > 0) + { + assert(bitset.data() != nullptr); + assert(bitset.num_blocks() > 0); + return (*(bitset.data() + bitset.num_blocks() - 1) & (one_block << extra_bits)) == zero_block; + } + return true; } template constexpr bool check_size(const sul::dynamic_bitset& bitset) noexcept { - const size_t blocks_required = - bitset.size() / sul::dynamic_bitset::bits_per_block - + static_cast(bitset.size() % sul::dynamic_bitset::bits_per_block > 0); - return blocks_required == bitset.num_blocks(); + const size_t blocks_required = bitset.size() / sul::dynamic_bitset::bits_per_block + + static_cast(bitset.size() % sul::dynamic_bitset::bits_per_block > 0); + return blocks_required == bitset.num_blocks(); } template constexpr bool check_consistency(const sul::dynamic_bitset& bitset) noexcept { - return check_unused_bits(bitset) && check_size(bitset); + return check_unused_bits(bitset) && check_size(bitset); } -#endif //DYNAMIC_BITSET_UTILS_HPP +#endif // DYNAMIC_BITSET_UTILS_HPP diff --git a/tests/src/count.cpp b/tests/src/count.cpp index 1afcf84..209371b 100644 --- a/tests/src/count.cpp +++ b/tests/src/count.cpp @@ -19,58 +19,54 @@ #include #if DYNAMIC_BITSET_CAN_USE_LIBPOPCNT -# define COUNT_TESTED_IMPL "libpopcnt" +# define COUNT_TESTED_IMPL "libpopcnt" #elif DYNAMIC_BITSET_CAN_USE_STD_BITOPS -# define COUNT_TESTED_IMPL "C++20 binary operations" +# define COUNT_TESTED_IMPL "C++20 binary operations" #elif DYNAMIC_BITSET_CAN_USE_GCC_BUILTIN -# define COUNT_TESTED_IMPL "gcc builtins" +# define COUNT_TESTED_IMPL "gcc builtins" #elif DYNAMIC_BITSET_CAN_USE_CLANG_BUILTIN_POPCOUNT -# define COUNT_TESTED_IMPL "clang builtins" +# define COUNT_TESTED_IMPL "clang builtins" #else -# define COUNT_TESTED_IMPL "base" +# define COUNT_TESTED_IMPL "base" #endif -TEMPLATE_TEST_CASE("count (" COUNT_TESTED_IMPL ")", - "[dynamic_bitset][libpopcnt][builtin][c++20]", - uint16_t, - uint32_t, - uint64_t) +TEMPLATE_TEST_CASE( + "count (" COUNT_TESTED_IMPL ")", "[dynamic_bitset][libpopcnt][builtin][c++20]", uint16_t, uint32_t, uint64_t) { - SECTION("empty bitset") - { - sul::dynamic_bitset bitset; + SECTION("empty bitset") + { + sul::dynamic_bitset bitset; - REQUIRE(bitset.count() == 0); - } + REQUIRE(bitset.count() == 0); + } - SECTION("non-empty bitset") - { - sul::dynamic_bitset bitset = - GENERATE(take(RANDOM_VECTORS_TO_TEST, randomDynamicBitset())); - CAPTURE(bitset); + SECTION("non-empty bitset") + { + sul::dynamic_bitset bitset = GENERATE(take(RANDOM_VECTORS_TO_TEST, randomDynamicBitset())); + CAPTURE(bitset); - size_t count = 0; - for(size_t i = 0; i < bitset.size(); ++i) - { - count += static_cast(bitset[i]); - } + size_t count = 0; + for(size_t i = 0; i < bitset.size(); ++i) + { + count += static_cast(bitset[i]); + } - SECTION("general") - { - REQUIRE(bitset.count() == count); - } + SECTION("general") + { + REQUIRE(bitset.count() == count); + } - SECTION("first block empty") - { - bitset.append(0); - bitset <<= bits_number; - REQUIRE(bitset.count() == count); - } + SECTION("first block empty") + { + bitset.append(0); + bitset <<= bits_number; + REQUIRE(bitset.count() == count); + } - SECTION("last block empty") - { - bitset.append(0); - REQUIRE(bitset.count() == count); - } - } + SECTION("last block empty") + { + bitset.append(0); + REQUIRE(bitset.count() == count); + } + } } diff --git a/tests/src/find_first_find_next.cpp b/tests/src/find_first_find_next.cpp index b09cd78..a31fa5d 100644 --- a/tests/src/find_first_find_next.cpp +++ b/tests/src/find_first_find_next.cpp @@ -20,19 +20,19 @@ #include #if DYNAMIC_BITSET_CAN_USE_STD_BITOPS -# define FIND_FIRST_FIND_NEXT_TESTED_IMPL "C++20 binary operations" +# define FIND_FIRST_FIND_NEXT_TESTED_IMPL "C++20 binary operations" #elif DYNAMIC_BITSET_CAN_USE_GCC_BUILTIN -# define FIND_FIRST_FIND_NEXT_TESTED_IMPL "gcc builtins" +# define FIND_FIRST_FIND_NEXT_TESTED_IMPL "gcc builtins" #elif DYNAMIC_BITSET_CAN_USE_CLANG_BUILTIN_CTZ -# define FIND_FIRST_FIND_NEXT_TESTED_IMPL "clang builtins" +# define FIND_FIRST_FIND_NEXT_TESTED_IMPL "clang builtins" #elif DYNAMIC_BITSET_CAN_USE_MSVC_BUILTIN_BITSCANFORWARD -# if DYNAMIC_BITSET_CAN_USE_MSVC_BUILTIN_BITSCANFORWARD64 -# define FIND_FIRST_FIND_NEXT_TESTED_IMPL "msvc builtins 32/64" -# else -# define FIND_FIRST_FIND_NEXT_TESTED_IMPL "msvc builtins 32" -# endif +# if DYNAMIC_BITSET_CAN_USE_MSVC_BUILTIN_BITSCANFORWARD64 +# define FIND_FIRST_FIND_NEXT_TESTED_IMPL "msvc builtins 32/64" +# else +# define FIND_FIRST_FIND_NEXT_TESTED_IMPL "msvc builtins 32" +# endif #else -# define FIND_FIRST_FIND_NEXT_TESTED_IMPL "base" +# define FIND_FIRST_FIND_NEXT_TESTED_IMPL "base" #endif TEMPLATE_TEST_CASE("find_first find_next (" FIND_FIRST_FIND_NEXT_TESTED_IMPL ")", @@ -41,31 +41,30 @@ TEMPLATE_TEST_CASE("find_first find_next (" FIND_FIRST_FIND_NEXT_TESTED_IMPL ")" uint32_t, uint64_t) { - SECTION("empty-bitset") - { - sul::dynamic_bitset bitset; + SECTION("empty-bitset") + { + sul::dynamic_bitset bitset; - REQUIRE(bitset.find_first() == bitset.npos); - REQUIRE(bitset.find_next(0) == bitset.npos); - } + REQUIRE(bitset.find_first() == bitset.npos); + REQUIRE(bitset.find_next(0) == bitset.npos); + } - SECTION("non-empty bitset") - { - const std::tuple values = - GENERATE(multitake(RANDOM_VECTORS_TO_TEST, - random(0, 5 * bits_number), - random(0, 5 * bits_number))); - const size_t first_bit_pos = std::get<0>(values); - const size_t second_bit_pos = first_bit_pos + 1 + std::get<1>(values); - CAPTURE(first_bit_pos, second_bit_pos); + SECTION("non-empty bitset") + { + const std::tuple values = GENERATE(multitake(RANDOM_VECTORS_TO_TEST, + random(0, 5 * bits_number), + random(0, 5 * bits_number))); + const size_t first_bit_pos = std::get<0>(values); + const size_t second_bit_pos = first_bit_pos + 1 + std::get<1>(values); + CAPTURE(first_bit_pos, second_bit_pos); - sul::dynamic_bitset bitset(second_bit_pos + 12); - REQUIRE(bitset.find_first() == bitset.npos); - bitset.set(first_bit_pos); - bitset.set(second_bit_pos); - REQUIRE(bitset.find_first() == first_bit_pos); - REQUIRE(bitset.find_next(first_bit_pos) == second_bit_pos); - REQUIRE(bitset.find_next(second_bit_pos) == bitset.npos); - REQUIRE(bitset.find_next(bitset.size()) == bitset.npos); - } + sul::dynamic_bitset bitset(second_bit_pos + 12); + REQUIRE(bitset.find_first() == bitset.npos); + bitset.set(first_bit_pos); + bitset.set(second_bit_pos); + REQUIRE(bitset.find_first() == first_bit_pos); + REQUIRE(bitset.find_next(first_bit_pos) == second_bit_pos); + REQUIRE(bitset.find_next(second_bit_pos) == bitset.npos); + REQUIRE(bitset.find_next(bitset.size()) == bitset.npos); + } } diff --git a/tests/src/tests.cpp b/tests/src/tests.cpp index eb6e695..9a9b8fc 100644 --- a/tests/src/tests.cpp +++ b/tests/src/tests.cpp @@ -28,2092 +28,2046 @@ TEMPLATE_TEST_CASE("constructors", "[dynamic_bitset]", uint16_t, uint32_t, uint64_t) { - SECTION("default constructor") - { - sul::dynamic_bitset bitset; - - REQUIRE(bitset.empty()); - REQUIRE(bitset.size() == 0); - REQUIRE(bitset.capacity() == 0); - REQUIRE(check_consistency(bitset)); - } - - SECTION("nbits and init_val constructor") - { - const std::tuple values = GENERATE( - multitake(RANDOM_VECTORS_TO_TEST, - random(std::numeric_limits::min(), - std::numeric_limits::max()), - random(1, bits_number))); - const unsigned long long value = std::get<0>(values); - const size_t bits_to_take = std::get<1>(values); - CAPTURE(value, bits_to_take); - - sul::dynamic_bitset bitset(bits_to_take, value); - CAPTURE(bitset); - - // check init value bits - for(size_t i = 0; i < bits_to_take; ++i) - { - CAPTURE(i); - REQUIRE(bitset[i] == bit_value(value, i)); - } - REQUIRE(check_consistency(bitset)); - } - - SECTION("initializer_list constructor") - { - SECTION("one value") - { - const TestType init_value = - GENERATE(take(RANDOM_VECTORS_TO_TEST, - random(std::numeric_limits::min(), - std::numeric_limits::max()))); - const sul::dynamic_bitset bitset = {init_value}; - CAPTURE(init_value, bitset); - - // check bits - for(size_t i = 0; i < bits_number; ++i) - { - CAPTURE(i); - REQUIRE(bitset[i] == bit_value(init_value, i)); - } - REQUIRE(check_consistency(bitset)); - } - - SECTION("two values") - { - const std::tuple init_values = GENERATE(multitake( - RANDOM_VECTORS_TO_TEST, - random(std::numeric_limits::min(), - std::numeric_limits::max()), - random(std::numeric_limits::min(), - std::numeric_limits::max()))); - std::initializer_list init_values_list = {std::get<0>(init_values), - std::get<1>(init_values)}; - const sul::dynamic_bitset bitset = init_values_list; - CAPTURE(bitset, init_values_list); - - // check bits - size_t value_i = 0; - for(const TestType& value: init_values_list) - { - for(size_t bit_i = 0; bit_i < bits_number; ++bit_i) - { - CAPTURE(value_i, bit_i); - REQUIRE(bitset[value_i * bits_number + bit_i] - == bit_value(value, bit_i)); - } - ++value_i; - } - REQUIRE(check_consistency(bitset)); - } - } - - SECTION("string constructor") - { - const std::tuple values = GENERATE( - multitake(RANDOM_VECTORS_TO_TEST, - random(std::numeric_limits::min(), - std::numeric_limits::max()), - random(1, bits_number))); - const unsigned long long value = std::get<0>(values); - const size_t bits_to_take = std::get<1>(values); - CAPTURE(value, bits_to_take); - - std::string str(bits_to_take, '0'); - const size_t size = str.size(); - for(size_t i = 0; i < bits_to_take; ++i) - { - if(bit_value(value, i)) - { - str[size - 1 - i] = '1'; - } - } - CAPTURE(str); - - SECTION("full string") - { - SECTION("std::string_view") - { - const sul::dynamic_bitset bitset(std::string_view{str}); - CAPTURE(bitset); - - for(size_t i = 0; i < bits_to_take; ++i) - { - CAPTURE(i); - REQUIRE(bitset[i] == bit_value(value, i)); - } - - REQUIRE(bitset.to_string() == str); - REQUIRE(check_consistency(bitset)); - } - - SECTION("std::string") - { - const sul::dynamic_bitset bitset(str); - CAPTURE(bitset); - - for(size_t i = 0; i < bits_to_take; ++i) - { - CAPTURE(i); - REQUIRE(bitset[i] == bit_value(value, i)); - } - - REQUIRE(bitset.to_string() == str); - REQUIRE(check_consistency(bitset)); - } - - SECTION("const char*") - { - const sul::dynamic_bitset bitset(str.c_str()); - CAPTURE(bitset); - - for(size_t i = 0; i < bits_to_take; ++i) - { - CAPTURE(i); - REQUIRE(bitset[i] == bit_value(value, i)); - } - - REQUIRE(bitset.to_string() == str); - REQUIRE(check_consistency(bitset)); - } - } - - SECTION("partial string") - { - const std::tuple parameters = GENERATE(multitake( - RANDOM_VARIATIONS_TO_TEST, - random(std::numeric_limits::min(), - std::numeric_limits::max()), - random(std::numeric_limits::min(), - std::numeric_limits::max()))); - const size_t pos = std::get<0>(parameters) % bits_to_take; - const size_t n = - (pos == (bits_to_take - 1)) ? std::get<1>(parameters) % (bits_to_take - pos) : 0; - CAPTURE(pos, n); - - SECTION("std::string_view") - { - const sul::dynamic_bitset bitset(std::string_view{str}, pos, n); - CAPTURE(bitset); - - for(size_t i = 0; i < n; ++i) - { - CAPTURE(i); - REQUIRE(bitset[i] == bit_value(value, pos + i)); - } - REQUIRE(check_consistency(bitset)); - } - - SECTION("std::string") - { - const sul::dynamic_bitset bitset(str, pos, n); - CAPTURE(bitset); - - for(size_t i = 0; i < n; ++i) - { - CAPTURE(i); - REQUIRE(bitset[i] == bit_value(value, pos + i)); - } - REQUIRE(check_consistency(bitset)); - } - - SECTION("const char*") - { - const sul::dynamic_bitset bitset(str.c_str(), pos, n); - CAPTURE(bitset); - - for(size_t i = 0; i < n; ++i) - { - CAPTURE(i); - REQUIRE(bitset[i] == bit_value(value, pos + i)); - } - REQUIRE(check_consistency(bitset)); - } - } - } + SECTION("default constructor") + { + sul::dynamic_bitset bitset; + + REQUIRE(bitset.empty()); + REQUIRE(bitset.size() == 0); + REQUIRE(bitset.capacity() == 0); + REQUIRE(check_consistency(bitset)); + } + + SECTION("nbits and init_val constructor") + { + const std::tuple values = + GENERATE(multitake(RANDOM_VECTORS_TO_TEST, + random(std::numeric_limits::min(), + std::numeric_limits::max()), + random(1, bits_number))); + const unsigned long long value = std::get<0>(values); + const size_t bits_to_take = std::get<1>(values); + CAPTURE(value, bits_to_take); + + sul::dynamic_bitset bitset(bits_to_take, value); + CAPTURE(bitset); + + // check init value bits + for(size_t i = 0; i < bits_to_take; ++i) + { + CAPTURE(i); + REQUIRE(bitset[i] == bit_value(value, i)); + } + REQUIRE(check_consistency(bitset)); + } + + SECTION("initializer_list constructor") + { + SECTION("one value") + { + const TestType init_value = GENERATE( + take(RANDOM_VECTORS_TO_TEST, + random(std::numeric_limits::min(), std::numeric_limits::max()))); + const sul::dynamic_bitset bitset = {init_value}; + CAPTURE(init_value, bitset); + + // check bits + for(size_t i = 0; i < bits_number; ++i) + { + CAPTURE(i); + REQUIRE(bitset[i] == bit_value(init_value, i)); + } + REQUIRE(check_consistency(bitset)); + } + + SECTION("two values") + { + const std::tuple init_values = + GENERATE(multitake(RANDOM_VECTORS_TO_TEST, + random(std::numeric_limits::min(), + std::numeric_limits::max()), + random(std::numeric_limits::min(), + std::numeric_limits::max()))); + std::initializer_list init_values_list = {std::get<0>(init_values), std::get<1>(init_values)}; + const sul::dynamic_bitset bitset = init_values_list; + CAPTURE(bitset, init_values_list); + + // check bits + size_t value_i = 0; + for(const TestType& value: init_values_list) + { + for(size_t bit_i = 0; bit_i < bits_number; ++bit_i) + { + CAPTURE(value_i, bit_i); + REQUIRE(bitset[value_i * bits_number + bit_i] == bit_value(value, bit_i)); + } + ++value_i; + } + REQUIRE(check_consistency(bitset)); + } + } + + SECTION("string constructor") + { + const std::tuple values = + GENERATE(multitake(RANDOM_VECTORS_TO_TEST, + random(std::numeric_limits::min(), + std::numeric_limits::max()), + random(1, bits_number))); + const unsigned long long value = std::get<0>(values); + const size_t bits_to_take = std::get<1>(values); + CAPTURE(value, bits_to_take); + + std::string str(bits_to_take, '0'); + const size_t size = str.size(); + for(size_t i = 0; i < bits_to_take; ++i) + { + if(bit_value(value, i)) + { + str[size - 1 - i] = '1'; + } + } + CAPTURE(str); + + SECTION("full string") + { + SECTION("std::string_view") + { + const sul::dynamic_bitset bitset(std::string_view{str}); + CAPTURE(bitset); + + for(size_t i = 0; i < bits_to_take; ++i) + { + CAPTURE(i); + REQUIRE(bitset[i] == bit_value(value, i)); + } + + REQUIRE(bitset.to_string() == str); + REQUIRE(check_consistency(bitset)); + } + + SECTION("std::string") + { + const sul::dynamic_bitset bitset(str); + CAPTURE(bitset); + + for(size_t i = 0; i < bits_to_take; ++i) + { + CAPTURE(i); + REQUIRE(bitset[i] == bit_value(value, i)); + } + + REQUIRE(bitset.to_string() == str); + REQUIRE(check_consistency(bitset)); + } + + SECTION("const char*") + { + const sul::dynamic_bitset bitset(str.c_str()); + CAPTURE(bitset); + + for(size_t i = 0; i < bits_to_take; ++i) + { + CAPTURE(i); + REQUIRE(bitset[i] == bit_value(value, i)); + } + + REQUIRE(bitset.to_string() == str); + REQUIRE(check_consistency(bitset)); + } + } + + SECTION("partial string") + { + const std::tuple parameters = + GENERATE(multitake(RANDOM_VARIATIONS_TO_TEST, + random(std::numeric_limits::min(), + std::numeric_limits::max()), + random(std::numeric_limits::min(), + std::numeric_limits::max()))); + const size_t pos = std::get<0>(parameters) % bits_to_take; + const size_t n = (pos == (bits_to_take - 1)) ? std::get<1>(parameters) % (bits_to_take - pos) : 0; + CAPTURE(pos, n); + + SECTION("std::string_view") + { + const sul::dynamic_bitset bitset(std::string_view{str}, pos, n); + CAPTURE(bitset); + + for(size_t i = 0; i < n; ++i) + { + CAPTURE(i); + REQUIRE(bitset[i] == bit_value(value, pos + i)); + } + REQUIRE(check_consistency(bitset)); + } + + SECTION("std::string") + { + const sul::dynamic_bitset bitset(str, pos, n); + CAPTURE(bitset); + + for(size_t i = 0; i < n; ++i) + { + CAPTURE(i); + REQUIRE(bitset[i] == bit_value(value, pos + i)); + } + REQUIRE(check_consistency(bitset)); + } + + SECTION("const char*") + { + const sul::dynamic_bitset bitset(str.c_str(), pos, n); + CAPTURE(bitset); + + for(size_t i = 0; i < n; ++i) + { + CAPTURE(i); + REQUIRE(bitset[i] == bit_value(value, pos + i)); + } + REQUIRE(check_consistency(bitset)); + } + } + } } TEMPLATE_TEST_CASE("resize", "[dynamic_bitset]", uint16_t, uint32_t, uint64_t) { - sul::dynamic_bitset bitset = - GENERATE(take(RANDOM_VECTORS_TO_TEST, randomDynamicBitset())); - CAPTURE(bitset); - - SECTION("resizing to 0") - { - bitset.resize(0); - REQUIRE(bitset.empty()); - REQUIRE(bitset.size() == 0); - REQUIRE(check_consistency(bitset)); - } - - SECTION("resizing to the same size") - { - const size_t size_save = bitset.size(); - bitset.resize(bitset.size()); - REQUIRE(bitset.size() == size_save); - REQUIRE(check_consistency(bitset)); - } - - SECTION("changing size") - { - size_t size_change = GENERATE(take(RANDOM_VARIATIONS_TO_TEST, random(0, 128))); - const bool new_values = GENERATE(true, false); - CAPTURE(size_change, new_values); - - SECTION("incrementing size") - { - const sul::dynamic_bitset bitset_copy = bitset; - const size_t new_size = bitset.size() + size_change; - bitset.resize(new_size, new_values); - REQUIRE(bitset.size() == new_size); - - for(size_t i = 0; i < bitset_copy.size(); ++i) - { - CAPTURE(i); - REQUIRE(bitset[i] == bitset_copy[i]); - } - for(size_t i = bitset_copy.size(); i < bitset.size(); ++i) - { - CAPTURE(i); - REQUIRE(bitset[i] == new_values); - } - REQUIRE(check_consistency(bitset)); - } - - SECTION("decrementing size") - { - const sul::dynamic_bitset bitset_copy = bitset; - const size_t new_size = size_change > bitset.size() ? 0 : size_change; - bitset.resize(new_size, new_values); - REQUIRE(bitset.size() == new_size); - - for(size_t i = 0; i < bitset.size(); ++i) - { - CAPTURE(i); - REQUIRE(bitset[i] == bitset_copy[i]); - } - REQUIRE(check_consistency(bitset)); - } - } + sul::dynamic_bitset bitset = GENERATE(take(RANDOM_VECTORS_TO_TEST, randomDynamicBitset())); + CAPTURE(bitset); + + SECTION("resizing to 0") + { + bitset.resize(0); + REQUIRE(bitset.empty()); + REQUIRE(bitset.size() == 0); + REQUIRE(check_consistency(bitset)); + } + + SECTION("resizing to the same size") + { + const size_t size_save = bitset.size(); + bitset.resize(bitset.size()); + REQUIRE(bitset.size() == size_save); + REQUIRE(check_consistency(bitset)); + } + + SECTION("changing size") + { + size_t size_change = GENERATE(take(RANDOM_VARIATIONS_TO_TEST, random(0, 128))); + const bool new_values = GENERATE(true, false); + CAPTURE(size_change, new_values); + + SECTION("incrementing size") + { + const sul::dynamic_bitset bitset_copy = bitset; + const size_t new_size = bitset.size() + size_change; + bitset.resize(new_size, new_values); + REQUIRE(bitset.size() == new_size); + + for(size_t i = 0; i < bitset_copy.size(); ++i) + { + CAPTURE(i); + REQUIRE(bitset[i] == bitset_copy[i]); + } + for(size_t i = bitset_copy.size(); i < bitset.size(); ++i) + { + CAPTURE(i); + REQUIRE(bitset[i] == new_values); + } + REQUIRE(check_consistency(bitset)); + } + + SECTION("decrementing size") + { + const sul::dynamic_bitset bitset_copy = bitset; + const size_t new_size = size_change > bitset.size() ? 0 : size_change; + bitset.resize(new_size, new_values); + REQUIRE(bitset.size() == new_size); + + for(size_t i = 0; i < bitset.size(); ++i) + { + CAPTURE(i); + REQUIRE(bitset[i] == bitset_copy[i]); + } + REQUIRE(check_consistency(bitset)); + } + } } TEMPLATE_TEST_CASE("clear", "[dynamic_bitset]", uint16_t, uint32_t, uint64_t) { - sul::dynamic_bitset bitset = - GENERATE(take(RANDOM_VECTORS_TO_TEST, randomDynamicBitset())); - CAPTURE(bitset); - - bitset.clear(); - REQUIRE(bitset.empty()); - REQUIRE(bitset.size() == 0); - REQUIRE(check_consistency(bitset)); + sul::dynamic_bitset bitset = GENERATE(take(RANDOM_VECTORS_TO_TEST, randomDynamicBitset())); + CAPTURE(bitset); + + bitset.clear(); + REQUIRE(bitset.empty()); + REQUIRE(bitset.size() == 0); + REQUIRE(check_consistency(bitset)); } TEMPLATE_TEST_CASE("push_back", "[dynamic_bitset]", uint16_t, uint32_t, uint64_t) { - std::tuple, sul::dynamic_bitset> values = - GENERATE(multitake(RANDOM_VECTORS_TO_TEST, - randomDynamicBitset(), - randomDynamicBitset(1, 2 * bits_number))); - sul::dynamic_bitset& bitset = std::get<0>(values); - sul::dynamic_bitset& to_push = std::get<1>(values); - CAPTURE(bitset, to_push); - - const sul::dynamic_bitset bitset_copy = bitset; - size_t size = bitset.size(); - - // new bits added - for(size_t i = 0; i < to_push.size(); ++i) - { - CAPTURE(i, size); - bitset.push_back(to_push[i]); - REQUIRE(bitset[size] == to_push[i]); - ++size; - REQUIRE(bitset.size() == size); - } - - // initial bits not changed - for(size_t i = 0; i < bitset_copy.size(); ++i) - { - CAPTURE(i); - REQUIRE(bitset[i] == bitset_copy[i]); - } - REQUIRE(check_consistency(bitset)); + std::tuple, sul::dynamic_bitset> values = + GENERATE(multitake(RANDOM_VECTORS_TO_TEST, + randomDynamicBitset(), + randomDynamicBitset(1, 2 * bits_number))); + sul::dynamic_bitset& bitset = std::get<0>(values); + sul::dynamic_bitset& to_push = std::get<1>(values); + CAPTURE(bitset, to_push); + + const sul::dynamic_bitset bitset_copy = bitset; + size_t size = bitset.size(); + + // new bits added + for(size_t i = 0; i < to_push.size(); ++i) + { + CAPTURE(i, size); + bitset.push_back(to_push[i]); + REQUIRE(bitset[size] == to_push[i]); + ++size; + REQUIRE(bitset.size() == size); + } + + // initial bits not changed + for(size_t i = 0; i < bitset_copy.size(); ++i) + { + CAPTURE(i); + REQUIRE(bitset[i] == bitset_copy[i]); + } + REQUIRE(check_consistency(bitset)); } TEMPLATE_TEST_CASE("pop_back", "[dynamic_bitset]", uint16_t, uint32_t, uint64_t) { - SECTION("empty bitset") - { - sul::dynamic_bitset bitset; - - bitset.pop_back(); - REQUIRE(bitset.empty()); - REQUIRE(check_consistency(bitset)); - } - - SECTION("non-empty bitset") - { - std::tuple, size_t> values = - GENERATE(multitake(RANDOM_VECTORS_TO_TEST, - randomDynamicBitset(), - random(1, 2 * bits_number))); - sul::dynamic_bitset& bitset = std::get<0>(values); - size_t to_pop = std::min(bitset.size(), std::get<1>(values)); - CAPTURE(bitset, to_pop); - - const sul::dynamic_bitset bitset_copy = bitset; - size_t size = bitset.size(); - - // bits removed - for(size_t i = 0; i < to_pop; ++i) - { - CAPTURE(i, size); - bitset.pop_back(); - --size; - REQUIRE(bitset.size() == size); - } - - // initial bits not changed - for(size_t i = 0; i < bitset.size(); ++i) - { - CAPTURE(i); - REQUIRE(bitset[i] == bitset_copy[i]); - } - REQUIRE(check_consistency(bitset)); - } + SECTION("empty bitset") + { + sul::dynamic_bitset bitset; + + bitset.pop_back(); + REQUIRE(bitset.empty()); + REQUIRE(check_consistency(bitset)); + } + + SECTION("non-empty bitset") + { + std::tuple, size_t> values = GENERATE(multitake( + RANDOM_VECTORS_TO_TEST, randomDynamicBitset(), random(1, 2 * bits_number))); + sul::dynamic_bitset& bitset = std::get<0>(values); + size_t to_pop = std::min(bitset.size(), std::get<1>(values)); + CAPTURE(bitset, to_pop); + + const sul::dynamic_bitset bitset_copy = bitset; + size_t size = bitset.size(); + + // bits removed + for(size_t i = 0; i < to_pop; ++i) + { + CAPTURE(i, size); + bitset.pop_back(); + --size; + REQUIRE(bitset.size() == size); + } + + // initial bits not changed + for(size_t i = 0; i < bitset.size(); ++i) + { + CAPTURE(i); + REQUIRE(bitset[i] == bitset_copy[i]); + } + REQUIRE(check_consistency(bitset)); + } } TEMPLATE_TEST_CASE("append", "[dynamic_bitset]", uint16_t, uint32_t, uint64_t) { - sul::dynamic_bitset bitset = - GENERATE(take(RANDOM_VECTORS_TO_TEST, randomDynamicBitset())); - CAPTURE(bitset); - const sul::dynamic_bitset bitset_copy = bitset; - - SECTION("one value") - { - const TestType value = - GENERATE(take(RANDOM_VARIATIONS_TO_TEST, - random(std::numeric_limits::min(), - std::numeric_limits::max()))); - CAPTURE(value); - - bitset.append(value); - REQUIRE(bitset.size() == (bitset_copy.size() + bits_number)); - - // new bits added - for(size_t i = 0; i < bits_number; ++i) - { - CAPTURE(i); - REQUIRE(bitset[bitset_copy.size() + i] == bit_value(value, i)); - } - - // initial bits not changed - for(size_t i = 0; i < bitset_copy.size(); ++i) - { - CAPTURE(i); - REQUIRE(bitset[i] == bitset_copy[i]); - } - REQUIRE(check_consistency(bitset)); - } - - SECTION("empty initializer_list") - { - bitset.append({}); - REQUIRE(bitset.size() == bitset_copy.size()); - REQUIRE(check_consistency(bitset)); - } - - SECTION("two values initializer_list") - { - const std::tuple init_values = GENERATE( - multitake(RANDOM_VARIATIONS_TO_TEST, - random(std::numeric_limits::min(), - std::numeric_limits::max()), - random(std::numeric_limits::min(), - std::numeric_limits::max()))); - std::initializer_list values = {std::get<0>(init_values), - std::get<1>(init_values)}; - CAPTURE(values); - - bitset.append(values); - REQUIRE(bitset.size() == (bitset_copy.size() + values.size() * bits_number)); - - // new bits added - size_t value_i = 0; - for(const TestType& value: values) - { - for(size_t bit_i = 0; bit_i < bits_number; ++bit_i) - { - CAPTURE(value_i, bit_i); - REQUIRE(bitset[bitset_copy.size() + value_i * bits_number + bit_i] - == bit_value(value, bit_i)); - } - ++value_i; - } - - // initial bits not changed - for(size_t i = 0; i < bitset_copy.size(); ++i) - { - CAPTURE(i); - REQUIRE(bitset[i] == bitset_copy[i]); - } - REQUIRE(check_consistency(bitset)); - } - - SECTION("same iterators") - { - const std::vector values; - - bitset.append(std::cbegin(values), std::cend(values)); - REQUIRE(bitset.size() == bitset_copy.size()); - REQUIRE(check_consistency(bitset)); - } - - SECTION("random access iterators") - { - const std::vector values = GENERATE( - take(RANDOM_VARIATIONS_TO_TEST, - randomChunk(2, - 5, - random(std::numeric_limits::min(), - std::numeric_limits::max())))); - CAPTURE(values); - - bitset.append(std::cbegin(values), std::cend(values)); - REQUIRE(bitset.size() == (bitset_copy.size() + values.size() * bits_number)); - - // new bits added - size_t value_i = 0; - for(const TestType& value: values) - { - for(size_t bit_i = 0; bit_i < bits_number; ++bit_i) - { - CAPTURE(value_i, bit_i); - REQUIRE(bitset[bitset_copy.size() + value_i * bits_number + bit_i] - == bit_value(value, bit_i)); - } - ++value_i; - } - - // initial bits not changed - for(size_t i = 0; i < bitset_copy.size(); ++i) - { - CAPTURE(i); - REQUIRE(bitset[i] == bitset_copy[i]); - } - REQUIRE(check_consistency(bitset)); - } - - SECTION("bidirectional iterators") - { - const std::vector values = GENERATE( - take(RANDOM_VARIATIONS_TO_TEST, - randomChunk(2, - 5, - random(std::numeric_limits::min(), - std::numeric_limits::max())))); - CAPTURE(values); - - const std::list values_list(std::cbegin(values), std::cend(values)); - bitset.append(std::cbegin(values_list), std::cend(values_list)); - REQUIRE(bitset.size() == (bitset_copy.size() + values.size() * bits_number)); - - // new bits added - size_t value_i = 0; - for(const TestType& value: values) - { - for(size_t bit_i = 0; bit_i < bits_number; ++bit_i) - { - CAPTURE(value_i, bit_i); - REQUIRE(bitset[bitset_copy.size() + value_i * bits_number + bit_i] - == bit_value(value, bit_i)); - } - ++value_i; - } - - // initial bits not changed - for(size_t i = 0; i < bitset_copy.size(); ++i) - { - CAPTURE(i); - REQUIRE(bitset[i] == bitset_copy[i]); - } - REQUIRE(check_consistency(bitset)); - } + sul::dynamic_bitset bitset = GENERATE(take(RANDOM_VECTORS_TO_TEST, randomDynamicBitset())); + CAPTURE(bitset); + const sul::dynamic_bitset bitset_copy = bitset; + + SECTION("one value") + { + const TestType value = + GENERATE(take(RANDOM_VARIATIONS_TO_TEST, + random(std::numeric_limits::min(), std::numeric_limits::max()))); + CAPTURE(value); + + bitset.append(value); + REQUIRE(bitset.size() == (bitset_copy.size() + bits_number)); + + // new bits added + for(size_t i = 0; i < bits_number; ++i) + { + CAPTURE(i); + REQUIRE(bitset[bitset_copy.size() + i] == bit_value(value, i)); + } + + // initial bits not changed + for(size_t i = 0; i < bitset_copy.size(); ++i) + { + CAPTURE(i); + REQUIRE(bitset[i] == bitset_copy[i]); + } + REQUIRE(check_consistency(bitset)); + } + + SECTION("empty initializer_list") + { + bitset.append({}); + REQUIRE(bitset.size() == bitset_copy.size()); + REQUIRE(check_consistency(bitset)); + } + + SECTION("two values initializer_list") + { + const std::tuple init_values = + GENERATE(multitake(RANDOM_VARIATIONS_TO_TEST, + random(std::numeric_limits::min(), + std::numeric_limits::max()), + random(std::numeric_limits::min(), + std::numeric_limits::max()))); + std::initializer_list values = {std::get<0>(init_values), std::get<1>(init_values)}; + CAPTURE(values); + + bitset.append(values); + REQUIRE(bitset.size() == (bitset_copy.size() + values.size() * bits_number)); + + // new bits added + size_t value_i = 0; + for(const TestType& value: values) + { + for(size_t bit_i = 0; bit_i < bits_number; ++bit_i) + { + CAPTURE(value_i, bit_i); + REQUIRE(bitset[bitset_copy.size() + value_i * bits_number + bit_i] + == bit_value(value, bit_i)); + } + ++value_i; + } + + // initial bits not changed + for(size_t i = 0; i < bitset_copy.size(); ++i) + { + CAPTURE(i); + REQUIRE(bitset[i] == bitset_copy[i]); + } + REQUIRE(check_consistency(bitset)); + } + + SECTION("same iterators") + { + const std::vector values; + + bitset.append(std::cbegin(values), std::cend(values)); + REQUIRE(bitset.size() == bitset_copy.size()); + REQUIRE(check_consistency(bitset)); + } + + SECTION("random access iterators") + { + const std::vector values = GENERATE( + take(RANDOM_VARIATIONS_TO_TEST, + randomChunk( + 2, 5, random(std::numeric_limits::min(), std::numeric_limits::max())))); + CAPTURE(values); + + bitset.append(std::cbegin(values), std::cend(values)); + REQUIRE(bitset.size() == (bitset_copy.size() + values.size() * bits_number)); + + // new bits added + size_t value_i = 0; + for(const TestType& value: values) + { + for(size_t bit_i = 0; bit_i < bits_number; ++bit_i) + { + CAPTURE(value_i, bit_i); + REQUIRE(bitset[bitset_copy.size() + value_i * bits_number + bit_i] + == bit_value(value, bit_i)); + } + ++value_i; + } + + // initial bits not changed + for(size_t i = 0; i < bitset_copy.size(); ++i) + { + CAPTURE(i); + REQUIRE(bitset[i] == bitset_copy[i]); + } + REQUIRE(check_consistency(bitset)); + } + + SECTION("bidirectional iterators") + { + const std::vector values = GENERATE( + take(RANDOM_VARIATIONS_TO_TEST, + randomChunk( + 2, 5, random(std::numeric_limits::min(), std::numeric_limits::max())))); + CAPTURE(values); + + const std::list values_list(std::cbegin(values), std::cend(values)); + bitset.append(std::cbegin(values_list), std::cend(values_list)); + REQUIRE(bitset.size() == (bitset_copy.size() + values.size() * bits_number)); + + // new bits added + size_t value_i = 0; + for(const TestType& value: values) + { + for(size_t bit_i = 0; bit_i < bits_number; ++bit_i) + { + CAPTURE(value_i, bit_i); + REQUIRE(bitset[bitset_copy.size() + value_i * bits_number + bit_i] + == bit_value(value, bit_i)); + } + ++value_i; + } + + // initial bits not changed + for(size_t i = 0; i < bitset_copy.size(); ++i) + { + CAPTURE(i); + REQUIRE(bitset[i] == bitset_copy[i]); + } + REQUIRE(check_consistency(bitset)); + } } TEMPLATE_TEST_CASE("bitwise operators", "[dynamic_bitset]", uint16_t, uint32_t, uint64_t) { - const std::tuple values = - GENERATE(multitake(RANDOM_VECTORS_TO_TEST, - random(std::numeric_limits::min(), - std::numeric_limits::max()), - random(std::numeric_limits::min(), - std::numeric_limits::max()), - random(1, bits_number))); - unsigned long long value1 = std::get<0>(values); - const unsigned long long value2 = std::get<1>(values); - const size_t bits_to_take = std::get<2>(values); - CAPTURE(value1, value2, bits_to_take); - - sul::dynamic_bitset bitset1(bits_to_take, value1); - const sul::dynamic_bitset bitset2(bits_to_take, value2); - CAPTURE(bitset1, bitset2); - - SECTION("assignement operators") - { - SECTION("operator&=") - { - bitset1 &= bitset2; - value1 &= value2; - - // check bits - for(size_t i = 0; i < bits_to_take; ++i) - { - CAPTURE(i); - REQUIRE(bitset1[i] == bit_value(value1, i)); - } - REQUIRE(check_consistency(bitset1)); - REQUIRE(check_consistency(bitset2)); - } - - SECTION("operator|=") - { - bitset1 |= bitset2; - value1 |= value2; - - // check bits - for(size_t i = 0; i < bits_to_take; ++i) - { - CAPTURE(i); - REQUIRE(bitset1[i] == bit_value(value1, i)); - } - REQUIRE(check_consistency(bitset1)); - REQUIRE(check_consistency(bitset2)); - } - - SECTION("operator^=") - { - bitset1 ^= bitset2; - value1 ^= value2; - - // check bits - for(size_t i = 0; i < bits_to_take; ++i) - { - CAPTURE(i); - REQUIRE(bitset1[i] == bit_value(value1, i)); - } - REQUIRE(check_consistency(bitset1)); - REQUIRE(check_consistency(bitset2)); - } - - SECTION("operator-=") - { - bitset1 -= bitset2; - value1 &= ~value2; - - // check bits - for(size_t i = 0; i < bits_to_take; ++i) - { - CAPTURE(i); - REQUIRE(bitset1[i] == bit_value(value1, i)); - } - REQUIRE(check_consistency(bitset1)); - REQUIRE(check_consistency(bitset2)); - } - } - - SECTION("binary operators") - { - SECTION("operator&") - { - const sul::dynamic_bitset bitset = bitset1 & bitset2; - const unsigned long long value = value1 & value2; - - // check bits - for(size_t i = 0; i < bits_to_take; ++i) - { - CAPTURE(i); - REQUIRE(bitset[i] == bit_value(value, i)); - } - REQUIRE(check_consistency(bitset)); - } - - SECTION("operator|") - { - const sul::dynamic_bitset bitset = bitset1 | bitset2; - const unsigned long long value = value1 | value2; - - // check bits - for(size_t i = 0; i < bits_to_take; ++i) - { - CAPTURE(i); - REQUIRE(bitset[i] == bit_value(value, i)); - } - REQUIRE(check_consistency(bitset)); - } - - SECTION("operator^") - { - const sul::dynamic_bitset bitset = bitset1 ^ bitset2; - const unsigned long long value = value1 ^ value2; - - // check bits - for(size_t i = 0; i < bits_to_take; ++i) - { - CAPTURE(i); - REQUIRE(bitset[i] == bit_value(value, i)); - } - REQUIRE(check_consistency(bitset)); - } - - SECTION("operator-") - { - const sul::dynamic_bitset bitset = bitset1 - bitset2; - const unsigned long long value = value1 & ~value2; - - // check bits - for(size_t i = 0; i < bits_to_take; ++i) - { - CAPTURE(i); - REQUIRE(bitset[i] == bit_value(value, i)); - } - REQUIRE(check_consistency(bitset)); - } - } + const std::tuple values = + GENERATE(multitake(RANDOM_VECTORS_TO_TEST, + random(std::numeric_limits::min(), + std::numeric_limits::max()), + random(std::numeric_limits::min(), + std::numeric_limits::max()), + random(1, bits_number))); + unsigned long long value1 = std::get<0>(values); + const unsigned long long value2 = std::get<1>(values); + const size_t bits_to_take = std::get<2>(values); + CAPTURE(value1, value2, bits_to_take); + + sul::dynamic_bitset bitset1(bits_to_take, value1); + const sul::dynamic_bitset bitset2(bits_to_take, value2); + CAPTURE(bitset1, bitset2); + + SECTION("assignement operators") + { + SECTION("operator&=") + { + bitset1 &= bitset2; + value1 &= value2; + + // check bits + for(size_t i = 0; i < bits_to_take; ++i) + { + CAPTURE(i); + REQUIRE(bitset1[i] == bit_value(value1, i)); + } + REQUIRE(check_consistency(bitset1)); + REQUIRE(check_consistency(bitset2)); + } + + SECTION("operator|=") + { + bitset1 |= bitset2; + value1 |= value2; + + // check bits + for(size_t i = 0; i < bits_to_take; ++i) + { + CAPTURE(i); + REQUIRE(bitset1[i] == bit_value(value1, i)); + } + REQUIRE(check_consistency(bitset1)); + REQUIRE(check_consistency(bitset2)); + } + + SECTION("operator^=") + { + bitset1 ^= bitset2; + value1 ^= value2; + + // check bits + for(size_t i = 0; i < bits_to_take; ++i) + { + CAPTURE(i); + REQUIRE(bitset1[i] == bit_value(value1, i)); + } + REQUIRE(check_consistency(bitset1)); + REQUIRE(check_consistency(bitset2)); + } + + SECTION("operator-=") + { + bitset1 -= bitset2; + value1 &= ~value2; + + // check bits + for(size_t i = 0; i < bits_to_take; ++i) + { + CAPTURE(i); + REQUIRE(bitset1[i] == bit_value(value1, i)); + } + REQUIRE(check_consistency(bitset1)); + REQUIRE(check_consistency(bitset2)); + } + } + + SECTION("binary operators") + { + SECTION("operator&") + { + const sul::dynamic_bitset bitset = bitset1 & bitset2; + const unsigned long long value = value1 & value2; + + // check bits + for(size_t i = 0; i < bits_to_take; ++i) + { + CAPTURE(i); + REQUIRE(bitset[i] == bit_value(value, i)); + } + REQUIRE(check_consistency(bitset)); + } + + SECTION("operator|") + { + const sul::dynamic_bitset bitset = bitset1 | bitset2; + const unsigned long long value = value1 | value2; + + // check bits + for(size_t i = 0; i < bits_to_take; ++i) + { + CAPTURE(i); + REQUIRE(bitset[i] == bit_value(value, i)); + } + REQUIRE(check_consistency(bitset)); + } + + SECTION("operator^") + { + const sul::dynamic_bitset bitset = bitset1 ^ bitset2; + const unsigned long long value = value1 ^ value2; + + // check bits + for(size_t i = 0; i < bits_to_take; ++i) + { + CAPTURE(i); + REQUIRE(bitset[i] == bit_value(value, i)); + } + REQUIRE(check_consistency(bitset)); + } + + SECTION("operator-") + { + const sul::dynamic_bitset bitset = bitset1 - bitset2; + const unsigned long long value = value1 & ~value2; + + // check bits + for(size_t i = 0; i < bits_to_take; ++i) + { + CAPTURE(i); + REQUIRE(bitset[i] == bit_value(value, i)); + } + REQUIRE(check_consistency(bitset)); + } + } } TEMPLATE_TEST_CASE("shift operators", "[dynamic_bitset]", uint16_t, uint32_t, uint64_t) { - SECTION("null shifts") - { - sul::dynamic_bitset bitset = - GENERATE(take(RANDOM_VECTORS_TO_TEST, randomDynamicBitset())); - CAPTURE(bitset); - - sul::dynamic_bitset bitset_copy = bitset; - - SECTION("assignement operators") - { - bitset <<= 0; - REQUIRE(bitset == bitset_copy); - bitset >>= 0; - REQUIRE(bitset == bitset_copy); - REQUIRE(check_consistency(bitset)); - } - - SECTION("binary operators") - { - sul::dynamic_bitset result = bitset << 0; - REQUIRE(bitset == bitset_copy); - result = bitset >> 0; - REQUIRE(bitset == bitset_copy); - REQUIRE(check_consistency(bitset)); - } - } - - SECTION("real shifts") - { - const std::tuple values = GENERATE( - multitake(RANDOM_VECTORS_TO_TEST, - random(std::numeric_limits::min(), - std::numeric_limits::max()), - random(1, bits_number), - random(0, bits_number - 1))); - unsigned long long value = std::get<0>(values); - const size_t bits_to_take = std::get<1>(values); - const size_t shift = std::get<2>(values); - CAPTURE(value, bits_to_take, shift); - - sul::dynamic_bitset bitset(bits_to_take, value); - CAPTURE(bitset); - - SECTION("assignement operators") - { - SECTION("operator<<=") - { - bitset <<= shift; - value <<= shift; - - // check bits - for(size_t i = 0; i < bits_to_take; ++i) - { - CAPTURE(i); - REQUIRE(bitset[i] == bit_value(value, i)); - } - REQUIRE(check_consistency(bitset)); - } - - SECTION("operator>>=") - { - bitset >>= shift; - value &= ~static_cast(0) - >> (bits_number - - bits_to_take); // set not taken left bits to 0 - value >>= shift; - - // check bits - for(size_t i = 0; i < bits_to_take; ++i) - { - CAPTURE(i); - REQUIRE(bitset[i] == bit_value(value, i)); - } - REQUIRE(check_consistency(bitset)); - } - } - - SECTION("binary operators") - { - SECTION("operator<<") - { - const sul::dynamic_bitset shifted_bitset = bitset << shift; - const unsigned long long shifted_value = value << shift; - - // check bits - for(size_t i = 0; i < bits_to_take; ++i) - { - CAPTURE(i); - REQUIRE(shifted_bitset[i] == bit_value(shifted_value, i)); - } - REQUIRE(check_consistency(bitset)); - } - - SECTION("operator>>") - { - const sul::dynamic_bitset shifted_bitset = bitset >> shift; - const unsigned long long shifted_value = - (value - & (~static_cast(0) - >> (bits_number - bits_to_take))) - >> shift; - - // check bits - for(size_t i = 0; i < bits_to_take; ++i) - { - CAPTURE(i); - REQUIRE(shifted_bitset[i] == bit_value(shifted_value, i)); - } - REQUIRE(check_consistency(bitset)); - } - } - } + SECTION("null shifts") + { + sul::dynamic_bitset bitset = GENERATE(take(RANDOM_VECTORS_TO_TEST, randomDynamicBitset())); + CAPTURE(bitset); + + sul::dynamic_bitset bitset_copy = bitset; + + SECTION("assignement operators") + { + bitset <<= 0; + REQUIRE(bitset == bitset_copy); + bitset >>= 0; + REQUIRE(bitset == bitset_copy); + REQUIRE(check_consistency(bitset)); + } + + SECTION("binary operators") + { + sul::dynamic_bitset result = bitset << 0; + REQUIRE(bitset == bitset_copy); + result = bitset >> 0; + REQUIRE(bitset == bitset_copy); + REQUIRE(check_consistency(bitset)); + } + } + + SECTION("real shifts") + { + const std::tuple values = + GENERATE(multitake(RANDOM_VECTORS_TO_TEST, + random(std::numeric_limits::min(), + std::numeric_limits::max()), + random(1, bits_number), + random(0, bits_number - 1))); + unsigned long long value = std::get<0>(values); + const size_t bits_to_take = std::get<1>(values); + const size_t shift = std::get<2>(values); + CAPTURE(value, bits_to_take, shift); + + sul::dynamic_bitset bitset(bits_to_take, value); + CAPTURE(bitset); + + SECTION("assignement operators") + { + SECTION("operator<<=") + { + bitset <<= shift; + value <<= shift; + + // check bits + for(size_t i = 0; i < bits_to_take; ++i) + { + CAPTURE(i); + REQUIRE(bitset[i] == bit_value(value, i)); + } + REQUIRE(check_consistency(bitset)); + } + + SECTION("operator>>=") + { + bitset >>= shift; + value &= ~static_cast(0) + >> (bits_number - bits_to_take); // set not taken left bits to 0 + value >>= shift; + + // check bits + for(size_t i = 0; i < bits_to_take; ++i) + { + CAPTURE(i); + REQUIRE(bitset[i] == bit_value(value, i)); + } + REQUIRE(check_consistency(bitset)); + } + } + + SECTION("binary operators") + { + SECTION("operator<<") + { + const sul::dynamic_bitset shifted_bitset = bitset << shift; + const unsigned long long shifted_value = value << shift; + + // check bits + for(size_t i = 0; i < bits_to_take; ++i) + { + CAPTURE(i); + REQUIRE(shifted_bitset[i] == bit_value(shifted_value, i)); + } + REQUIRE(check_consistency(bitset)); + } + + SECTION("operator>>") + { + const sul::dynamic_bitset shifted_bitset = bitset >> shift; + const unsigned long long shifted_value = + (value & (~static_cast(0) >> (bits_number - bits_to_take))) + >> shift; + + // check bits + for(size_t i = 0; i < bits_to_take; ++i) + { + CAPTURE(i); + REQUIRE(shifted_bitset[i] == bit_value(shifted_value, i)); + } + REQUIRE(check_consistency(bitset)); + } + } + } } TEMPLATE_TEST_CASE("operator~", "[dynamic_bitset]", uint16_t, uint32_t, uint64_t) { - const std::tuple values = - GENERATE(multitake(RANDOM_VECTORS_TO_TEST, - random(std::numeric_limits::min(), - std::numeric_limits::max()), - random(1, bits_number))); - unsigned long long value = std::get<0>(values); - const size_t bits_to_take = std::get<1>(values); - CAPTURE(value, bits_to_take); - - sul::dynamic_bitset bitset(bits_to_take, value); - CAPTURE(bitset); - - // operator~ - bitset = ~bitset; - value = ~value; - - // check bits - for(size_t i = 0; i < bits_to_take; ++i) - { - CAPTURE(i); - REQUIRE(bitset[i] == bit_value(value, i)); - } - REQUIRE(check_consistency(bitset)); + const std::tuple values = + GENERATE(multitake(RANDOM_VECTORS_TO_TEST, + random(std::numeric_limits::min(), + std::numeric_limits::max()), + random(1, bits_number))); + unsigned long long value = std::get<0>(values); + const size_t bits_to_take = std::get<1>(values); + CAPTURE(value, bits_to_take); + + sul::dynamic_bitset bitset(bits_to_take, value); + CAPTURE(bitset); + + // operator~ + bitset = ~bitset; + value = ~value; + + // check bits + for(size_t i = 0; i < bits_to_take; ++i) + { + CAPTURE(i); + REQUIRE(bitset[i] == bit_value(value, i)); + } + REQUIRE(check_consistency(bitset)); } TEMPLATE_TEST_CASE("set reset flip", "[dynamic_bitset]", uint16_t, uint32_t, uint64_t) { - sul::dynamic_bitset bitset = GENERATE( - take(RANDOM_VECTORS_TO_TEST, - randomDynamicBitset(3 * bits_number, 8 * bits_number))); - CAPTURE(bitset); - - SECTION("range") - { - const std::tuple values = GENERATE( - multitake(RANDOM_VARIATIONS_TO_TEST, - random(std::numeric_limits::min(), - std::numeric_limits::max()), - random(std::numeric_limits::min(), - std::numeric_limits::max()))); - const size_t pos = std::get<0>(values) % bitset.size(); - const size_t len = std::get<1>(values) % (bitset.size() - pos); - CAPTURE(pos, len); - - const sul::dynamic_bitset bitset_copy = bitset; - - SECTION("set") - { - const bool set_to = GENERATE(true, false); - CAPTURE(set_to); - - bitset.set(0, 0, set_to); - REQUIRE(bitset == bitset_copy); - - bitset.set(pos, 0, set_to); - REQUIRE(bitset == bitset_copy); - - bitset.set(pos, len, set_to); - - // check bits - for(size_t i = 0; i < pos; ++i) - { - CAPTURE(i); - REQUIRE(bitset[i] == bitset_copy[i]); - } - for(size_t i = 0; i < len; ++i) - { - CAPTURE(i); - REQUIRE(bitset[pos + i] == set_to); - } - for(size_t i = pos + len; i < bitset.size(); ++i) - { - CAPTURE(i); - REQUIRE(bitset[i] == bitset_copy[i]); - } - REQUIRE(check_consistency(bitset)); - } - - SECTION("reset") - { - bitset.reset(0, 0); - REQUIRE(bitset == bitset_copy); - - bitset.reset(pos, 0); - REQUIRE(bitset == bitset_copy); - - bitset.reset(pos, len); - - // check bits - for(size_t i = 0; i < pos; ++i) - { - CAPTURE(i); - REQUIRE(bitset[i] == bitset_copy[i]); - } - for(size_t i = 0; i < len; ++i) - { - CAPTURE(i); - REQUIRE(bitset[pos + i] == false); - } - for(size_t i = pos + len; i < bitset.size(); ++i) - { - CAPTURE(i); - REQUIRE(bitset[i] == bitset_copy[i]); - } - REQUIRE(check_consistency(bitset)); - } - - SECTION("flip") - { - bitset.flip(0, 0); - REQUIRE(bitset == bitset_copy); - - bitset.flip(pos, 0); - REQUIRE(bitset == bitset_copy); - - bitset.flip(pos, len); - - // check bits - for(size_t i = 0; i < pos; ++i) - { - CAPTURE(i); - REQUIRE(bitset[i] == bitset_copy[i]); - } - for(size_t i = 0; i < len; ++i) - { - CAPTURE(i); - REQUIRE(bitset[pos + i] != bitset_copy[pos + i]); - } - for(size_t i = pos + len; i < bitset.size(); ++i) - { - CAPTURE(i); - REQUIRE(bitset[i] == bitset_copy[i]); - } - REQUIRE(check_consistency(bitset)); - } - } - - SECTION("single bit") - { - const size_t pos = - GENERATE(take(RANDOM_VARIATIONS_TO_TEST, - random(std::numeric_limits::min(), - std::numeric_limits::max()))) - % bitset.size(); - CAPTURE(pos); - - const sul::dynamic_bitset bitset_copy = bitset; - - SECTION("set") - { - const bool set_to = GENERATE(true, false); - CAPTURE(set_to); - bitset.set(pos, set_to); - - // check bits - for(size_t i = 0; i < pos; ++i) - { - CAPTURE(i); - REQUIRE(bitset[i] == bitset_copy[i]); - } - REQUIRE(bitset[pos] == set_to); - for(size_t i = pos + 1; i < bitset.size(); ++i) - { - CAPTURE(i); - REQUIRE(bitset[i] == bitset_copy[i]); - } - REQUIRE(check_consistency(bitset)); - } - - SECTION("reset") - { - bitset.reset(pos); - - // check bits - for(size_t i = 0; i < pos; ++i) - { - CAPTURE(i); - REQUIRE(bitset[i] == bitset_copy[i]); - } - REQUIRE(bitset[pos] == false); - for(size_t i = pos + 1; i < bitset.size(); ++i) - { - CAPTURE(i); - REQUIRE(bitset[i] == bitset_copy[i]); - } - REQUIRE(check_consistency(bitset)); - } - - SECTION("flip") - { - bitset.flip(pos); - - // check bits - for(size_t i = 0; i < pos; ++i) - { - CAPTURE(i); - REQUIRE(bitset[i] == bitset_copy[i]); - } - REQUIRE(bitset[pos] != bitset_copy[pos]); - for(size_t i = pos + 1; i < bitset.size(); ++i) - { - CAPTURE(i); - REQUIRE(bitset[i] == bitset_copy[i]); - } - REQUIRE(check_consistency(bitset)); - } - } - - SECTION("all bits") - { - SECTION("set") - { - bitset.set(); - - // check bits - REQUIRE(bitset.all()); - REQUIRE(check_consistency(bitset)); - } - - SECTION("reset") - { - bitset.reset(); - - // check bits - REQUIRE(bitset.none()); - REQUIRE(check_consistency(bitset)); - } - - SECTION("flip") - { - const sul::dynamic_bitset bitset_copy = bitset; - bitset.flip(); - - // check bits - for(size_t i = 0; i < bitset.size(); ++i) - { - CAPTURE(i); - REQUIRE(bitset[i] != bitset_copy[i]); - } - REQUIRE(check_consistency(bitset)); - } - } + sul::dynamic_bitset bitset = GENERATE(take( + RANDOM_VECTORS_TO_TEST, randomDynamicBitset(3 * bits_number, 8 * bits_number))); + CAPTURE(bitset); + + SECTION("range") + { + const std::tuple values = + GENERATE(multitake(RANDOM_VARIATIONS_TO_TEST, + random(std::numeric_limits::min(), + std::numeric_limits::max()), + random(std::numeric_limits::min(), + std::numeric_limits::max()))); + const size_t pos = std::get<0>(values) % bitset.size(); + const size_t len = std::get<1>(values) % (bitset.size() - pos); + CAPTURE(pos, len); + + const sul::dynamic_bitset bitset_copy = bitset; + + SECTION("set") + { + const bool set_to = GENERATE(true, false); + CAPTURE(set_to); + + bitset.set(0, 0, set_to); + REQUIRE(bitset == bitset_copy); + + bitset.set(pos, 0, set_to); + REQUIRE(bitset == bitset_copy); + + bitset.set(pos, len, set_to); + + // check bits + for(size_t i = 0; i < pos; ++i) + { + CAPTURE(i); + REQUIRE(bitset[i] == bitset_copy[i]); + } + for(size_t i = 0; i < len; ++i) + { + CAPTURE(i); + REQUIRE(bitset[pos + i] == set_to); + } + for(size_t i = pos + len; i < bitset.size(); ++i) + { + CAPTURE(i); + REQUIRE(bitset[i] == bitset_copy[i]); + } + REQUIRE(check_consistency(bitset)); + } + + SECTION("reset") + { + bitset.reset(0, 0); + REQUIRE(bitset == bitset_copy); + + bitset.reset(pos, 0); + REQUIRE(bitset == bitset_copy); + + bitset.reset(pos, len); + + // check bits + for(size_t i = 0; i < pos; ++i) + { + CAPTURE(i); + REQUIRE(bitset[i] == bitset_copy[i]); + } + for(size_t i = 0; i < len; ++i) + { + CAPTURE(i); + REQUIRE(bitset[pos + i] == false); + } + for(size_t i = pos + len; i < bitset.size(); ++i) + { + CAPTURE(i); + REQUIRE(bitset[i] == bitset_copy[i]); + } + REQUIRE(check_consistency(bitset)); + } + + SECTION("flip") + { + bitset.flip(0, 0); + REQUIRE(bitset == bitset_copy); + + bitset.flip(pos, 0); + REQUIRE(bitset == bitset_copy); + + bitset.flip(pos, len); + + // check bits + for(size_t i = 0; i < pos; ++i) + { + CAPTURE(i); + REQUIRE(bitset[i] == bitset_copy[i]); + } + for(size_t i = 0; i < len; ++i) + { + CAPTURE(i); + REQUIRE(bitset[pos + i] != bitset_copy[pos + i]); + } + for(size_t i = pos + len; i < bitset.size(); ++i) + { + CAPTURE(i); + REQUIRE(bitset[i] == bitset_copy[i]); + } + REQUIRE(check_consistency(bitset)); + } + } + + SECTION("single bit") + { + const size_t pos = GENERATE(take(RANDOM_VARIATIONS_TO_TEST, + random(std::numeric_limits::min(), + std::numeric_limits::max()))) + % bitset.size(); + CAPTURE(pos); + + const sul::dynamic_bitset bitset_copy = bitset; + + SECTION("set") + { + const bool set_to = GENERATE(true, false); + CAPTURE(set_to); + bitset.set(pos, set_to); + + // check bits + for(size_t i = 0; i < pos; ++i) + { + CAPTURE(i); + REQUIRE(bitset[i] == bitset_copy[i]); + } + REQUIRE(bitset[pos] == set_to); + for(size_t i = pos + 1; i < bitset.size(); ++i) + { + CAPTURE(i); + REQUIRE(bitset[i] == bitset_copy[i]); + } + REQUIRE(check_consistency(bitset)); + } + + SECTION("reset") + { + bitset.reset(pos); + + // check bits + for(size_t i = 0; i < pos; ++i) + { + CAPTURE(i); + REQUIRE(bitset[i] == bitset_copy[i]); + } + REQUIRE(bitset[pos] == false); + for(size_t i = pos + 1; i < bitset.size(); ++i) + { + CAPTURE(i); + REQUIRE(bitset[i] == bitset_copy[i]); + } + REQUIRE(check_consistency(bitset)); + } + + SECTION("flip") + { + bitset.flip(pos); + + // check bits + for(size_t i = 0; i < pos; ++i) + { + CAPTURE(i); + REQUIRE(bitset[i] == bitset_copy[i]); + } + REQUIRE(bitset[pos] != bitset_copy[pos]); + for(size_t i = pos + 1; i < bitset.size(); ++i) + { + CAPTURE(i); + REQUIRE(bitset[i] == bitset_copy[i]); + } + REQUIRE(check_consistency(bitset)); + } + } + + SECTION("all bits") + { + SECTION("set") + { + bitset.set(); + + // check bits + REQUIRE(bitset.all()); + REQUIRE(check_consistency(bitset)); + } + + SECTION("reset") + { + bitset.reset(); + + // check bits + REQUIRE(bitset.none()); + REQUIRE(check_consistency(bitset)); + } + + SECTION("flip") + { + const sul::dynamic_bitset bitset_copy = bitset; + bitset.flip(); + + // check bits + for(size_t i = 0; i < bitset.size(); ++i) + { + CAPTURE(i); + REQUIRE(bitset[i] != bitset_copy[i]); + } + REQUIRE(check_consistency(bitset)); + } + } } TEMPLATE_TEST_CASE("test", "[dynamic_bitset]", uint16_t, uint32_t, uint64_t) { - const std::tuple values = - GENERATE(multitake(RANDOM_VECTORS_TO_TEST, - random(std::numeric_limits::min(), - std::numeric_limits::max()), - random(1, bits_number))); - unsigned long long value = std::get<0>(values); - const size_t bits_to_take = std::get<1>(values); - CAPTURE(value, bits_to_take); - - sul::dynamic_bitset bitset(bits_to_take, value); - CAPTURE(bitset); - - // check - for(size_t i = 0; i < bits_to_take; ++i) - { - CAPTURE(i); - REQUIRE(bitset.test(i) == bit_value(value, i)); - } + const std::tuple values = + GENERATE(multitake(RANDOM_VECTORS_TO_TEST, + random(std::numeric_limits::min(), + std::numeric_limits::max()), + random(1, bits_number))); + unsigned long long value = std::get<0>(values); + const size_t bits_to_take = std::get<1>(values); + CAPTURE(value, bits_to_take); + + sul::dynamic_bitset bitset(bits_to_take, value); + CAPTURE(bitset); + + // check + for(size_t i = 0; i < bits_to_take; ++i) + { + CAPTURE(i); + REQUIRE(bitset.test(i) == bit_value(value, i)); + } } TEMPLATE_TEST_CASE("test_set", "[dynamic_bitset]", uint16_t, uint32_t, uint64_t) { - const std::tuple values = - GENERATE(multitake(RANDOM_VECTORS_TO_TEST, - random(std::numeric_limits::min(), - std::numeric_limits::max()), - random(1, bits_number))); - unsigned long long value = std::get<0>(values); - const size_t bits_to_take = std::get<1>(values); - const bool set_to = GENERATE(true, false); - CAPTURE(value, bits_to_take, set_to); - - sul::dynamic_bitset bitset(bits_to_take, value); - CAPTURE(bitset); - - // check - for(size_t i = 0; i < bits_to_take; ++i) - { - CAPTURE(i); - REQUIRE(bitset.test_set(i, set_to) == bit_value(value, i)); - REQUIRE(bitset[i] == set_to); - } - REQUIRE(check_consistency(bitset)); + const std::tuple values = + GENERATE(multitake(RANDOM_VECTORS_TO_TEST, + random(std::numeric_limits::min(), + std::numeric_limits::max()), + random(1, bits_number))); + unsigned long long value = std::get<0>(values); + const size_t bits_to_take = std::get<1>(values); + const bool set_to = GENERATE(true, false); + CAPTURE(value, bits_to_take, set_to); + + sul::dynamic_bitset bitset(bits_to_take, value); + CAPTURE(bitset); + + // check + for(size_t i = 0; i < bits_to_take; ++i) + { + CAPTURE(i); + REQUIRE(bitset.test_set(i, set_to) == bit_value(value, i)); + REQUIRE(bitset[i] == set_to); + } + REQUIRE(check_consistency(bitset)); } TEMPLATE_TEST_CASE("all any none", "[dynamic_bitset]", uint16_t, uint32_t, uint64_t) { - SECTION("empty bitset") - { - sul::dynamic_bitset bitset; - CAPTURE(bitset); - - REQUIRE(bitset.all()); - REQUIRE_FALSE(bitset.any()); - REQUIRE(bitset.none()); - } - - SECTION("non-empty bitset") - { - const size_t bitset_size = - GENERATE(take(RANDOM_VECTORS_TO_TEST, - random(3 * bits_number, 8 * bits_number))); - CAPTURE(bitset_size); - - sul::dynamic_bitset bitset(bitset_size); - CAPTURE(bitset); - - SECTION("all bits on") - { - bitset.set(); - REQUIRE(bitset.all()); - REQUIRE(bitset.any()); - REQUIRE_FALSE(bitset.none()); - } - - SECTION("one bit on") - { - const size_t pos = - GENERATE( - take(RANDOM_VARIATIONS_TO_TEST, - random(std::numeric_limits::min(), - std::numeric_limits::max()))) - % bitset_size; - CAPTURE(pos); - bitset.reset(); - bitset.set(pos); - REQUIRE_FALSE(bitset.all()); - REQUIRE(bitset.any()); - REQUIRE_FALSE(bitset.none()); - } - - SECTION("no bit on") - { - bitset.reset(); - REQUIRE_FALSE(bitset.all()); - REQUIRE_FALSE(bitset.any()); - REQUIRE(bitset.none()); - } - } + SECTION("empty bitset") + { + sul::dynamic_bitset bitset; + CAPTURE(bitset); + + REQUIRE(bitset.all()); + REQUIRE_FALSE(bitset.any()); + REQUIRE(bitset.none()); + } + + SECTION("non-empty bitset") + { + const size_t bitset_size = + GENERATE(take(RANDOM_VECTORS_TO_TEST, random(3 * bits_number, 8 * bits_number))); + CAPTURE(bitset_size); + + sul::dynamic_bitset bitset(bitset_size); + CAPTURE(bitset); + + SECTION("all bits on") + { + bitset.set(); + REQUIRE(bitset.all()); + REQUIRE(bitset.any()); + REQUIRE_FALSE(bitset.none()); + } + + SECTION("one bit on") + { + const size_t pos = + GENERATE(take(RANDOM_VARIATIONS_TO_TEST, + random(std::numeric_limits::min(), + std::numeric_limits::max()))) + % bitset_size; + CAPTURE(pos); + bitset.reset(); + bitset.set(pos); + REQUIRE_FALSE(bitset.all()); + REQUIRE(bitset.any()); + REQUIRE_FALSE(bitset.none()); + } + + SECTION("no bit on") + { + bitset.reset(); + REQUIRE_FALSE(bitset.all()); + REQUIRE_FALSE(bitset.any()); + REQUIRE(bitset.none()); + } + } } TEMPLATE_TEST_CASE("array subscript operator", "[dynamic_bitset]", uint16_t, uint32_t, uint64_t) { - const std::tuple values = - GENERATE(multitake(RANDOM_VECTORS_TO_TEST, - random(std::numeric_limits::min(), - std::numeric_limits::max()), - random(1, bits_number))); - unsigned long long value = std::get<0>(values); - const size_t bits_to_take = std::get<1>(values); - CAPTURE(value, bits_to_take); - - sul::dynamic_bitset bitset(bits_to_take, value); - CAPTURE(bitset); - - SECTION("access") - { - for(size_t i = 0; i < bits_to_take; ++i) - { - CAPTURE(i); - REQUIRE(bitset[i] == bit_value(value, i)); - } - REQUIRE(check_consistency(bitset)); - } - - SECTION("reference operator=") - { - const unsigned long long other_value = GENERATE( - take(1, - random(std::numeric_limits::min(), - std::numeric_limits::max()))); - sul::dynamic_bitset other_bitset(bits_to_take, other_value); - CAPTURE(other_bitset); - - SECTION("with bool") - { - for(size_t i = 0; i < bits_to_take; ++i) - { - bitset[i] = other_bitset.test(i); - } - REQUIRE(bitset == other_bitset); - REQUIRE(check_consistency(bitset)); - } - - SECTION("with reference") - { - for(size_t i = 0; i < bits_to_take; ++i) - { - bitset[i] = other_bitset[i]; - } - REQUIRE(bitset == other_bitset); - REQUIRE(check_consistency(bitset)); - } - } - - SECTION("reference binary operators") - { - const unsigned long long other_value = GENERATE( - take(1, - random(std::numeric_limits::min(), - std::numeric_limits::max()))); - sul::dynamic_bitset other_bitset(bits_to_take, other_value); - CAPTURE(other_bitset); - - sul::dynamic_bitset bitset_copy = bitset; - - SECTION("operator&=") - { - for(size_t i = 0; i < bits_to_take; ++i) - { - bitset[i] &= other_bitset[i]; - } - - bitset_copy &= other_bitset; - REQUIRE(bitset == bitset_copy); - REQUIRE(check_consistency(bitset)); - } - - SECTION("operator|=") - { - for(size_t i = 0; i < bits_to_take; ++i) - { - bitset[i] |= other_bitset[i]; - } - - bitset_copy |= other_bitset; - REQUIRE(bitset == bitset_copy); - REQUIRE(check_consistency(bitset)); - } - - SECTION("operator^=") - { - for(size_t i = 0; i < bits_to_take; ++i) - { - bitset[i] ^= other_bitset[i]; - } - - bitset_copy ^= other_bitset; - REQUIRE(bitset == bitset_copy); - REQUIRE(check_consistency(bitset)); - } - - SECTION("operator-=") - { - for(size_t i = 0; i < bits_to_take; ++i) - { - bitset[i] -= other_bitset[i]; - } - - bitset_copy -= other_bitset; - REQUIRE(bitset == bitset_copy); - REQUIRE(check_consistency(bitset)); - } - } - - SECTION("reference operator~") - { - for(size_t i = 0; i < bits_to_take; ++i) - { - CAPTURE(i); - REQUIRE(~bitset[i] == !bit_value(value, i)); - } - REQUIRE(check_consistency(bitset)); - } - - SECTION("set reset flip assign") - { - const size_t pos = - GENERATE(take(RANDOM_VARIATIONS_TO_TEST, - random(std::numeric_limits::min(), - std::numeric_limits::max()))) - % bits_to_take; - CAPTURE(pos); - - SECTION("set") - { - bitset[pos].set(); - REQUIRE(bitset[pos] == true); - REQUIRE(check_consistency(bitset)); - } - - SECTION("reset") - { - bitset[pos].reset(); - REQUIRE(bitset[pos] == false); - REQUIRE(check_consistency(bitset)); - } - - SECTION("flip") - { - bitset[pos].flip(); - REQUIRE(bitset[pos] == !bit_value(value, pos)); - REQUIRE(check_consistency(bitset)); - } - - SECTION("assign") - { - const bool new_value = GENERATE(true, false); - CAPTURE(new_value); - bitset[pos].assign(new_value); - REQUIRE(bitset[pos] == new_value); - REQUIRE(check_consistency(bitset)); - } - } + const std::tuple values = + GENERATE(multitake(RANDOM_VECTORS_TO_TEST, + random(std::numeric_limits::min(), + std::numeric_limits::max()), + random(1, bits_number))); + unsigned long long value = std::get<0>(values); + const size_t bits_to_take = std::get<1>(values); + CAPTURE(value, bits_to_take); + + sul::dynamic_bitset bitset(bits_to_take, value); + CAPTURE(bitset); + + SECTION("access") + { + for(size_t i = 0; i < bits_to_take; ++i) + { + CAPTURE(i); + REQUIRE(bitset[i] == bit_value(value, i)); + } + REQUIRE(check_consistency(bitset)); + } + + SECTION("reference operator=") + { + const unsigned long long other_value = + GENERATE(take(1, + random(std::numeric_limits::min(), + std::numeric_limits::max()))); + sul::dynamic_bitset other_bitset(bits_to_take, other_value); + CAPTURE(other_bitset); + + SECTION("with bool") + { + for(size_t i = 0; i < bits_to_take; ++i) + { + bitset[i] = other_bitset.test(i); + } + REQUIRE(bitset == other_bitset); + REQUIRE(check_consistency(bitset)); + } + + SECTION("with reference") + { + for(size_t i = 0; i < bits_to_take; ++i) + { + bitset[i] = other_bitset[i]; + } + REQUIRE(bitset == other_bitset); + REQUIRE(check_consistency(bitset)); + } + } + + SECTION("reference binary operators") + { + const unsigned long long other_value = + GENERATE(take(1, + random(std::numeric_limits::min(), + std::numeric_limits::max()))); + sul::dynamic_bitset other_bitset(bits_to_take, other_value); + CAPTURE(other_bitset); + + sul::dynamic_bitset bitset_copy = bitset; + + SECTION("operator&=") + { + for(size_t i = 0; i < bits_to_take; ++i) + { + bitset[i] &= other_bitset[i]; + } + + bitset_copy &= other_bitset; + REQUIRE(bitset == bitset_copy); + REQUIRE(check_consistency(bitset)); + } + + SECTION("operator|=") + { + for(size_t i = 0; i < bits_to_take; ++i) + { + bitset[i] |= other_bitset[i]; + } + + bitset_copy |= other_bitset; + REQUIRE(bitset == bitset_copy); + REQUIRE(check_consistency(bitset)); + } + + SECTION("operator^=") + { + for(size_t i = 0; i < bits_to_take; ++i) + { + bitset[i] ^= other_bitset[i]; + } + + bitset_copy ^= other_bitset; + REQUIRE(bitset == bitset_copy); + REQUIRE(check_consistency(bitset)); + } + + SECTION("operator-=") + { + for(size_t i = 0; i < bits_to_take; ++i) + { + bitset[i] -= other_bitset[i]; + } + + bitset_copy -= other_bitset; + REQUIRE(bitset == bitset_copy); + REQUIRE(check_consistency(bitset)); + } + } + + SECTION("reference operator~") + { + for(size_t i = 0; i < bits_to_take; ++i) + { + CAPTURE(i); + REQUIRE(~bitset[i] == !bit_value(value, i)); + } + REQUIRE(check_consistency(bitset)); + } + + SECTION("set reset flip assign") + { + const size_t pos = GENERATE(take(RANDOM_VARIATIONS_TO_TEST, + random(std::numeric_limits::min(), + std::numeric_limits::max()))) + % bits_to_take; + CAPTURE(pos); + + SECTION("set") + { + bitset[pos].set(); + REQUIRE(bitset[pos] == true); + REQUIRE(check_consistency(bitset)); + } + + SECTION("reset") + { + bitset[pos].reset(); + REQUIRE(bitset[pos] == false); + REQUIRE(check_consistency(bitset)); + } + + SECTION("flip") + { + bitset[pos].flip(); + REQUIRE(bitset[pos] == !bit_value(value, pos)); + REQUIRE(check_consistency(bitset)); + } + + SECTION("assign") + { + const bool new_value = GENERATE(true, false); + CAPTURE(new_value); + bitset[pos].assign(new_value); + REQUIRE(bitset[pos] == new_value); + REQUIRE(check_consistency(bitset)); + } + } } -TEMPLATE_TEST_CASE("size num_blocks empty capacity", - "[dynamic_bitset]", - uint16_t, - uint32_t, - uint64_t) +TEMPLATE_TEST_CASE("size num_blocks empty capacity", "[dynamic_bitset]", uint16_t, uint32_t, uint64_t) { - const std::tuple values = - GENERATE(multitake(RANDOM_VECTORS_TO_TEST, - random(std::numeric_limits::min(), - std::numeric_limits::max()), - random(1, bits_number))); - unsigned long long value = std::get<0>(values); - const size_t bits_to_take = std::get<1>(values); - CAPTURE(value, bits_to_take); - - sul::dynamic_bitset bitset(bits_to_take, value); - CAPTURE(bitset); - - // size - REQUIRE(bitset.size() == bits_to_take); - - // num_blocks - const size_t num_blocks = bits_to_take / bits_number - + static_cast(bits_to_take % bits_number > 0); - REQUIRE(bitset.num_blocks() == num_blocks); - - const size_t old_capacity = bitset.capacity(); - bitset.clear(); - REQUIRE(bitset.empty()); - - REQUIRE(bitset.capacity() == old_capacity); + const std::tuple values = + GENERATE(multitake(RANDOM_VECTORS_TO_TEST, + random(std::numeric_limits::min(), + std::numeric_limits::max()), + random(1, bits_number))); + unsigned long long value = std::get<0>(values); + const size_t bits_to_take = std::get<1>(values); + CAPTURE(value, bits_to_take); + + sul::dynamic_bitset bitset(bits_to_take, value); + CAPTURE(bitset); + + // size + REQUIRE(bitset.size() == bits_to_take); + + // num_blocks + const size_t num_blocks = + bits_to_take / bits_number + static_cast(bits_to_take % bits_number > 0); + REQUIRE(bitset.num_blocks() == num_blocks); + + const size_t old_capacity = bitset.capacity(); + bitset.clear(); + REQUIRE(bitset.empty()); + + REQUIRE(bitset.capacity() == old_capacity); } TEMPLATE_TEST_CASE("reserve shrink_to_fit", "[dynamic_bitset]", uint16_t, uint32_t, uint64_t) { - const size_t size = - GENERATE(take(RANDOM_VARIATIONS_TO_TEST, random(1, 8 * bits_number))); - CAPTURE(size); + const size_t size = GENERATE(take(RANDOM_VARIATIONS_TO_TEST, random(1, 8 * bits_number))); + CAPTURE(size); - sul::dynamic_bitset bitset; - bitset.reserve(size); + sul::dynamic_bitset bitset; + bitset.reserve(size); - REQUIRE(bitset.capacity() > 0); + REQUIRE(bitset.capacity() > 0); - bitset.shrink_to_fit(); - REQUIRE(check_consistency(bitset)); + bitset.shrink_to_fit(); + REQUIRE(check_consistency(bitset)); } -TEMPLATE_TEST_CASE("is_subset_of is_proper_subset_of", - "[dynamic_bitset]", - uint16_t, - uint32_t, - uint64_t) +TEMPLATE_TEST_CASE("is_subset_of is_proper_subset_of", "[dynamic_bitset]", uint16_t, uint32_t, uint64_t) { - sul::dynamic_bitset bitset = - GENERATE(take(RANDOM_VECTORS_TO_TEST, randomDynamicBitset())); - CAPTURE(bitset); - - const sul::dynamic_bitset bitset_copy = bitset; - - SECTION("subset") - { - REQUIRE(bitset.is_subset_of(bitset_copy) == true); - REQUIRE(bitset.is_proper_subset_of(bitset_copy) == false); - } - - SECTION("proper subset") - { - if(bitset.any()) - { - const size_t bit_to_reset = - GENERATE( - take(RANDOM_VARIATIONS_TO_TEST, - random(std::numeric_limits::min(), - std::numeric_limits::max()))) - % bitset.count(); - size_t bit_to_reset_pos = bitset.find_first(); - for(size_t i = 1; i < bit_to_reset; ++i) - { - bit_to_reset_pos = bitset.find_next(bit_to_reset_pos); - } - bitset.reset(bit_to_reset_pos); - - REQUIRE(bitset.is_subset_of(bitset_copy) == true); - REQUIRE(bitset.is_proper_subset_of(bitset_copy) == true); - } - } - - SECTION("not a subset") - { - if(!bitset.all()) - { - const sul::dynamic_bitset not_bitset = ~bitset; - const size_t bit_to_set = - GENERATE( - take(RANDOM_VARIATIONS_TO_TEST, - random(std::numeric_limits::min(), - std::numeric_limits::max()))) - % not_bitset.count(); - size_t bit_to_set_pos = not_bitset.find_first(); - for(size_t i = 1; i < bit_to_set; ++i) - { - bit_to_set_pos = not_bitset.find_next(bit_to_set_pos); - } - bitset.set(bit_to_set_pos); - - REQUIRE(bitset.is_subset_of(bitset_copy) == false); - REQUIRE(bitset.is_proper_subset_of(bitset_copy) == false); - } - } + sul::dynamic_bitset bitset = GENERATE(take(RANDOM_VECTORS_TO_TEST, randomDynamicBitset())); + CAPTURE(bitset); + + const sul::dynamic_bitset bitset_copy = bitset; + + SECTION("subset") + { + REQUIRE(bitset.is_subset_of(bitset_copy) == true); + REQUIRE(bitset.is_proper_subset_of(bitset_copy) == false); + } + + SECTION("proper subset") + { + if(bitset.any()) + { + const size_t bit_to_reset = + GENERATE(take(RANDOM_VARIATIONS_TO_TEST, + random(std::numeric_limits::min(), + std::numeric_limits::max()))) + % bitset.count(); + size_t bit_to_reset_pos = bitset.find_first(); + for(size_t i = 1; i < bit_to_reset; ++i) + { + bit_to_reset_pos = bitset.find_next(bit_to_reset_pos); + } + bitset.reset(bit_to_reset_pos); + + REQUIRE(bitset.is_subset_of(bitset_copy) == true); + REQUIRE(bitset.is_proper_subset_of(bitset_copy) == true); + } + } + + SECTION("not a subset") + { + if(!bitset.all()) + { + const sul::dynamic_bitset not_bitset = ~bitset; + const size_t bit_to_set = + GENERATE(take(RANDOM_VARIATIONS_TO_TEST, + random(std::numeric_limits::min(), + std::numeric_limits::max()))) + % not_bitset.count(); + size_t bit_to_set_pos = not_bitset.find_first(); + for(size_t i = 1; i < bit_to_set; ++i) + { + bit_to_set_pos = not_bitset.find_next(bit_to_set_pos); + } + bitset.set(bit_to_set_pos); + + REQUIRE(bitset.is_subset_of(bitset_copy) == false); + REQUIRE(bitset.is_proper_subset_of(bitset_copy) == false); + } + } } TEMPLATE_TEST_CASE("intersects", "[dynamic_bitset]", uint16_t, uint32_t, uint64_t) { - sul::dynamic_bitset bitset = - GENERATE(take(RANDOM_VECTORS_TO_TEST, randomDynamicBitset())); - CAPTURE(bitset); - - // require non 0-only bitset - if(bitset.none()) - { - bitset.push_back(true); - } - - const sul::dynamic_bitset bitset_copy = bitset; - - REQUIRE(bitset.intersects(bitset_copy)); - - if(!bitset.all()) - { - // flip first bit at 0 - for(size_t i = 0; i < bitset.size(); ++i) - { - if(bitset.test(i) == false) - { - bitset.flip(i); - break; - } - } - REQUIRE(bitset.intersects(bitset_copy)); - } - - bitset.flip(); - REQUIRE_FALSE(bitset.intersects(bitset_copy)); - bitset.reset(); - REQUIRE_FALSE(bitset.intersects(bitset_copy)); + sul::dynamic_bitset bitset = GENERATE(take(RANDOM_VECTORS_TO_TEST, randomDynamicBitset())); + CAPTURE(bitset); + + // require non 0-only bitset + if(bitset.none()) + { + bitset.push_back(true); + } + + const sul::dynamic_bitset bitset_copy = bitset; + + REQUIRE(bitset.intersects(bitset_copy)); + + if(!bitset.all()) + { + // flip first bit at 0 + for(size_t i = 0; i < bitset.size(); ++i) + { + if(bitset.test(i) == false) + { + bitset.flip(i); + break; + } + } + REQUIRE(bitset.intersects(bitset_copy)); + } + + bitset.flip(); + REQUIRE_FALSE(bitset.intersects(bitset_copy)); + bitset.reset(); + REQUIRE_FALSE(bitset.intersects(bitset_copy)); } TEMPLATE_TEST_CASE("swap", "[dynamic_bitset]", uint16_t, uint32_t, uint64_t) { - const std::tuple, sul::dynamic_bitset> bitsets = - GENERATE(multitake( - RANDOM_VECTORS_TO_TEST, randomDynamicBitset(), randomDynamicBitset())); - sul::dynamic_bitset bitset1 = std::get<0>(bitsets); - sul::dynamic_bitset bitset2 = std::get<1>(bitsets); - CAPTURE(bitset1, bitset2); - - SECTION("member function") - { - const sul::dynamic_bitset bitset1_copy = bitset1; - const sul::dynamic_bitset bitset2_copy = bitset2; - bitset1.swap(bitset2); - REQUIRE(bitset1 == bitset2_copy); - REQUIRE(bitset2 == bitset1_copy); - REQUIRE(check_consistency(bitset1)); - REQUIRE(check_consistency(bitset2)); - } - - SECTION("external function") - { - const sul::dynamic_bitset bitset1_copy = bitset1; - const sul::dynamic_bitset bitset2_copy = bitset2; - swap(bitset1, bitset2); - REQUIRE(bitset1 == bitset2_copy); - REQUIRE(bitset2 == bitset1_copy); - REQUIRE(check_consistency(bitset1)); - REQUIRE(check_consistency(bitset2)); - } + const std::tuple, sul::dynamic_bitset> bitsets = + GENERATE(multitake(RANDOM_VECTORS_TO_TEST, randomDynamicBitset(), randomDynamicBitset())); + sul::dynamic_bitset bitset1 = std::get<0>(bitsets); + sul::dynamic_bitset bitset2 = std::get<1>(bitsets); + CAPTURE(bitset1, bitset2); + + SECTION("member function") + { + const sul::dynamic_bitset bitset1_copy = bitset1; + const sul::dynamic_bitset bitset2_copy = bitset2; + bitset1.swap(bitset2); + REQUIRE(bitset1 == bitset2_copy); + REQUIRE(bitset2 == bitset1_copy); + REQUIRE(check_consistency(bitset1)); + REQUIRE(check_consistency(bitset2)); + } + + SECTION("external function") + { + const sul::dynamic_bitset bitset1_copy = bitset1; + const sul::dynamic_bitset bitset2_copy = bitset2; + swap(bitset1, bitset2); + REQUIRE(bitset1 == bitset2_copy); + REQUIRE(bitset2 == bitset1_copy); + REQUIRE(check_consistency(bitset1)); + REQUIRE(check_consistency(bitset2)); + } } TEMPLATE_TEST_CASE("get_allocator", "[dynamic_bitset]", uint16_t, uint32_t, uint64_t) { - sul::dynamic_bitset bitset; - static_cast(bitset.get_allocator()); // avoid unused warnings + sul::dynamic_bitset bitset; + static_cast(bitset.get_allocator()); // avoid unused warnings } TEMPLATE_TEST_CASE("to_string", "[dynamic_bitset]", uint16_t, uint32_t, uint64_t) { - const std::tuple values = - GENERATE(multitake(RANDOM_VECTORS_TO_TEST, - random(std::numeric_limits::min(), - std::numeric_limits::max()), - random(1, bits_number))); - unsigned long long value = std::get<0>(values); - const size_t bits_to_take = std::get<1>(values); - CAPTURE(value, bits_to_take); - - sul::dynamic_bitset bitset(bits_to_take, value); - CAPTURE(bitset); - - std::string string; - string.reserve(bits_to_take); - for(size_t i = bits_to_take - 1; i > 0; --i) - { - string.push_back(bit_value(value, i) ? '1' : '0'); - } - string.push_back(bit_value(value, 0) ? '1' : '0'); - - REQUIRE(bitset.to_string() == string); + const std::tuple values = + GENERATE(multitake(RANDOM_VECTORS_TO_TEST, + random(std::numeric_limits::min(), + std::numeric_limits::max()), + random(1, bits_number))); + unsigned long long value = std::get<0>(values); + const size_t bits_to_take = std::get<1>(values); + CAPTURE(value, bits_to_take); + + sul::dynamic_bitset bitset(bits_to_take, value); + CAPTURE(bitset); + + std::string string; + string.reserve(bits_to_take); + for(size_t i = bits_to_take - 1; i > 0; --i) + { + string.push_back(bit_value(value, i) ? '1' : '0'); + } + string.push_back(bit_value(value, 0) ? '1' : '0'); + + REQUIRE(bitset.to_string() == string); } TEMPLATE_TEST_CASE("to_ulong", "[dynamic_bitset]", uint16_t, uint32_t, uint64_t) { - SECTION("empty bitset") - { - const sul::dynamic_bitset bitset; - - REQUIRE(bitset.to_ulong() == 0); - } - - SECTION("non-empty bitset") - { - SECTION("value") - { - const std::tuple values = GENERATE( - multitake(RANDOM_VECTORS_TO_TEST, - random(std::numeric_limits::min(), - std::numeric_limits::max()), - random(1, bits_number))); - unsigned long long value = std::get<0>(values); - const size_t bits_to_take = std::get<1>(values); - CAPTURE(value, bits_to_take); - - sul::dynamic_bitset bitset(bits_to_take, value); - CAPTURE(bitset); - - unsigned long long bits_taken_mask = - one_block >> (bits_number - bits_to_take); - unsigned long ulong_value = static_cast(value & bits_taken_mask); - - REQUIRE(bitset.to_ulong() == ulong_value); - } - - SECTION("overflow exception") - { - sul::dynamic_bitset bitset = - GENERATE(take(RANDOM_VECTORS_TO_TEST, randomDynamicBitset())); - CAPTURE(bitset); - - size_t last = sul::dynamic_bitset::npos; - bitset.iterate_bits_on([&last](size_t bit_pos) noexcept { last = bit_pos; }); - if(last == sul::dynamic_bitset::npos || last <= bits_number) - { - do - { - bitset.push_back(true); - } while(bitset.size() <= bits_number); - } - CAPTURE(bitset); - - REQUIRE_THROWS(bitset.to_ulong()); - } - } + SECTION("empty bitset") + { + const sul::dynamic_bitset bitset; + + REQUIRE(bitset.to_ulong() == 0); + } + + SECTION("non-empty bitset") + { + SECTION("value") + { + const std::tuple values = + GENERATE(multitake(RANDOM_VECTORS_TO_TEST, + random(std::numeric_limits::min(), + std::numeric_limits::max()), + random(1, bits_number))); + unsigned long long value = std::get<0>(values); + const size_t bits_to_take = std::get<1>(values); + CAPTURE(value, bits_to_take); + + sul::dynamic_bitset bitset(bits_to_take, value); + CAPTURE(bitset); + + unsigned long long bits_taken_mask = + one_block >> (bits_number - bits_to_take); + unsigned long ulong_value = static_cast(value & bits_taken_mask); + + REQUIRE(bitset.to_ulong() == ulong_value); + } + + SECTION("overflow exception") + { + sul::dynamic_bitset bitset = + GENERATE(take(RANDOM_VECTORS_TO_TEST, randomDynamicBitset())); + CAPTURE(bitset); + + size_t last = sul::dynamic_bitset::npos; + bitset.iterate_bits_on([&last](size_t bit_pos) noexcept { last = bit_pos; }); + if(last == sul::dynamic_bitset::npos || last <= bits_number) + { + do + { + bitset.push_back(true); + } while(bitset.size() <= bits_number); + } + CAPTURE(bitset); + + REQUIRE_THROWS(bitset.to_ulong()); + } + } } TEMPLATE_TEST_CASE("to_ullong", "[dynamic_bitset]", uint16_t, uint32_t, uint64_t) { - SECTION("empty bitset") - { - const sul::dynamic_bitset bitset; - - REQUIRE(bitset.to_ullong() == 0); - } - - SECTION("non-empty bitset") - { - SECTION("value") - { - const std::tuple values = GENERATE( - multitake(RANDOM_VECTORS_TO_TEST, - random(std::numeric_limits::min(), - std::numeric_limits::max()), - random(1, bits_number))); - unsigned long long value = std::get<0>(values); - const size_t bits_to_take = std::get<1>(values); - CAPTURE(value, bits_to_take); - - sul::dynamic_bitset bitset(bits_to_take, value); - CAPTURE(bitset); - - unsigned long long bits_taken_mask = - one_block >> (bits_number - bits_to_take); - unsigned long long ullong_value = value & bits_taken_mask; - - REQUIRE(bitset.to_ullong() == ullong_value); - } - - SECTION("overflow exception") - { - sul::dynamic_bitset bitset = - GENERATE(take(RANDOM_VECTORS_TO_TEST, randomDynamicBitset())); - CAPTURE(bitset); - - size_t last = sul::dynamic_bitset::npos; - bitset.iterate_bits_on([&last](size_t bit_pos) noexcept { last = bit_pos; }); - if(last == sul::dynamic_bitset::npos - || last <= bits_number) - { - do - { - bitset.push_back(true); - } while(bitset.size() <= bits_number); - } - CAPTURE(bitset); - - REQUIRE_THROWS(bitset.to_ullong()); - } - } + SECTION("empty bitset") + { + const sul::dynamic_bitset bitset; + + REQUIRE(bitset.to_ullong() == 0); + } + + SECTION("non-empty bitset") + { + SECTION("value") + { + const std::tuple values = + GENERATE(multitake(RANDOM_VECTORS_TO_TEST, + random(std::numeric_limits::min(), + std::numeric_limits::max()), + random(1, bits_number))); + unsigned long long value = std::get<0>(values); + const size_t bits_to_take = std::get<1>(values); + CAPTURE(value, bits_to_take); + + sul::dynamic_bitset bitset(bits_to_take, value); + CAPTURE(bitset); + + unsigned long long bits_taken_mask = + one_block >> (bits_number - bits_to_take); + unsigned long long ullong_value = value & bits_taken_mask; + + REQUIRE(bitset.to_ullong() == ullong_value); + } + + SECTION("overflow exception") + { + sul::dynamic_bitset bitset = + GENERATE(take(RANDOM_VECTORS_TO_TEST, randomDynamicBitset())); + CAPTURE(bitset); + + size_t last = sul::dynamic_bitset::npos; + bitset.iterate_bits_on([&last](size_t bit_pos) noexcept { last = bit_pos; }); + if(last == sul::dynamic_bitset::npos || last <= bits_number) + { + do + { + bitset.push_back(true); + } while(bitset.size() <= bits_number); + } + CAPTURE(bitset); + + REQUIRE_THROWS(bitset.to_ullong()); + } + } } TEMPLATE_TEST_CASE("iterate_bits_on", "[dynamic_bitset]", uint16_t, uint32_t, uint64_t) { - const std::tuple values = - GENERATE(multitake(RANDOM_VECTORS_TO_TEST, - random(std::numeric_limits::min(), - std::numeric_limits::max()), - random(1, bits_number))); - unsigned long long value = std::get<0>(values); - const size_t bits_to_take = std::get<1>(values); - CAPTURE(value, bits_to_take); - - sul::dynamic_bitset bitset(bits_to_take, value); - CAPTURE(bitset); - - SECTION("return void") - { - SECTION("no parameters") - { - size_t current_check_bit = 0; - bitset.iterate_bits_on([&](size_t bit_pos) { - while(current_check_bit < bit_pos) - { - REQUIRE(bitset[current_check_bit] == false); - ++current_check_bit; - } - REQUIRE(bitset[bit_pos] == true); - ++current_check_bit; - }); - for(size_t i = current_check_bit; i < bits_to_take; ++i) - { - REQUIRE(bitset[i] == false); - } - } - - SECTION("parameters") - { - sul::dynamic_bitset check_bitset(bits_to_take); - bitset.iterate_bits_on( - [](size_t bit_pos, sul::dynamic_bitset& check_bitset_) { - check_bitset_[bit_pos] = true; - }, - check_bitset); - REQUIRE(check_bitset == bitset); - } - } - - SECTION("return bool") - { - if(bitset.count() == 0) - { - bitset.push_back(true); - } - const size_t stop_at_bit = - GENERATE(take(RANDOM_VARIATIONS_TO_TEST, - random(std::numeric_limits::min(), - std::numeric_limits::max()))) - % bitset.count() - + 1; - - SECTION("no parameters") - { - size_t current_check_bit = 0; - size_t bit_count = 0; - bitset.iterate_bits_on([&](size_t bit_pos) { - while(current_check_bit < bit_pos) - { - REQUIRE(bitset[current_check_bit] == false); - ++current_check_bit; - } - REQUIRE(bitset[bit_pos] == true); - ++current_check_bit; - - ++bit_count; - return bit_count < stop_at_bit; - }); - REQUIRE(bit_count == stop_at_bit); - } - - SECTION("parameters") - { - size_t bit_count = 0; - size_t last_bit_pos = 0; - sul::dynamic_bitset check_bitset(bitset.size()); - bitset.iterate_bits_on( - [](size_t bit_pos, - sul::dynamic_bitset& check_bitset_, - size_t& bit_count_, - size_t& last_bit_pos_, - const size_t stop_at_bit_) { - check_bitset_[bit_pos] = true; - last_bit_pos_ = bit_pos; - - ++bit_count_; - return bit_count_ < stop_at_bit_; - }, - check_bitset, - bit_count, - last_bit_pos, - stop_at_bit); - REQUIRE(bit_count == stop_at_bit); - - check_bitset.resize(last_bit_pos); - bitset.resize(last_bit_pos); - REQUIRE(check_bitset == bitset); - } - } + const std::tuple values = + GENERATE(multitake(RANDOM_VECTORS_TO_TEST, + random(std::numeric_limits::min(), + std::numeric_limits::max()), + random(1, bits_number))); + unsigned long long value = std::get<0>(values); + const size_t bits_to_take = std::get<1>(values); + CAPTURE(value, bits_to_take); + + sul::dynamic_bitset bitset(bits_to_take, value); + CAPTURE(bitset); + + SECTION("return void") + { + SECTION("no parameters") + { + size_t current_check_bit = 0; + bitset.iterate_bits_on( + [&](size_t bit_pos) + { + while(current_check_bit < bit_pos) + { + REQUIRE(bitset[current_check_bit] == false); + ++current_check_bit; + } + REQUIRE(bitset[bit_pos] == true); + ++current_check_bit; + }); + for(size_t i = current_check_bit; i < bits_to_take; ++i) + { + REQUIRE(bitset[i] == false); + } + } + + SECTION("parameters") + { + sul::dynamic_bitset check_bitset(bits_to_take); + bitset.iterate_bits_on([](size_t bit_pos, sul::dynamic_bitset& check_bitset_) + { check_bitset_[bit_pos] = true; }, + check_bitset); + REQUIRE(check_bitset == bitset); + } + } + + SECTION("return bool") + { + if(bitset.count() == 0) + { + bitset.push_back(true); + } + const size_t stop_at_bit = + GENERATE(take(RANDOM_VARIATIONS_TO_TEST, + random(std::numeric_limits::min(), + std::numeric_limits::max()))) + % bitset.count() + + 1; + + SECTION("no parameters") + { + size_t current_check_bit = 0; + size_t bit_count = 0; + bitset.iterate_bits_on( + [&](size_t bit_pos) + { + while(current_check_bit < bit_pos) + { + REQUIRE(bitset[current_check_bit] == false); + ++current_check_bit; + } + REQUIRE(bitset[bit_pos] == true); + ++current_check_bit; + + ++bit_count; + return bit_count < stop_at_bit; + }); + REQUIRE(bit_count == stop_at_bit); + } + + SECTION("parameters") + { + size_t bit_count = 0; + size_t last_bit_pos = 0; + sul::dynamic_bitset check_bitset(bitset.size()); + bitset.iterate_bits_on( + [](size_t bit_pos, + sul::dynamic_bitset& check_bitset_, + size_t& bit_count_, + size_t& last_bit_pos_, + const size_t stop_at_bit_) + { + check_bitset_[bit_pos] = true; + last_bit_pos_ = bit_pos; + + ++bit_count_; + return bit_count_ < stop_at_bit_; + }, + check_bitset, + bit_count, + last_bit_pos, + stop_at_bit); + REQUIRE(bit_count == stop_at_bit); + + check_bitset.resize(last_bit_pos); + bitset.resize(last_bit_pos); + REQUIRE(check_bitset == bitset); + } + } } TEMPLATE_TEST_CASE("data", "[dynamic_bitset]", uint16_t, uint32_t, uint64_t) { - SECTION("const") - { - const sul::dynamic_bitset bitset = - GENERATE(take(RANDOM_VECTORS_TO_TEST, randomDynamicBitset())); - CAPTURE(bitset); - - if(!bitset.empty()) - { - REQUIRE(bitset.data() != nullptr); - } - REQUIRE(check_consistency(bitset)); - } - - SECTION("non-const") - { - sul::dynamic_bitset bitset = - GENERATE(take(RANDOM_VECTORS_TO_TEST, randomDynamicBitset())); - CAPTURE(bitset); - - if(!bitset.empty()) - { - REQUIRE(bitset.data() != nullptr); - } - REQUIRE(check_consistency(bitset)); - } + SECTION("const") + { + const sul::dynamic_bitset bitset = + GENERATE(take(RANDOM_VECTORS_TO_TEST, randomDynamicBitset())); + CAPTURE(bitset); + + if(!bitset.empty()) + { + REQUIRE(bitset.data() != nullptr); + } + REQUIRE(check_consistency(bitset)); + } + + SECTION("non-const") + { + sul::dynamic_bitset bitset = GENERATE(take(RANDOM_VECTORS_TO_TEST, randomDynamicBitset())); + CAPTURE(bitset); + + if(!bitset.empty()) + { + REQUIRE(bitset.data() != nullptr); + } + REQUIRE(check_consistency(bitset)); + } } TEMPLATE_TEST_CASE("operator== operator!=", "[dynamic_bitset]", uint16_t, uint32_t, uint64_t) { - sul::dynamic_bitset bitset = - GENERATE(take(RANDOM_VECTORS_TO_TEST, randomDynamicBitset())); - CAPTURE(bitset); - - SECTION("same") - { - const sul::dynamic_bitset bitset_copy = bitset; - REQUIRE(bitset == bitset_copy); - REQUIRE_FALSE(bitset != bitset_copy); - } - - SECTION("different size and same bits") - { - const sul::dynamic_bitset bitset_copy = bitset; - bitset.push_back(true); - REQUIRE_FALSE(bitset == bitset_copy); - REQUIRE_FALSE(bitset_copy == bitset); - REQUIRE(bitset != bitset_copy); - REQUIRE(bitset_copy != bitset); - } - - SECTION("same size and different bits") - { - if(bitset.empty()) - { - bitset.push_back(true); - } - const sul::dynamic_bitset bitset_copy = bitset; - - size_t pos = - GENERATE(take(RANDOM_VARIATIONS_TO_TEST, - random(std::numeric_limits::min(), - std::numeric_limits::max()))) - % bitset.size(); - CAPTURE(pos); - bitset.flip(pos); - REQUIRE_FALSE(bitset == bitset_copy); - REQUIRE_FALSE(bitset_copy == bitset); - REQUIRE(bitset != bitset_copy); - REQUIRE(bitset_copy != bitset); - } + sul::dynamic_bitset bitset = GENERATE(take(RANDOM_VECTORS_TO_TEST, randomDynamicBitset())); + CAPTURE(bitset); + + SECTION("same") + { + const sul::dynamic_bitset bitset_copy = bitset; + REQUIRE(bitset == bitset_copy); + REQUIRE_FALSE(bitset != bitset_copy); + } + + SECTION("different size and same bits") + { + const sul::dynamic_bitset bitset_copy = bitset; + bitset.push_back(true); + REQUIRE_FALSE(bitset == bitset_copy); + REQUIRE_FALSE(bitset_copy == bitset); + REQUIRE(bitset != bitset_copy); + REQUIRE(bitset_copy != bitset); + } + + SECTION("same size and different bits") + { + if(bitset.empty()) + { + bitset.push_back(true); + } + const sul::dynamic_bitset bitset_copy = bitset; + + size_t pos = GENERATE(take(RANDOM_VARIATIONS_TO_TEST, + random(std::numeric_limits::min(), + std::numeric_limits::max()))) + % bitset.size(); + CAPTURE(pos); + bitset.flip(pos); + REQUIRE_FALSE(bitset == bitset_copy); + REQUIRE_FALSE(bitset_copy == bitset); + REQUIRE(bitset != bitset_copy); + REQUIRE(bitset_copy != bitset); + } } -TEMPLATE_TEST_CASE("operator< operator<= operator> operator>=", - "[dynamic_bitset]", - uint16_t, - uint32_t, - uint64_t) +TEMPLATE_TEST_CASE("operator< operator<= operator> operator>=", "[dynamic_bitset]", uint16_t, uint32_t, uint64_t) { - SECTION("2 empty bitsets") - { - const sul::dynamic_bitset bitset1; - const sul::dynamic_bitset bitset2; - - REQUIRE_FALSE(bitset1 < bitset2); - REQUIRE_FALSE(bitset2 < bitset1); - REQUIRE(bitset1 <= bitset2); - REQUIRE(bitset2 <= bitset1); - - REQUIRE_FALSE(bitset1 > bitset2); - REQUIRE_FALSE(bitset2 > bitset1); - REQUIRE(bitset1 >= bitset2); - REQUIRE(bitset2 >= bitset1); - } - - SECTION("1 empty bitset") - { - const sul::dynamic_bitset bitset = - GENERATE(take(RANDOM_VECTORS_TO_TEST, randomDynamicBitset())); - const sul::dynamic_bitset empty_bitset; - CAPTURE(bitset); - - REQUIRE(empty_bitset < bitset); - REQUIRE_FALSE(bitset < empty_bitset); - REQUIRE(empty_bitset <= bitset); - REQUIRE_FALSE(bitset <= empty_bitset); - - REQUIRE_FALSE(empty_bitset > bitset); - REQUIRE(bitset > empty_bitset); - REQUIRE_FALSE(empty_bitset >= bitset); - REQUIRE(bitset >= empty_bitset); - } - - SECTION("non-empty bitsets") - { - const std::tuple values = GENERATE( - multitake(RANDOM_VECTORS_TO_TEST, - random(std::numeric_limits::min(), - std::numeric_limits::max()), - random(std::numeric_limits::min(), - std::numeric_limits::max()))); - const unsigned long long value1 = std::get<0>(values); - const unsigned long long value2 = std::get<1>(values) % value1; // value2 != value1 - const size_t bits_to_take = bits_number; - CAPTURE(value1, value2, bits_to_take); - - SECTION("same") - { - const sul::dynamic_bitset bitset1(bits_to_take, value1); - const sul::dynamic_bitset bitset2(bits_to_take, value1); - - REQUIRE_FALSE(bitset1 < bitset2); - REQUIRE_FALSE(bitset2 < bitset1); - REQUIRE(bitset1 <= bitset2); - REQUIRE(bitset2 <= bitset1); - - REQUIRE_FALSE(bitset1 > bitset2); - REQUIRE_FALSE(bitset2 > bitset1); - REQUIRE(bitset1 >= bitset2); - REQUIRE(bitset2 >= bitset1); - } - - SECTION("different size and same bits") - { - const sul::dynamic_bitset bitset1(bits_to_take, value1); - sul::dynamic_bitset bitset2(bits_to_take, value1); - const bool added_value = GENERATE(true, false); - CAPTURE(added_value); - bitset2.push_back(added_value); - - REQUIRE(bitset1 < bitset2); - REQUIRE_FALSE(bitset2 < bitset1); - REQUIRE(bitset1 <= bitset2); - REQUIRE_FALSE(bitset2 <= bitset1); - - REQUIRE_FALSE(bitset1 > bitset2); - REQUIRE(bitset2 > bitset1); - REQUIRE_FALSE(bitset1 >= bitset2); - REQUIRE(bitset2 >= bitset1); - } - - SECTION("same size and different bits") - { - const sul::dynamic_bitset bitset1(bits_to_take, value1); - const sul::dynamic_bitset bitset2(bits_to_take, value2); - if(value1 < value2) - { - REQUIRE(bitset1 < bitset2); - REQUIRE_FALSE(bitset2 < bitset1); - REQUIRE(bitset1 <= bitset2); - REQUIRE_FALSE(bitset2 <= bitset1); - - REQUIRE_FALSE(bitset1 > bitset2); - REQUIRE(bitset2 > bitset1); - REQUIRE_FALSE(bitset1 >= bitset2); - REQUIRE(bitset2 >= bitset1); - } - else - { - REQUIRE(bitset2 < bitset1); - REQUIRE_FALSE(bitset1 < bitset2); - REQUIRE(bitset2 <= bitset1); - REQUIRE_FALSE(bitset1 <= bitset2); - - REQUIRE_FALSE(bitset2 > bitset1); - REQUIRE(bitset1 > bitset2); - REQUIRE_FALSE(bitset2 >= bitset1); - REQUIRE(bitset1 >= bitset2); - } - } - - SECTION("different size and different bits") - { - SECTION("difference in common blocks") - { - sul::dynamic_bitset bitset1(bits_to_take, value1); - sul::dynamic_bitset bitset2(bits_to_take, value1); - - // make bitset1 < bitset2 - const size_t bit_pos = - GENERATE(take( - RANDOM_VARIATIONS_TO_TEST, - random(std::numeric_limits::min(), - std::numeric_limits::max()))) - % bitset1.size(); - CAPTURE(bit_pos); - if(bitset1[bit_pos]) - { - bitset1.reset(bit_pos); - } - else - { - bitset2.set(bit_pos); - } - - // add some 0 to a bitset to have a different size - const size_t bits_to_add = GENERATE( - take(RANDOM_VARIATIONS_TO_TEST, random(0, 2 * bits_number))); - const bool bitset_to_add = GENERATE(true, false); - CAPTURE(bits_to_add, bitset_to_add); - - sul::dynamic_bitset& longest_bitset = bitset_to_add ? bitset1 : bitset2; - for(size_t i = 0; i < bits_to_add; ++i) - { - longest_bitset.push_back(false); - } - - REQUIRE(bitset1 < bitset2); - REQUIRE_FALSE(bitset2 < bitset1); - REQUIRE(bitset1 <= bitset2); - REQUIRE_FALSE(bitset2 <= bitset1); - - REQUIRE_FALSE(bitset1 > bitset2); - REQUIRE(bitset2 > bitset1); - REQUIRE_FALSE(bitset1 >= bitset2); - REQUIRE(bitset2 >= bitset1); - } - - SECTION("difference in extra blocks") - { - sul::dynamic_bitset longest_bitset(bits_to_take, value1); - sul::dynamic_bitset bitset(bits_to_take, value1); - - sul::dynamic_bitset bits_to_add = - GENERATE(take(RANDOM_VARIATIONS_TO_TEST, - randomDynamicBitset(1, 2 * bits_number))); - CAPTURE(bits_to_add); - if(bits_to_add.none()) - { - bits_to_add.set(0); - } - for(size_t i = 0; i < bits_to_add.size(); ++i) - { - longest_bitset.push_back(longest_bitset[i]); - } - - REQUIRE(bitset < longest_bitset); - REQUIRE_FALSE(longest_bitset < bitset); - REQUIRE(bitset <= longest_bitset); - REQUIRE_FALSE(longest_bitset <= bitset); - - REQUIRE_FALSE(bitset > longest_bitset); - REQUIRE(longest_bitset > bitset); - REQUIRE_FALSE(bitset >= longest_bitset); - REQUIRE(longest_bitset >= bitset); - } - } - } + SECTION("2 empty bitsets") + { + const sul::dynamic_bitset bitset1; + const sul::dynamic_bitset bitset2; + + REQUIRE_FALSE(bitset1 < bitset2); + REQUIRE_FALSE(bitset2 < bitset1); + REQUIRE(bitset1 <= bitset2); + REQUIRE(bitset2 <= bitset1); + + REQUIRE_FALSE(bitset1 > bitset2); + REQUIRE_FALSE(bitset2 > bitset1); + REQUIRE(bitset1 >= bitset2); + REQUIRE(bitset2 >= bitset1); + } + + SECTION("1 empty bitset") + { + const sul::dynamic_bitset bitset = + GENERATE(take(RANDOM_VECTORS_TO_TEST, randomDynamicBitset())); + const sul::dynamic_bitset empty_bitset; + CAPTURE(bitset); + + REQUIRE(empty_bitset < bitset); + REQUIRE_FALSE(bitset < empty_bitset); + REQUIRE(empty_bitset <= bitset); + REQUIRE_FALSE(bitset <= empty_bitset); + + REQUIRE_FALSE(empty_bitset > bitset); + REQUIRE(bitset > empty_bitset); + REQUIRE_FALSE(empty_bitset >= bitset); + REQUIRE(bitset >= empty_bitset); + } + + SECTION("non-empty bitsets") + { + const std::tuple values = + GENERATE(multitake(RANDOM_VECTORS_TO_TEST, + random(std::numeric_limits::min(), + std::numeric_limits::max()), + random(std::numeric_limits::min(), + std::numeric_limits::max()))); + const unsigned long long value1 = std::get<0>(values); + const unsigned long long value2 = std::get<1>(values) % value1; // value2 != value1 + const size_t bits_to_take = bits_number; + CAPTURE(value1, value2, bits_to_take); + + SECTION("same") + { + const sul::dynamic_bitset bitset1(bits_to_take, value1); + const sul::dynamic_bitset bitset2(bits_to_take, value1); + + REQUIRE_FALSE(bitset1 < bitset2); + REQUIRE_FALSE(bitset2 < bitset1); + REQUIRE(bitset1 <= bitset2); + REQUIRE(bitset2 <= bitset1); + + REQUIRE_FALSE(bitset1 > bitset2); + REQUIRE_FALSE(bitset2 > bitset1); + REQUIRE(bitset1 >= bitset2); + REQUIRE(bitset2 >= bitset1); + } + + SECTION("different size and same bits") + { + const sul::dynamic_bitset bitset1(bits_to_take, value1); + sul::dynamic_bitset bitset2(bits_to_take, value1); + const bool added_value = GENERATE(true, false); + CAPTURE(added_value); + bitset2.push_back(added_value); + + REQUIRE(bitset1 < bitset2); + REQUIRE_FALSE(bitset2 < bitset1); + REQUIRE(bitset1 <= bitset2); + REQUIRE_FALSE(bitset2 <= bitset1); + + REQUIRE_FALSE(bitset1 > bitset2); + REQUIRE(bitset2 > bitset1); + REQUIRE_FALSE(bitset1 >= bitset2); + REQUIRE(bitset2 >= bitset1); + } + + SECTION("same size and different bits") + { + const sul::dynamic_bitset bitset1(bits_to_take, value1); + const sul::dynamic_bitset bitset2(bits_to_take, value2); + if(value1 < value2) + { + REQUIRE(bitset1 < bitset2); + REQUIRE_FALSE(bitset2 < bitset1); + REQUIRE(bitset1 <= bitset2); + REQUIRE_FALSE(bitset2 <= bitset1); + + REQUIRE_FALSE(bitset1 > bitset2); + REQUIRE(bitset2 > bitset1); + REQUIRE_FALSE(bitset1 >= bitset2); + REQUIRE(bitset2 >= bitset1); + } + else + { + REQUIRE(bitset2 < bitset1); + REQUIRE_FALSE(bitset1 < bitset2); + REQUIRE(bitset2 <= bitset1); + REQUIRE_FALSE(bitset1 <= bitset2); + + REQUIRE_FALSE(bitset2 > bitset1); + REQUIRE(bitset1 > bitset2); + REQUIRE_FALSE(bitset2 >= bitset1); + REQUIRE(bitset1 >= bitset2); + } + } + + SECTION("different size and different bits") + { + SECTION("difference in common blocks") + { + sul::dynamic_bitset bitset1(bits_to_take, value1); + sul::dynamic_bitset bitset2(bits_to_take, value1); + + // make bitset1 < bitset2 + const size_t bit_pos = + GENERATE(take(RANDOM_VARIATIONS_TO_TEST, + random(std::numeric_limits::min(), + std::numeric_limits::max()))) + % bitset1.size(); + CAPTURE(bit_pos); + if(bitset1[bit_pos]) + { + bitset1.reset(bit_pos); + } + else + { + bitset2.set(bit_pos); + } + + // add some 0 to a bitset to have a different size + const size_t bits_to_add = + GENERATE(take(RANDOM_VARIATIONS_TO_TEST, random(0, 2 * bits_number))); + const bool bitset_to_add = GENERATE(true, false); + CAPTURE(bits_to_add, bitset_to_add); + + sul::dynamic_bitset& longest_bitset = bitset_to_add ? bitset1 : bitset2; + for(size_t i = 0; i < bits_to_add; ++i) + { + longest_bitset.push_back(false); + } + + REQUIRE(bitset1 < bitset2); + REQUIRE_FALSE(bitset2 < bitset1); + REQUIRE(bitset1 <= bitset2); + REQUIRE_FALSE(bitset2 <= bitset1); + + REQUIRE_FALSE(bitset1 > bitset2); + REQUIRE(bitset2 > bitset1); + REQUIRE_FALSE(bitset1 >= bitset2); + REQUIRE(bitset2 >= bitset1); + } + + SECTION("difference in extra blocks") + { + sul::dynamic_bitset longest_bitset(bits_to_take, value1); + sul::dynamic_bitset bitset(bits_to_take, value1); + + sul::dynamic_bitset bits_to_add = GENERATE( + take(RANDOM_VARIATIONS_TO_TEST, randomDynamicBitset(1, 2 * bits_number))); + CAPTURE(bits_to_add); + if(bits_to_add.none()) + { + bits_to_add.set(0); + } + for(size_t i = 0; i < bits_to_add.size(); ++i) + { + longest_bitset.push_back(longest_bitset[i]); + } + + REQUIRE(bitset < longest_bitset); + REQUIRE_FALSE(longest_bitset < bitset); + REQUIRE(bitset <= longest_bitset); + REQUIRE_FALSE(longest_bitset <= bitset); + + REQUIRE_FALSE(bitset > longest_bitset); + REQUIRE(longest_bitset > bitset); + REQUIRE_FALSE(bitset >= longest_bitset); + REQUIRE(longest_bitset >= bitset); + } + } + } } TEMPLATE_TEST_CASE("ostream operator<<", "[dynamic_bitset]", uint16_t, uint32_t, uint64_t) { - sul::dynamic_bitset bitset = - GENERATE(take(RANDOM_VECTORS_TO_TEST, randomDynamicBitset())); - CAPTURE(bitset); - - std::stringstream sstream; - sstream << bitset; - std::string str = sstream.str(); - CAPTURE(str); - - REQUIRE(str.size() == bitset.size()); - for(size_t i = 0; i < bitset.size(); ++i) - { - CAPTURE(i); - if(bitset[bitset.size() - i - 1]) - { - REQUIRE(str[i] == '1'); - } - else - { - REQUIRE(str[i] == '0'); - } - } + sul::dynamic_bitset bitset = GENERATE(take(RANDOM_VECTORS_TO_TEST, randomDynamicBitset())); + CAPTURE(bitset); + + std::stringstream sstream; + sstream << bitset; + std::string str = sstream.str(); + CAPTURE(str); + + REQUIRE(str.size() == bitset.size()); + for(size_t i = 0; i < bitset.size(); ++i) + { + CAPTURE(i); + if(bitset[bitset.size() - i - 1]) + { + REQUIRE(str[i] == '1'); + } + else + { + REQUIRE(str[i] == '0'); + } + } } TEMPLATE_TEST_CASE("istream operator>>", "[dynamic_bitset]", uint16_t, uint32_t, uint64_t) { - SECTION("invalid stream") - { - std::stringstream sstream; - sul::dynamic_bitset bitset; - sstream >> bitset; - REQUIRE(bitset.empty()); - REQUIRE(check_consistency(bitset)); - } - - SECTION("valid stream") - { - SECTION("only valid characters") - { - std::string str = GENERATE(take(RANDOM_VECTORS_TO_TEST, randomBitsetString())); - CAPTURE(str); - - std::stringstream sstream; - sstream.str(str); - sul::dynamic_bitset bitset; - sstream >> bitset; - CAPTURE(bitset); - - REQUIRE(bitset.size() == str.size()); - for(size_t i = 0; i < str.size(); ++i) - { - CAPTURE(i); - if(str[str.size() - i - 1] == '1') - { - REQUIRE(bitset.test(i)); - } - else - { - REQUIRE_FALSE(bitset.test(i)); - } - } - REQUIRE(sstream.eof()); - REQUIRE(check_consistency(bitset)); - } - - SECTION("with invalid characters") - { - std::string str = GENERATE(take(RANDOM_VECTORS_TO_TEST, randomBitsetString())); - CAPTURE(str); - - std::stringstream sstream; - sstream << str; - sstream << 'E'; - sul::dynamic_bitset bitset; - sstream >> bitset; - CAPTURE(bitset); - - REQUIRE(bitset.size() == str.size()); - for(size_t i = 0; i < str.size(); ++i) - { - CAPTURE(i); - if(str[str.size() - i - 1] == '1') - { - REQUIRE(bitset.test(i)); - } - else - { - REQUIRE_FALSE(bitset.test(i)); - } - } - char E; - sstream >> E; - REQUIRE(E == 'E'); - sstream >> E; - REQUIRE(sstream.eof()); - REQUIRE(check_consistency(bitset)); - } - } + SECTION("invalid stream") + { + std::stringstream sstream; + sul::dynamic_bitset bitset; + sstream >> bitset; + REQUIRE(bitset.empty()); + REQUIRE(check_consistency(bitset)); + } + + SECTION("valid stream") + { + SECTION("only valid characters") + { + std::string str = GENERATE(take(RANDOM_VECTORS_TO_TEST, randomBitsetString())); + CAPTURE(str); + + std::stringstream sstream; + sstream.str(str); + sul::dynamic_bitset bitset; + sstream >> bitset; + CAPTURE(bitset); + + REQUIRE(bitset.size() == str.size()); + for(size_t i = 0; i < str.size(); ++i) + { + CAPTURE(i); + if(str[str.size() - i - 1] == '1') + { + REQUIRE(bitset.test(i)); + } + else + { + REQUIRE_FALSE(bitset.test(i)); + } + } + REQUIRE(sstream.eof()); + REQUIRE(check_consistency(bitset)); + } + + SECTION("with invalid characters") + { + std::string str = GENERATE(take(RANDOM_VECTORS_TO_TEST, randomBitsetString())); + CAPTURE(str); + + std::stringstream sstream; + sstream << str; + sstream << 'E'; + sul::dynamic_bitset bitset; + sstream >> bitset; + CAPTURE(bitset); + + REQUIRE(bitset.size() == str.size()); + for(size_t i = 0; i < str.size(); ++i) + { + CAPTURE(i); + if(str[str.size() - i - 1] == '1') + { + REQUIRE(bitset.test(i)); + } + else + { + REQUIRE_FALSE(bitset.test(i)); + } + } + char E; + sstream >> E; + REQUIRE(E == 'E'); + sstream >> E; + REQUIRE(sstream.eof()); + REQUIRE(check_consistency(bitset)); + } + } }