SparseVectorTests.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  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/UnitTest/TestTypes.h>
  9. #include <Atom/Feature/Utils/SparseVector.h>
  10. #include <Atom/Feature/Utils/MultiSparseVector.h>
  11. namespace UnitTest
  12. {
  13. using namespace AZ;
  14. using namespace AZ::Render;
  15. class SparseVectorTests
  16. : public UnitTest::LeakDetectionFixture
  17. {
  18. };
  19. struct TestData
  20. {
  21. static constexpr int DefaultValueA = 100;
  22. static constexpr float DefaultValueB = 123.45f;
  23. static constexpr bool DefaultValueC = true;
  24. int a = DefaultValueA;
  25. float b = DefaultValueB;
  26. bool c = DefaultValueC;
  27. };
  28. struct TestDataWithDestructor
  29. {
  30. bool m_destroyed = false;
  31. size_t m_value = 100;
  32. ~TestDataWithDestructor()
  33. {
  34. EXPECT_FALSE(m_destroyed);
  35. m_destroyed = true;
  36. }
  37. };
  38. TEST_F(SparseVectorTests, SparseVectorCreate)
  39. {
  40. // Simple test to make sure we can create a SparseVector and it initializes with no values.
  41. SparseVector<TestData> container;
  42. EXPECT_EQ(0, container.GetSize());
  43. container.Clear();
  44. EXPECT_EQ(0, container.GetSize());
  45. }
  46. TEST_F(SparseVectorTests, SparseVectorReserveRelease)
  47. {
  48. SparseVector<TestData> container;
  49. constexpr size_t Count = 10;
  50. size_t indices[Count];
  51. // Create some elements
  52. for (size_t i = 0; i < Count; ++i)
  53. {
  54. indices[i] = container.Reserve();
  55. }
  56. EXPECT_EQ(container.GetSize(), Count);
  57. // Ensure that the elements were created with valid indices
  58. for (size_t i = 0; i < Count; ++i)
  59. {
  60. EXPECT_EQ(indices[i], i);
  61. }
  62. // Check default initialization of struct and initialize primitive types
  63. for (size_t i = 0; i < Count; ++i)
  64. {
  65. TestData& data = container.GetElement(indices[i]);
  66. // Ensure that the data was initialized properly.
  67. EXPECT_EQ(data.a, TestData::DefaultValueA);
  68. EXPECT_EQ(data.b, TestData::DefaultValueB);
  69. EXPECT_EQ(data.c, TestData::DefaultValueC);
  70. // Assign new unique values
  71. data.a = TestData::DefaultValueA * static_cast<int>(i);
  72. data.b = TestData::DefaultValueB * float(i);
  73. data.c = i % 2 == 0;
  74. }
  75. // Release every other element.
  76. for (size_t i = 0; i < Count; i += 2)
  77. {
  78. container.Release(indices[i]);
  79. }
  80. // Size should be unaffected by release since it just leaves empty slots.
  81. EXPECT_EQ(container.GetSize(), Count);
  82. // Check the remaining slots to make sure the data is still correct
  83. for (size_t i = 1; i < Count; i += 2)
  84. {
  85. TestData& data = container.GetElement(indices[i]);
  86. EXPECT_EQ(data.a, TestData::DefaultValueA * i);
  87. EXPECT_EQ(data.b, TestData::DefaultValueB * float(i));
  88. EXPECT_EQ(data.c, i % 2 == 0);
  89. }
  90. // Re-reserve the previously deleted elements
  91. for (size_t i = 0; i < Count; i += 2)
  92. {
  93. indices[i] = container.Reserve();
  94. }
  95. // Make sure the new elements data is initialized to default.
  96. for (size_t i = 0; i < Count; i += 2)
  97. {
  98. TestData& data = container.GetElement(indices[i]);
  99. // Ensure that the data was initialized properly.
  100. EXPECT_EQ(data.a, TestData::DefaultValueA);
  101. EXPECT_EQ(data.b, TestData::DefaultValueB);
  102. EXPECT_EQ(data.c, TestData::DefaultValueC);
  103. }
  104. }
  105. TEST_F(SparseVectorTests, SparseVectorGetRawData)
  106. {
  107. SparseVector<TestData> container;
  108. constexpr size_t Count = 10;
  109. [[maybe_unused]] size_t indices[Count];
  110. // Create some elements
  111. for (size_t i = 0; i < Count; ++i)
  112. {
  113. indices[i] = container.Reserve();
  114. }
  115. // Get the raw data pointer
  116. const TestData* testData = container.GetRawData();
  117. // Make sure the data in the raw array matches what's expected.
  118. for (size_t i = 0; i < container.GetSize(); ++i)
  119. {
  120. const TestData& data = testData[i];
  121. EXPECT_EQ(data.a, TestData::DefaultValueA);
  122. EXPECT_EQ(data.b, TestData::DefaultValueB);
  123. EXPECT_EQ(data.c, TestData::DefaultValueC);
  124. }
  125. container.Clear();
  126. EXPECT_EQ(0, container.GetSize());
  127. }
  128. TEST_F(SparseVectorTests, MultiSparseVectorCreate)
  129. {
  130. // Simple test to make sure we can create a MultiSparseVector and it initializes with no values.
  131. MultiSparseVector<TestData, int, float> container;
  132. EXPECT_EQ(0, container.GetSize());
  133. container.Clear();
  134. EXPECT_EQ(0, container.GetSize());
  135. }
  136. TEST_F(SparseVectorTests, MultiSparseVectorReserve)
  137. {
  138. MultiSparseVector<TestData, int, float> container;
  139. constexpr size_t Count = 10;
  140. size_t indices[Count];
  141. // Create some elements
  142. for (size_t i = 0; i < Count; ++i)
  143. {
  144. indices[i] = container.Reserve();
  145. }
  146. EXPECT_EQ(container.GetSize(), Count);
  147. // Ensure that the elements were created with valid indices
  148. for (size_t i = 0; i < Count; ++i)
  149. {
  150. EXPECT_EQ(indices[i], i);
  151. }
  152. // Ensure that the data was initialized properly.
  153. for (size_t i = 0; i < Count; ++i)
  154. {
  155. TestData& data = container.GetElement<0>(indices[i]);
  156. EXPECT_EQ(data.a, TestData::DefaultValueA);
  157. EXPECT_EQ(data.b, TestData::DefaultValueB);
  158. EXPECT_EQ(data.c, TestData::DefaultValueC);
  159. data.a = TestData::DefaultValueA * static_cast<int>(i);
  160. data.b = TestData::DefaultValueB * float(i);
  161. data.c = i % 2 == 0;
  162. // Assign some values to the uninitialized primitive types
  163. container.GetElement<1>(indices[i]) = static_cast<int>(i * 10);
  164. container.GetElement<2>(indices[i]) = i * 20.0f;
  165. }
  166. // Release every other element
  167. for (size_t i = 0; i < Count; i += 2)
  168. {
  169. container.Release(indices[i]);
  170. }
  171. // Size should be unaffected by release since it just leaves empty slots.
  172. EXPECT_EQ(container.GetSize(), Count);
  173. // Check the remaining slots to make sure the data is still correct
  174. for (size_t i = 1; i < Count; i += 2)
  175. {
  176. TestData& data = container.GetElement<0>(indices[i]);
  177. EXPECT_EQ(data.a, TestData::DefaultValueA * i);
  178. EXPECT_EQ(data.b, TestData::DefaultValueB * float(i));
  179. EXPECT_EQ(data.c, i % 2 == 0);
  180. EXPECT_EQ(container.GetElement<1>(indices[i]), i * 10);
  181. EXPECT_EQ(container.GetElement<2>(indices[i]), i * 20.0f);
  182. }
  183. // Re-reserve the previously deleted elements
  184. for (size_t i = 0; i < Count; i += 2)
  185. {
  186. indices[i] = container.Reserve();
  187. }
  188. // Make sure the new elements data is initialized to default.
  189. for (size_t i = 0; i < Count; i += 2)
  190. {
  191. TestData& data = container.GetElement<0>(indices[i]);
  192. // Ensure that the data was initialized properly.
  193. EXPECT_EQ(data.a, TestData::DefaultValueA);
  194. EXPECT_EQ(data.b, TestData::DefaultValueB);
  195. EXPECT_EQ(data.c, TestData::DefaultValueC);
  196. EXPECT_EQ(container.GetElement<1>(indices[i]), 0);
  197. EXPECT_EQ(container.GetElement<2>(indices[i]), 0.0f);
  198. }
  199. }
  200. TEST_F(SparseVectorTests, MultiSparseVectorGetRawData)
  201. {
  202. MultiSparseVector<TestData, int, float> container;
  203. constexpr size_t Count = 10;
  204. [[maybe_unused]] size_t indices[Count];
  205. // Create some elements and give them values to check later.
  206. for (size_t i = 0; i < Count; ++i)
  207. {
  208. indices[i] = container.Reserve();
  209. container.GetElement<1>(i) = static_cast<int>(i * 10);
  210. container.GetElement<2>(i) = i * 20.0f;
  211. }
  212. // Get raw data arrays
  213. const TestData* testData = container.GetRawData<0>();
  214. const int* testints = container.GetRawData<1>();
  215. const float* testfloats = container.GetRawData<2>();
  216. // Check all the data to make sure it's accurate.
  217. for (size_t i = 0; i < container.GetSize(); ++i)
  218. {
  219. const TestData& data = testData[i];
  220. EXPECT_EQ(data.a, TestData::DefaultValueA);
  221. EXPECT_EQ(data.b, TestData::DefaultValueB);
  222. EXPECT_EQ(data.c, TestData::DefaultValueC);
  223. }
  224. for (size_t i = 0; i < container.GetSize(); ++i)
  225. {
  226. EXPECT_EQ(testints[i], i * 10);
  227. }
  228. for (size_t i = 0; i < container.GetSize(); ++i)
  229. {
  230. EXPECT_EQ(testfloats[i], i * 20.0f);
  231. }
  232. container.Clear();
  233. EXPECT_EQ(0, container.GetSize());
  234. }
  235. TEST_F(SparseVectorTests, SparseVectorNonTrivialDestructor)
  236. {
  237. constexpr size_t Count = 10;
  238. SparseVector<TestDataWithDestructor> container;
  239. for (size_t i = 0; i < Count; ++i)
  240. {
  241. container.Reserve();
  242. }
  243. // Release some elements to call their destructor
  244. for (size_t i = 0; i < Count / 2; ++i)
  245. {
  246. container.Release(i);
  247. }
  248. container.Clear(); // TestDataWithDestructor checks in its destructor for double-deletes;
  249. MultiSparseVector<TestDataWithDestructor, TestData> multiContainer;
  250. for (size_t i = 0; i < Count; ++i)
  251. {
  252. multiContainer.Reserve();
  253. }
  254. // Release some elements to call their destructor
  255. for (size_t i = 0; i < Count / 2; ++i)
  256. {
  257. multiContainer.Release(i);
  258. }
  259. multiContainer.Clear(); // TestDataWithDestructor checks in its destructor for double-deletes;
  260. }
  261. }