diff --git a/CMakeLists.txt b/CMakeLists.txt index 975f545..1487094 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.1) set(CMAKE_CXX_STANDARD 14) set(CMAKE_CXX_STANDARD_REQUIRED on) -include_directories(SYSTEM submodules/gsl) +include_directories(SYSTEM submodules/gsl/include) add_executable(test_basic test.cpp) add_executable(test_graph test_graph.cpp) @@ -12,5 +12,5 @@ enable_testing() add_test(test_basic ${CMAKE_BINARY_DIR}/test_basic -s) -# FIXME: Fix graph tests which fail with an assertion error on macOS. +# FIXME: Fix graph tests which fail with an assertion error on macOS. # add_test(test_graph ${CMAKE_BINARY_DIR}/test_graph -s) diff --git a/bitflags.h b/bitflags.h index f2a0c31..817cc40 100644 --- a/bitflags.h +++ b/bitflags.h @@ -36,14 +36,16 @@ namespace gcpp { //---------------------------------------------------------------------------- class bitflags { + public: using unit = unsigned int; static_assert(std::is_unsigned::value, "unit must be an unsigned integral type."); + static constexpr auto bits_per_unit = static_cast(sizeof(unit) * CHAR_BIT); + + private: std::unique_ptr bits; const int size; - static constexpr auto bits_per_unit = static_cast(sizeof(unit) * CHAR_BIT); - // Return a unit with all bits set if "set" is true, or all bits cleared otherwise. // static constexpr unit all_bits(bool set) noexcept { @@ -96,9 +98,12 @@ namespace gcpp { // Test whether all bits are false // bool all_false() const noexcept { - auto all_false = [](unit u) { return u == unit(0); }; - return std::all_of(bits.get(), bits.get() + unit_count(size) - 1, all_false) - && all_false(*(bits.get() + unit_count(size) - 1) & (bit_mask(size) - 1)); + auto const all_false = [](unit const u) { return u == unit(0); }; + if (!std::all_of(bits.get(), bits.get() + unit_count(size) - 1, all_false)) { + return false; + } + auto const mask = size % bits_per_unit == 0 ? unit(0) : bit_mask(size); + return all_false(*(bits.get() + unit_count(size) - 1) & (mask - 1)); } // Set flag value at position diff --git a/submodules/gsl b/submodules/gsl index 348a859..8b320e3 160000 --- a/submodules/gsl +++ b/submodules/gsl @@ -1 +1 @@ -Subproject commit 348a8595470b2ae7716a99ccacb8189821efb566 +Subproject commit 8b320e3f5d016f953e55dfc7ec8694c1349d3fe4 diff --git a/test.cpp b/test.cpp index 1d8e85f..ae071ae 100644 --- a/test.cpp +++ b/test.cpp @@ -396,7 +396,6 @@ void test_deferred_array() { } - void test_bitflags() { const int N = 100; // picked so that we have 3 x 32-bit units + 1 partial unit, // so we can exercise the boundary and internal unit cases @@ -404,7 +403,7 @@ void test_bitflags() { // Test that we can correctly set any bit range [i,j) for (auto i = 0; i < N; ++i) { for (auto j = i; j < N; ++j) { - bitflags flags(100, false); + bitflags flags(N, false); flags.set(i, j, true); for (auto test = 0; test < N; ++test) { assert(flags.get(test) == (i <= test && test < j)); @@ -414,7 +413,7 @@ void test_bitflags() { // Test that we can find a true bit set anywhere with any range for (auto set = 0; set < N; ++set) { - bitflags flags(100, false); + bitflags flags(N, false); flags.set(set, true); for (auto i = 0; i <= set; ++i) { for (auto j = i; j < N; ++j) { @@ -425,7 +424,7 @@ void test_bitflags() { // Test that we can find a false bit set anywhere with any range for (auto set = 0; set < N; ++set) { - bitflags flags(100, true); + bitflags flags(N, true); flags.set(set, false); for (auto i = 0; i <= set; ++i) { for (auto j = i; j < N; ++j) { @@ -434,13 +433,22 @@ void test_bitflags() { } } + { + // Regression test for #23: + // Test that all_false observes the bits in the last unit + bitflags flags(bitflags::bits_per_unit, false); + assert(flags.all_false()); + flags.set(bitflags::bits_per_unit - 1, true); + assert(!flags.all_false()); + } + //flags.debug_print(); } int main() { //test_page(); - //test_bitflags(); + test_bitflags(); //test_deferred_heap(); //time_deferred_heap(); @@ -457,7 +465,5 @@ int main() { //heap.collect(); //heap.debug_print(); - - return 0; }