Bitset.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include <AzCore/std/containers/bitset.h>
  9. #include <AzCore/UnitTest/TestTypes.h>
  10. #include <type_traits>
  11. #include <bitset> // Used for comparison tests.
  12. #include "UserTypes.h"
  13. namespace UnitTest
  14. {
  15. // Or the bitset can be tested without respect to the unsigned long, but benefit from having multiple test cases exercised through the parameterized test
  16. class BitsetUnsignedLongTests
  17. : public ::testing::WithParamInterface <unsigned long>
  18. , public UnitTest::LeakDetectionFixture
  19. {
  20. protected:
  21. void SetUp() override
  22. {
  23. m_unsignedLong = static_cast<AZ::u32>(GetParam());
  24. m_bitset = AZStd::bitset<32>(m_unsignedLong);
  25. }
  26. // The ground truth
  27. AZ::u32 m_unsignedLong;
  28. // The unit under test
  29. AZStd::bitset<32> m_bitset;
  30. };
  31. TEST_P(BitsetUnsignedLongTests, UnsignedLongConstructor_MatchesUnsignedLong)
  32. {
  33. // Bit by bit comparison
  34. unsigned long currentBit = 1;
  35. for (size_t i = 0; i < m_bitset.size(); ++i)
  36. {
  37. // Expect each bit of the bitset which was constructed during the test fixture SetUp to match the bits in the unsigned long
  38. EXPECT_EQ(m_bitset[i], (m_unsignedLong & currentBit) != 0) << "The bit at index " << i << " did not match the corresponding bit in the unsigned long";
  39. currentBit <<= 1;
  40. }
  41. }
  42. TEST_P(BitsetUnsignedLongTests, ToUlong_MatchesUnsignedLong)
  43. {
  44. EXPECT_EQ(m_bitset.to_ulong(), m_unsignedLong);
  45. }
  46. TEST_P(BitsetUnsignedLongTests, BitwiseNot_MatchesUnsignedLong)
  47. {
  48. m_bitset = ~m_bitset;
  49. EXPECT_EQ(m_bitset.to_ulong(), ~m_unsignedLong);
  50. }
  51. TEST_P(BitsetUnsignedLongTests, Reset_EachBitReset_EachBitIsFalse)
  52. {
  53. // Iterate over the entire bitset and reset each bit individually
  54. for (size_t i = 0; i < m_bitset.size(); ++i)
  55. {
  56. m_bitset.reset(i);
  57. EXPECT_FALSE(m_bitset[i]) << "The bit at index " << i << " was not reset to 0";
  58. }
  59. }
  60. TEST_P(BitsetUnsignedLongTests, Flip_EachBitFlipped_MatchesFlippedUnsignedLong)
  61. {
  62. // Iterate over the entire bitset and flip each bit individually
  63. for (size_t i = 0; i < m_bitset.size(); ++i)
  64. {
  65. m_bitset.flip(i);
  66. }
  67. // Compare to the flipped unsigned long
  68. EXPECT_EQ(m_bitset.to_ulong(), ~m_unsignedLong);
  69. }
  70. TEST_P(BitsetUnsignedLongTests, Reference_EachBitFlipped_MatchesFlippedUnsignedLong)
  71. {
  72. // Iterate over the entire bitset and flip each bit individually via a bitset reference
  73. for (size_t i = 0; i < m_bitset.size(); ++i)
  74. {
  75. AZStd::bitset<32>::reference ref = m_bitset[i];
  76. ref.flip();
  77. }
  78. // Compare to the flipped unsigned long
  79. EXPECT_EQ(m_bitset.to_ulong(), ~m_unsignedLong);
  80. }
  81. TEST_P(BitsetUnsignedLongTests, Reference_BitwiseNotForEachBit_EachBitDoesNotEqualOriginalValue)
  82. {
  83. for (size_t i = 0; i < m_bitset.size(); ++i)
  84. {
  85. // Get a reference to a bit
  86. AZStd::bitset<32>::reference ref = m_bitset[i];
  87. // Compare the reference to the original value of the bit
  88. EXPECT_NE(m_bitset[i], ~ref) << "The ~ operator did not negate the reference to the bitset at index " << i << ".";
  89. }
  90. }
  91. // This fixture initializes two bitsets from two unsigned longs
  92. // Bitwise operations can be performed between the bitsets, then compared to the same bitwise operations preformed between the unsigned longs
  93. class BitsetUnsignedLongPairTests
  94. : public ::testing::WithParamInterface < AZStd::pair<unsigned long, unsigned long> >
  95. , public UnitTest::LeakDetectionFixture
  96. {
  97. protected:
  98. void SetUp() override
  99. {
  100. m_unsignedLong1 = GetParam().first;
  101. m_bitset1 = AZStd::bitset<32>(m_unsignedLong1);
  102. m_unsignedLong2 = GetParam().second;
  103. m_bitset2 = AZStd::bitset<32>(m_unsignedLong2);
  104. }
  105. unsigned long m_unsignedLong1;
  106. unsigned long m_unsignedLong2;
  107. AZStd::bitset<32> m_bitset1;
  108. AZStd::bitset<32> m_bitset2;
  109. };
  110. TEST_P(BitsetUnsignedLongPairTests, BitwiseANDOperator_MatchesUnsignedLongAND)
  111. {
  112. EXPECT_EQ((m_bitset1 & m_bitset2).to_ulong(), m_unsignedLong1 & m_unsignedLong2);
  113. }
  114. TEST_P(BitsetUnsignedLongPairTests, BitwiseOROperator_MatchesUnsignedLongOR)
  115. {
  116. EXPECT_EQ((m_bitset1 | m_bitset2).to_ulong(), m_unsignedLong1 | m_unsignedLong2);
  117. }
  118. TEST_P(BitsetUnsignedLongPairTests, BitwiseXOROperator_MatchesUnsignedLongXOR)
  119. {
  120. EXPECT_EQ((m_bitset1 ^ m_bitset2).to_ulong(), m_unsignedLong1 ^ m_unsignedLong2);
  121. }
  122. TEST_P(BitsetUnsignedLongPairTests, BitwiseANDAssignmentOperator_MatchesUnsignedLongANDAssignment)
  123. {
  124. m_bitset1 &= m_bitset2;
  125. m_unsignedLong1 &= m_unsignedLong2;
  126. EXPECT_EQ(m_bitset1.to_ulong(), m_unsignedLong1);
  127. }
  128. TEST_P(BitsetUnsignedLongPairTests, BitwiseORAssignmentOperator_MatchesUnsignedLongORAssignment)
  129. {
  130. m_bitset1 |= m_bitset2;
  131. m_unsignedLong1 |= m_unsignedLong2;
  132. EXPECT_EQ(m_bitset1.to_ulong(), m_unsignedLong1);
  133. }
  134. TEST_P(BitsetUnsignedLongPairTests, BitwiseXORAssignmentOperator_MatchesUnsignedLongXORAssignment)
  135. {
  136. m_bitset1 ^= m_bitset2;
  137. m_unsignedLong1 ^= m_unsignedLong2;
  138. EXPECT_EQ(m_bitset1.to_ulong(), m_unsignedLong1);
  139. }
  140. TEST_P(BitsetUnsignedLongPairTests, EqualOperator_ComparedToOtherBitset_MatchesUnsignedLongComparison)
  141. {
  142. // The == comparison between the bitsets should have the same result as the == comparison between the unsigned longs
  143. EXPECT_EQ(m_bitset1 == m_bitset2, m_unsignedLong1 == m_unsignedLong2);
  144. }
  145. TEST_P(BitsetUnsignedLongPairTests, NotEqualOperator_ComparedToOtherBitset_MatchesUnsignedLongComparison)
  146. {
  147. // The != comparison between the bitsets should have the same result as the != comparison between the unsigned longs
  148. EXPECT_EQ(m_bitset1 != m_bitset2, m_unsignedLong1 != m_unsignedLong2);
  149. }
  150. TEST_P(BitsetUnsignedLongPairTests, CopyConstructor_CopyOtherBitset_EqualsOriginal)
  151. {
  152. m_bitset2 = m_bitset1;
  153. EXPECT_EQ(m_bitset1, m_bitset2);
  154. }
  155. TEST_P(BitsetUnsignedLongPairTests, ReferenceAssignmentOperator_AssignBoolToReferenceForEachBit_ReferencedBitsetMatchesOriginal)
  156. {
  157. // Iterate over the entire m_bitset1 and assign its values to m_bitset2 bit by bit
  158. for (size_t i = 0; i < m_bitset1.size(); ++i)
  159. {
  160. // Assign a bool value to the reference
  161. bool bitValue = m_bitset1[i];
  162. AZStd::bitset<32>::reference bitset2Ref = m_bitset2[i];
  163. bitset2Ref = bitValue;
  164. EXPECT_EQ(m_bitset1[i], m_bitset2[i]) << "The value of the bit at index " << i << " from m_bitset1 was not assigned to the bit at index " << i << " of m_bitset2.";
  165. }
  166. EXPECT_EQ(m_bitset1, m_bitset2);
  167. }
  168. TEST_P(BitsetUnsignedLongPairTests, ReferenceAssignmentOperator_AssignReferenceToReferenceForEachBit_ReferencedBitsetMatchesOriginal)
  169. {
  170. // Iterate over the entire m_bitset1 and assign its values to m_bitset2 bit by bit
  171. for (size_t i = 0; i < m_bitset1.size(); ++i)
  172. {
  173. // Assign a bitset reference value to the reference
  174. AZStd::bitset<32>::reference bitset1Ref = m_bitset1[i];
  175. AZStd::bitset<32>::reference bitset2Ref = m_bitset2[i];
  176. bitset2Ref = bitset1Ref;
  177. EXPECT_EQ(m_bitset1[i], m_bitset2[i]) << "The value of the bit at index " << i << " from m_bitset1 was not assigned to the bit at index " << i << " of m_bitset2.";
  178. }
  179. EXPECT_EQ(m_bitset1, m_bitset2);
  180. }
  181. // This class initializes an AZStd::bitset and an std::bitset with the same value to validate that the behavior of AZStd::bitset matches the behavior of std::bitset
  182. // It should only be used to test functions where we want AZStd::bitset to conform to the behavior of std::bitset
  183. // It is useful for testing functions where operations on the bitset behave differently than the same operations on an unsigned long,
  184. // such as shifting bits beyond the length of the bitset
  185. class BitsetStdComparisonTests
  186. : public ::testing::WithParamInterface <unsigned long>
  187. , public UnitTest::LeakDetectionFixture
  188. {
  189. protected:
  190. void SetUp() override
  191. {
  192. // Initialize the bitsets from an unsigned long
  193. m_stdBitset = std::bitset<32>(GetParam());
  194. m_bitset = AZStd::bitset<32>(GetParam());
  195. }
  196. // The ground truth for the unit test
  197. std::bitset<32> m_stdBitset;
  198. // The unit under test
  199. AZStd::bitset<32> m_bitset;
  200. // An array of values to use when shifting bits
  201. AZStd::vector<AZStd::size_t> m_shiftValues = { 0,1,2,3,5,8,13,21,44 };
  202. };
  203. TEST_P(BitsetStdComparisonTests, RightShift_MatchesStd)
  204. {
  205. for (AZStd::size_t value : m_shiftValues)
  206. {
  207. EXPECT_EQ((m_bitset >> value).to_ulong(), (m_stdBitset >> value).to_ulong()) << "Right shift by " << value << " bits did not match std::bitset";
  208. }
  209. }
  210. TEST_P(BitsetStdComparisonTests, RightShiftAssignment_MatchesStd)
  211. {
  212. for (AZStd::size_t value : m_shiftValues)
  213. {
  214. m_bitset >>= value;
  215. m_stdBitset >>= value;
  216. EXPECT_EQ(m_bitset.to_ulong(), m_stdBitset.to_ulong()) << "Right shift assignment by " << value << " bits did not match std::bitset.";
  217. }
  218. }
  219. TEST_P(BitsetStdComparisonTests, LeftShift_MatchesStd)
  220. {
  221. for (AZStd::size_t value : m_shiftValues)
  222. {
  223. EXPECT_EQ((m_bitset << value).to_ulong(), (m_stdBitset << value).to_ulong()) << "Left shift by " << value << " bits did not match std::bitset";
  224. }
  225. }
  226. TEST_P(BitsetStdComparisonTests, LeftShiftAssignment_MatchesStd)
  227. {
  228. for (AZStd::size_t value : m_shiftValues)
  229. {
  230. m_bitset <<= value;
  231. m_stdBitset <<= value;
  232. EXPECT_EQ(m_bitset.to_ulong(), m_stdBitset.to_ulong()) << "Left shift assignment by " << value << " bits did not match std::bitset.";
  233. }
  234. }
  235. TEST_P(BitsetStdComparisonTests, ToString_MatchesStd)
  236. {
  237. AZStd::string bitsetString = m_bitset.to_string<char>();
  238. std::string stdBitsetString = m_stdBitset.to_string<char>();
  239. EXPECT_TRUE(azstricmp(bitsetString.c_str(), stdBitsetString.c_str()) == 0) << "Bitset string '" << bitsetString.c_str() << "' does not match expected output '" << stdBitsetString << "'";
  240. }
  241. // Helper to generate a set of n bitsets that can be re-used to generate either n test cases or nxn test cases
  242. std::vector<unsigned long> GenerateBitsetTestCases()
  243. {
  244. std::vector<unsigned long> testCases;
  245. testCases.push_back(0b0000'0000'0000'0000'0000'0000'0000'0000);
  246. testCases.push_back(0b1111'1111'1111'1111'1111'1111'1111'1111);
  247. testCases.push_back(0b1010'1010'1010'1010'1010'1010'1010'1010);
  248. testCases.push_back(0b0101'0101'0101'0101'0101'0101'0101'0101);
  249. testCases.push_back(0b0000'0000'0000'0000'1111'1111'1111'1111);
  250. testCases.push_back(0b1111'1111'1111'1111'0000'0000'0000'0000);
  251. // Asymmetrical test cases
  252. testCases.push_back(0b1100'1010'1000'1000'0011'1101'0100'1100);
  253. testCases.push_back(0b0111'1100'1000'1001'1000'0001'1001'1001);
  254. return testCases;
  255. };
  256. std::vector<unsigned long> GenerateBitsetUnsignedLongTestCases()
  257. {
  258. return GenerateBitsetTestCases();
  259. }
  260. std::vector<AZStd::pair<unsigned long, unsigned long>> GenerateBitsetUnsignedLongPairTestCases()
  261. {
  262. std::vector<AZStd::pair<unsigned long, unsigned long>> testCasePairs;
  263. std::vector<unsigned long> testCases = GenerateBitsetTestCases();
  264. for (unsigned long value1 : testCases)
  265. {
  266. for (unsigned long value2 : testCases)
  267. {
  268. testCasePairs.emplace_back(value1, value2);
  269. }
  270. }
  271. return testCasePairs;
  272. }
  273. std::string GenerateBitsetUnsignedLongTestCaseName(const ::testing::TestParamInfo<unsigned long>& info)
  274. {
  275. std::bitset<32> stdBitset(info.param);
  276. return stdBitset.to_string();
  277. }
  278. std::string GenerateBitsetUnsignedLongPairTestCaseName(const ::testing::TestParamInfo<AZStd::pair<unsigned long, unsigned long>>& info)
  279. {
  280. // Output a string in the style of 0000x1111 where 0000 is the first bitset and 1111 is the second bitset
  281. std::bitset<32> bitset1(info.param.first);
  282. std::bitset<32> bitset2(info.param.second);
  283. return bitset1.to_string() + 'x' + bitset2.to_string();
  284. }
  285. INSTANTIATE_TEST_SUITE_P(Bitset, BitsetUnsignedLongTests, ::testing::ValuesIn(GenerateBitsetUnsignedLongTestCases()), GenerateBitsetUnsignedLongTestCaseName);
  286. INSTANTIATE_TEST_SUITE_P(Bitset, BitsetUnsignedLongPairTests, ::testing::ValuesIn(GenerateBitsetUnsignedLongPairTestCases()), GenerateBitsetUnsignedLongPairTestCaseName);
  287. INSTANTIATE_TEST_SUITE_P(Bitset, BitsetStdComparisonTests, ::testing::ValuesIn(GenerateBitsetUnsignedLongTestCases()), GenerateBitsetUnsignedLongTestCaseName);
  288. class BitsetTests
  289. : public LeakDetectionFixture
  290. {
  291. };
  292. TEST_F(BitsetTests, DefaultConstructor_IsZero)
  293. {
  294. AZStd::bitset<8> bitset;
  295. ASSERT_EQ(bitset.to_ullong(), 0);
  296. }
  297. TEST_F(BitsetTests, Constructor64Bits_MatchesInput)
  298. {
  299. constexpr AZ::u64 initValue = std::numeric_limits<AZ::u64>::max();
  300. AZStd::bitset<64> bitset(initValue);
  301. ASSERT_EQ(bitset.to_ullong(), initValue);
  302. }
  303. TEST_F(BitsetTests, Constructor64BitsInto32Bits_MatchesLeastSignificant32Bits)
  304. {
  305. constexpr AZ::u64 initValue = std::numeric_limits<AZ::u64>::max();
  306. AZStd::bitset<32> bitset(initValue);
  307. constexpr AZ::u64 expectedValue(initValue & static_cast<AZ::u32>(-1));
  308. ASSERT_EQ(bitset.to_ullong(), expectedValue);
  309. }
  310. TEST_F(BitsetTests, Constructor32BitsInto64Bits_ZeroPadRemaining)
  311. {
  312. constexpr AZ::u32 initValue = std::numeric_limits<AZ::u32>::max();
  313. AZStd::bitset<64> bitset(initValue);
  314. constexpr AZ::u64 expectedValue = static_cast<AZ::u64>(initValue);;
  315. ASSERT_EQ(bitset.to_ullong(), expectedValue);
  316. }
  317. TEST_F(BitsetTests, GeneralTesting)
  318. {
  319. // BitsetTest-Begin
  320. typedef AZStd::bitset<25> bitset25_type;
  321. bitset25_type bs;
  322. AZ_TEST_ASSERT(bs.count() == 0);
  323. bitset25_type bs1((unsigned long)5);
  324. AZ_TEST_ASSERT(bs1.count() == 2);
  325. AZ_TEST_ASSERT(bs1[0] && bs1[2]);
  326. AZStd::string str("10110");
  327. bitset25_type bs2(str, 0, str.length());
  328. AZ_TEST_ASSERT(bs2.count() == 3);
  329. AZ_TEST_ASSERT(bs2[1] && bs2[2] && bs2[4]);
  330. bitset25_type::reference bit0 = bs2[0], bit1 = bs2[1];
  331. AZ_TEST_ASSERT(bit0 == false);
  332. AZ_TEST_ASSERT(bit1 == true);
  333. bs &= bs1;
  334. AZ_TEST_ASSERT(bs.count() == 0);
  335. bs |= bs1;
  336. AZ_TEST_ASSERT(bs.count() == 2);
  337. AZ_TEST_ASSERT(bs[0] && bs[2]);
  338. bs ^= bs2;
  339. AZ_TEST_ASSERT(bs.count() == 3);
  340. AZ_TEST_ASSERT(bs[0] && bs[1] && bs[4]);
  341. bs <<= 4;
  342. AZ_TEST_ASSERT(bs.count() == 3);
  343. AZ_TEST_ASSERT(bs[4] && bs[5] && bs[8]);
  344. bs >>= 3;
  345. AZ_TEST_ASSERT(bs.count() == 3);
  346. AZ_TEST_ASSERT(bs[1] && bs[2] && bs[5]);
  347. bs.set(3);
  348. AZ_TEST_ASSERT(bs.count() == 4);
  349. AZ_TEST_ASSERT(bs[1] && bs[2] && bs[3] && bs[5]);
  350. bs.set(1, false);
  351. AZ_TEST_ASSERT(bs.count() == 3);
  352. AZ_TEST_ASSERT(!bs[1] && bs[2] && bs[3] && bs[5]);
  353. bs.set();
  354. AZ_TEST_ASSERT(bs.count() == 25);
  355. bs.reset();
  356. AZ_TEST_ASSERT(bs.count() == 0);
  357. bs.set(0);
  358. bs.set(1);
  359. AZ_TEST_ASSERT(bs.count() == 2);
  360. bs.flip();
  361. AZ_TEST_ASSERT(bs.count() == 23);
  362. bs.flip(0);
  363. AZ_TEST_ASSERT(bs.count() == 24);
  364. str = bs.to_string<char>();
  365. AZ_TEST_ASSERT(str.length() == 25);
  366. AZ_TEST_ASSERT(bs != bs1);
  367. bs2 = bs;
  368. AZ_TEST_ASSERT(bs == bs2);
  369. bs1.reset();
  370. AZ_TEST_ASSERT(bs.any());
  371. AZ_TEST_ASSERT(!bs1.any());
  372. AZ_TEST_ASSERT(!bs.none());
  373. AZ_TEST_ASSERT(bs1.none());
  374. bs1 = bs >> 1;
  375. AZ_TEST_ASSERT(bs1.count() == 23);
  376. bs1 = bs << 2;
  377. AZ_TEST_ASSERT(bs1.count() == 22);
  378. // extensions
  379. bitset25_type bs3(AZStd::string("10110"));
  380. AZ_TEST_ASSERT(bs3.num_words() == 1); // check number of words
  381. bitset25_type::word_t tempWord = *bs3.data(); // access the bits data
  382. AZ_TEST_ASSERT((tempWord & 0x16) == 0x16); // check values
  383. bitset25_type bs4;
  384. *bs4.data() = tempWord; // modify the data directly
  385. AZ_TEST_ASSERT(bs3 == bs4);
  386. }
  387. } // end namespace UnitTest