Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/dosbox-staging/dosbox-staging.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorkcgen <kcgen@users.noreply.github.com>2022-01-24 05:52:44 +0300
committerkcgen <1557255+kcgen@users.noreply.github.com>2022-02-02 01:32:14 +0300
commit6f764a9872c5a38a86099e2b87cd4cad2641f522 (patch)
treeb41950fa52c41df83772beb2c3e1e1c9e1309c80 /tests
parent1e50f8a058ba4aff6a57483f976fdbb8e0096379 (diff)
Add bit-operations helper functions
Bit operations can often be done in different ways: - one based bits? (not recommended, industy uses zero-based) - zero based bits? (recommended, but many unaware of this) - hex numbers? (common, but hard to read for multi-bits) - binary-literals? (gets massive and unreadable for larger bit depth: so then need to pick a different style leading to inconsistencies) - decimals? (confusion with counter and purpose) - on-the-fly conversion (1 << 4) (OK, but visually messy) this attempts to standardize these operations and also make the code more self-documenting. The functions are "const-correct", and all can be evaluated at compile-time when literals are used.
Diffstat (limited to 'tests')
-rw-r--r--tests/bitops_tests.cpp282
-rw-r--r--tests/meson.build1
-rw-r--r--tests/vs/tests.vcxproj3
-rw-r--r--tests/vs/tests.vcxproj.filters5
4 files changed, 289 insertions, 2 deletions
diff --git a/tests/bitops_tests.cpp b/tests/bitops_tests.cpp
new file mode 100644
index 000000000..b5a44d73a
--- /dev/null
+++ b/tests/bitops_tests.cpp
@@ -0,0 +1,282 @@
+/*
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * Copyright (C) 2021-2021 The DOSBox Staging Team
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "bitops.h"
+
+#include <gtest/gtest.h>
+
+namespace {
+
+TEST(bitops, enum_vals)
+{
+ // check against bit-shifts
+ EXPECT_FALSE(bit_0 == 0 << 0);
+ EXPECT_TRUE(bit_0 == 1 << 0); // this is why
+ EXPECT_FALSE(bit_0 == 1 << 1);
+
+ EXPECT_FALSE(bit_5 == 1 << 4);
+ EXPECT_TRUE(bit_5 == 1 << 5); // industry prefers
+ EXPECT_FALSE(bit_5 == 1 << 6);
+
+ EXPECT_FALSE(bit_12 == 1 << 11);
+ EXPECT_TRUE(bit_12 == 1 << 12); // zero-based bit names
+ EXPECT_FALSE(bit_12 == 1 << 13);
+
+ EXPECT_FALSE(bit_22 == 1 << 21);
+ EXPECT_TRUE(bit_22 == 1 << 22); // and not one-based
+ EXPECT_FALSE(bit_22 == 1 << 23);
+
+ EXPECT_FALSE(bit_31 == 1 << 30);
+ EXPECT_TRUE(bit_31 == 1 << 31);
+
+ // check against bit literals
+ EXPECT_TRUE(bit_0 == 0b1);
+ EXPECT_TRUE(bit_5 == 0b100000);
+ EXPECT_TRUE(bit_12 == 0b1000000000000);
+ EXPECT_TRUE(bit_22 == 0b10000000000000000000000);
+ EXPECT_TRUE(static_cast<uint32_t>(bit_14 | bit_22 | bit_31) ==
+ 0b10000000010000000100000000000000);
+
+ // check against magic numbers
+ EXPECT_TRUE(bit_0 == 1);
+ EXPECT_TRUE(bit_5 == 32);
+ EXPECT_TRUE(bit_12 == 4096);
+ EXPECT_TRUE(bit_22 == 4194304);
+ EXPECT_TRUE(static_cast<uint32_t>(bit_14 | bit_22 | bit_31) == 2151694336);
+
+ // check some combos
+ EXPECT_FALSE((bit_4 | bit_5) == 0b1'1000);
+ EXPECT_TRUE((bit_4 | bit_5) == 0b11'0000);
+ EXPECT_FALSE((bit_4 | bit_5) == 0b110'0000);
+}
+
+TEST(bitops, nominal_byte)
+{
+ const auto even_bits = bit_0 | bit_2 | bit_4 | bit_6;
+ const auto odd_bits = bit_1 | bit_3 | bit_5 | bit_7;
+
+ uint8_t reg = 0;
+ set_bits(reg, odd_bits);
+ EXPECT_EQ(reg, 0b10101010);
+
+ set_bits(reg, even_bits);
+ EXPECT_EQ(reg, 0b11111111);
+
+ EXPECT_TRUE(are_bits_set(reg, bit_0));
+ EXPECT_TRUE(are_bits_set(reg, bit_3));
+ EXPECT_TRUE(are_bits_set(reg, bit_7));
+ EXPECT_TRUE(are_bits_set(reg, even_bits));
+ EXPECT_TRUE(are_bits_set(reg, odd_bits));
+
+ EXPECT_FALSE(are_bits_cleared(reg, bit_0));
+ EXPECT_FALSE(are_bits_cleared(reg, bit_3));
+ EXPECT_FALSE(are_bits_cleared(reg, bit_7));
+ EXPECT_FALSE(are_bits_cleared(reg, even_bits));
+ EXPECT_FALSE(are_bits_cleared(reg, odd_bits));
+
+ clear_bits(reg, odd_bits); // odd-off, even-on
+ EXPECT_EQ(reg, even_bits);
+ EXPECT_TRUE(are_bits_set(reg, even_bits));
+ EXPECT_TRUE(are_bits_cleared(reg, odd_bits));
+
+ toggle_bits(reg, odd_bits); // both are on
+ EXPECT_TRUE(are_bits_set(reg, (odd_bits | even_bits)));
+ EXPECT_FALSE(are_bits_cleared(reg, (odd_bits | even_bits)));
+
+ toggle_bits(reg, even_bits); // odd-on, even-off
+ EXPECT_TRUE(are_bits_set(reg, odd_bits));
+ EXPECT_TRUE(are_bits_cleared(reg, even_bits));
+
+ toggle_bits(reg, even_bits | odd_bits); // odd-off, even-on
+ EXPECT_EQ(reg, even_bits);
+
+ // set all bits
+ set_all_bits(reg);
+ EXPECT_EQ(reg, 0b1111'1111);
+ EXPECT_TRUE(are_bits_set(reg, even_bits | odd_bits));
+ EXPECT_TRUE(are_any_bits_set(reg, even_bits | odd_bits));
+ EXPECT_FALSE(are_bits_cleared(reg, (odd_bits | even_bits)));
+
+ // toggle all bits
+ toggle_all_bits(reg);
+ EXPECT_EQ(reg, 0b0000'0000);
+ EXPECT_FALSE(are_bits_set(reg, even_bits | odd_bits));
+ EXPECT_FALSE(are_any_bits_set(reg, even_bits | odd_bits));
+ EXPECT_TRUE(are_bits_cleared(reg, (odd_bits | even_bits)));
+}
+
+TEST(bitops, nominal_word)
+{
+ const auto even_bits = bit_8 | bit_10 | bit_12 | bit_14;
+ const auto odd_bits = bit_9 | bit_11 | bit_13 | bit_15;
+
+ uint16_t reg = 0;
+ set_bits(reg, odd_bits);
+ EXPECT_EQ(reg, 0b10101010'00000000);
+
+ set_bits(reg, even_bits);
+ EXPECT_EQ(reg, 0b11111111'00000000);
+
+ EXPECT_FALSE(are_bits_cleared(reg, bit_8));
+ EXPECT_FALSE(are_bits_cleared(reg, bit_12));
+ EXPECT_FALSE(are_bits_cleared(reg, bit_15));
+ EXPECT_FALSE(are_bits_cleared(reg, even_bits));
+ EXPECT_FALSE(are_bits_cleared(reg, odd_bits));
+
+ clear_bits(reg, odd_bits); // odd-off, even-on
+ EXPECT_EQ(reg, even_bits);
+ EXPECT_TRUE(are_bits_set(reg, even_bits));
+ EXPECT_TRUE(are_any_bits_set(reg, even_bits | odd_bits));
+ EXPECT_TRUE(are_bits_cleared(reg, odd_bits));
+
+ toggle_bits(reg, odd_bits); // both are on
+ EXPECT_TRUE(are_bits_set(reg, (odd_bits | even_bits)));
+ EXPECT_FALSE(are_bits_cleared(reg, (odd_bits | even_bits)));
+
+ toggle_bits(reg, even_bits); // odd-on, even-off
+ EXPECT_TRUE(are_bits_set(reg, odd_bits));
+ EXPECT_TRUE(are_bits_cleared(reg, even_bits));
+
+ toggle_bits(reg, even_bits | odd_bits); // odd-off, even-on
+ EXPECT_EQ(reg, even_bits);
+
+ // set all bits
+ set_all_bits(reg);
+ EXPECT_EQ(reg, 0b11111111'11111111);
+ EXPECT_TRUE(are_bits_set(reg, even_bits | odd_bits));
+ EXPECT_TRUE(are_any_bits_set(reg, even_bits | odd_bits));
+ EXPECT_FALSE(are_bits_cleared(reg, (odd_bits | even_bits)));
+
+ // toggle all bits
+ toggle_all_bits(reg);
+ EXPECT_EQ(reg, 0b00000000'00000000);
+ EXPECT_FALSE(are_bits_set(reg, even_bits | odd_bits));
+ EXPECT_FALSE(are_any_bits_set(reg, even_bits | odd_bits));
+ EXPECT_TRUE(are_bits_cleared(reg, (odd_bits | even_bits)));
+}
+
+TEST(bitops, nominal_dword)
+{
+ const auto even_bits = bit_16 | bit_18 | bit_20 | bit_22 | bit_24 |
+ bit_26 | bit_28 | bit_30;
+ const auto odd_bits = bit_17 | bit_19 | bit_21 | bit_23 | bit_25 |
+ bit_27 | bit_29 | bit_31;
+
+ uint32_t reg = 0;
+
+ set_bits(reg, even_bits);
+ EXPECT_EQ(reg, 0b01010101'01010101'00000000'00000000);
+
+ set_bits(reg, odd_bits);
+ EXPECT_EQ(reg, 0b11111111'11111111'00000000'00000000);
+
+ EXPECT_FALSE(are_bits_cleared(reg, bit_16));
+ EXPECT_FALSE(are_bits_cleared(reg, bit_24));
+ EXPECT_FALSE(are_bits_cleared(reg, bit_31));
+ EXPECT_FALSE(are_bits_cleared(reg, even_bits));
+ EXPECT_FALSE(are_bits_cleared(reg, odd_bits));
+
+ clear_bits(reg, odd_bits); // odd-off, even-on
+ EXPECT_EQ(reg, even_bits);
+ EXPECT_TRUE(are_bits_set(reg, even_bits));
+ EXPECT_TRUE(are_bits_cleared(reg, odd_bits));
+
+ toggle_bits(reg, odd_bits); // both are on
+ EXPECT_TRUE(are_bits_set(reg, (odd_bits | even_bits)));
+ EXPECT_FALSE(are_bits_cleared(reg, (odd_bits | even_bits)));
+
+ toggle_bits(reg, even_bits); // odd-on, even-off
+ EXPECT_TRUE(are_bits_set(reg, odd_bits));
+ EXPECT_TRUE(are_bits_cleared(reg, even_bits));
+
+ toggle_bits(reg, even_bits | odd_bits); // odd-off, even-on
+ EXPECT_EQ(reg, even_bits);
+
+ // set all bits
+ set_all_bits(reg);
+ EXPECT_EQ(reg, 0b11111111'11111111'11111111'11111111);
+ EXPECT_TRUE(are_bits_set(reg, even_bits | odd_bits));
+ EXPECT_TRUE(are_any_bits_set(reg, even_bits | odd_bits));
+ EXPECT_FALSE(are_bits_cleared(reg, (odd_bits | even_bits)));
+
+ // toggle all bits
+ toggle_all_bits(reg);
+ EXPECT_EQ(reg, 0b00000000'00000000'00000000'00000000);
+ EXPECT_FALSE(are_bits_set(reg, even_bits | odd_bits));
+ EXPECT_FALSE(are_any_bits_set(reg, even_bits | odd_bits));
+ EXPECT_TRUE(are_bits_cleared(reg, (odd_bits | even_bits)));
+}
+
+TEST(bitops, bits_too_wide_for_byte)
+{
+ uint8_t reg = 0;
+ set_bits(reg, bit_7);
+ EXPECT_TRUE(are_bits_set(reg, bit_7));
+ EXPECT_DEBUG_DEATH({ set_bits(reg, bit_8); }, "");
+ EXPECT_DEBUG_DEATH({ are_bits_set(reg, bit_8); }, "");
+
+ clear_bits(reg, bit_7);
+ EXPECT_TRUE(are_bits_cleared(reg, bit_7));
+ EXPECT_DEBUG_DEATH({ clear_bits(reg, bit_8); }, "");
+ EXPECT_DEBUG_DEATH({ are_bits_cleared(reg, bit_8); }, "");
+
+ toggle_bits(reg, bit_7);
+ EXPECT_TRUE(are_bits_set(reg, bit_7));
+ EXPECT_DEBUG_DEATH({ toggle_bits(reg, bit_8); }, "");
+}
+
+TEST(bitops, bits_too_wide_for_word)
+{
+ uint16_t reg = 0;
+ set_bits(reg, bit_8);
+ EXPECT_TRUE(are_bits_set(reg, bit_8));
+ EXPECT_DEBUG_DEATH({ set_bits(reg, bit_16); }, "");
+ EXPECT_DEBUG_DEATH({ are_bits_set(reg, bit_16); }, "");
+
+ clear_bits(reg, bit_8);
+ EXPECT_TRUE(are_bits_cleared(reg, bit_8));
+ EXPECT_DEBUG_DEATH({ clear_bits(reg, bit_16); }, "");
+ EXPECT_DEBUG_DEATH({ are_bits_cleared(reg, bit_16); }, "");
+
+ toggle_bits(reg, bit_8);
+ EXPECT_TRUE(are_bits_set(reg, bit_8));
+ EXPECT_DEBUG_DEATH({ toggle_bits(reg, bit_16); }, "");
+}
+
+TEST(bitops, bits_not_too_wide_for_dword)
+{
+ uint32_t reg = 0;
+ set_bits(reg, bit_8);
+ set_bits(reg, bit_24);
+ set_bits(reg, bit_31);
+ EXPECT_TRUE(are_bits_set(reg, (bit_8 | bit_24 | bit_31)));
+
+ clear_bits(reg, bit_8);
+ clear_bits(reg, bit_24);
+ clear_bits(reg, bit_31);
+ EXPECT_TRUE(are_bits_cleared(reg, (bit_8 | bit_24 | bit_31)));
+
+ toggle_bits(reg, bit_8);
+ toggle_bits(reg, bit_24);
+ toggle_bits(reg, bit_31);
+ EXPECT_TRUE(are_bits_set(reg, (bit_8 | bit_24 | bit_31)));
+}
+
+} // namespace
diff --git a/tests/meson.build b/tests/meson.build
index 2dfea0407..287d04257 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -59,6 +59,7 @@ test('gtest fs_utils', fs_utils,
# other unit tests
unit_tests = [
+ {'name' : 'bitops', 'deps' : []},
{'name' : 'iohandler_containers', 'deps' : [libmisc_dep]},
{'name' : 'rwqueue', 'deps' : [libmisc_dep]},
{'name' : 'soft_limiter', 'deps' : [atomic_dep, libmisc_dep]},
diff --git a/tests/vs/tests.vcxproj b/tests/vs/tests.vcxproj
index 3fca85bb9..2f2f9866b 100644
--- a/tests/vs/tests.vcxproj
+++ b/tests/vs/tests.vcxproj
@@ -232,6 +232,7 @@ $(TargetPath)
<ClCompile Include="..\..\src\libs\loguru\loguru.cpp" />
<ClCompile Include="..\..\src\libs\whereami\whereami.c" />
<ClCompile Include="..\ansi_code_markup_tests.cpp" />
+ <ClCompile Include="..\bitops_tests.cpp" />
<ClCompile Include="..\fs_utils_tests.cpp" />
<ClCompile Include="..\iohandler_containers_tests.cpp" />
<ClCompile Include="..\rwqueue_tests.cpp" />
@@ -247,4 +248,4 @@ $(TargetPath)
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
-</Project> \ No newline at end of file
+</Project>
diff --git a/tests/vs/tests.vcxproj.filters b/tests/vs/tests.vcxproj.filters
index 4dcfe1b46..d0dab98d1 100644
--- a/tests/vs/tests.vcxproj.filters
+++ b/tests/vs/tests.vcxproj.filters
@@ -18,6 +18,9 @@
</Filter>
</ItemGroup>
<ItemGroup>
+ <ClCompile Include="..\bitops_tests.cpp">
+ <Filter>tests</Filter>
+ </ClCompile>
<ClCompile Include="..\fs_utils_tests.cpp">
<Filter>tests</Filter>
</ClCompile>
@@ -82,4 +85,4 @@
<ItemGroup>
<None Include="..\meson.build" />
</ItemGroup>
-</Project> \ No newline at end of file
+</Project>