fixed_array_test.cc 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835
  1. // Copyright 2017 The Abseil Authors.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // https://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #include "ceres/internal/fixed_array.h"
  15. #include <cstdio>
  16. #include <cstring>
  17. #include <list>
  18. #include <memory>
  19. #include <numeric>
  20. #include <scoped_allocator>
  21. #include <stdexcept>
  22. #include <string>
  23. #include <vector>
  24. #include "gmock/gmock.h"
  25. #include "gtest/gtest.h"
  26. using ::testing::ElementsAreArray;
  27. namespace {
  28. // CERES_INTERNAL_ARRAYSIZE()
  29. //
  30. // Returns the number of elements in an array as a compile-time constant, which
  31. // can be used in defining new arrays. If you use this macro on a pointer by
  32. // mistake, you will get a compile-time error.
  33. #define CERES_INTERNAL_ARRAYSIZE(array) (sizeof(ArraySizeHelper(array)))
  34. // Note: this internal template function declaration is used by
  35. // CERES_INTERNAL_ARRAYSIZE. The function doesn't need a definition, as we only
  36. // use its type.
  37. template <typename T, size_t N>
  38. auto ArraySizeHelper(const T (&array)[N]) -> char (&)[N];
  39. // Helper routine to determine if a ceres::internal::FixedArray used stack
  40. // allocation.
  41. template <typename ArrayType>
  42. static bool IsOnStack(const ArrayType& a) {
  43. return a.size() <= ArrayType::inline_elements;
  44. }
  45. class ConstructionTester {
  46. public:
  47. ConstructionTester() : self_ptr_(this) { constructions++; }
  48. ~ConstructionTester() {
  49. assert(self_ptr_ == this);
  50. self_ptr_ = nullptr;
  51. destructions++;
  52. }
  53. // These are incremented as elements are constructed and destructed so we can
  54. // be sure all elements are properly cleaned up.
  55. static int constructions;
  56. static int destructions;
  57. void CheckConstructed() { assert(self_ptr_ == this); }
  58. void set(int value) { value_ = value; }
  59. int get() { return value_; }
  60. private:
  61. // self_ptr_ should always point to 'this' -- that's how we can be sure the
  62. // constructor has been called.
  63. ConstructionTester* self_ptr_;
  64. int value_{0};
  65. };
  66. int ConstructionTester::constructions = 0;
  67. int ConstructionTester::destructions = 0;
  68. // ThreeInts will initialize its three ints to the value stored in
  69. // ThreeInts::counter. The constructor increments counter so that each object
  70. // in an array of ThreeInts will have different values.
  71. class ThreeInts {
  72. public:
  73. ThreeInts() {
  74. x_ = counter;
  75. y_ = counter;
  76. z_ = counter;
  77. ++counter;
  78. }
  79. static int counter;
  80. int x_, y_, z_;
  81. };
  82. int ThreeInts::counter = 0;
  83. TEST(FixedArrayTest, CopyCtor) {
  84. ceres::internal::FixedArray<int, 10> on_stack(5);
  85. std::iota(on_stack.begin(), on_stack.end(), 0);
  86. ceres::internal::FixedArray<int, 10> stack_copy = on_stack;
  87. EXPECT_THAT(stack_copy, ElementsAreArray(on_stack));
  88. EXPECT_TRUE(IsOnStack(stack_copy));
  89. ceres::internal::FixedArray<int, 10> allocated(15);
  90. std::iota(allocated.begin(), allocated.end(), 0);
  91. ceres::internal::FixedArray<int, 10> alloced_copy = allocated;
  92. EXPECT_THAT(alloced_copy, ElementsAreArray(allocated));
  93. EXPECT_FALSE(IsOnStack(alloced_copy));
  94. }
  95. TEST(FixedArrayTest, MoveCtor) {
  96. ceres::internal::FixedArray<std::unique_ptr<int>, 10> on_stack(5);
  97. for (int i = 0; i < 5; ++i) {
  98. on_stack[i] = std::make_unique<int>(i);
  99. }
  100. ceres::internal::FixedArray<std::unique_ptr<int>, 10> stack_copy =
  101. std::move(on_stack);
  102. for (int i = 0; i < 5; ++i) EXPECT_EQ(*(stack_copy[i]), i);
  103. EXPECT_EQ(stack_copy.size(), on_stack.size());
  104. ceres::internal::FixedArray<std::unique_ptr<int>, 10> allocated(15);
  105. for (int i = 0; i < 15; ++i) {
  106. allocated[i] = std::make_unique<int>(i);
  107. }
  108. ceres::internal::FixedArray<std::unique_ptr<int>, 10> alloced_copy =
  109. std::move(allocated);
  110. for (int i = 0; i < 15; ++i) EXPECT_EQ(*(alloced_copy[i]), i);
  111. EXPECT_EQ(allocated.size(), alloced_copy.size());
  112. }
  113. TEST(FixedArrayTest, SmallObjects) {
  114. // Small object arrays
  115. {
  116. // Short arrays should be on the stack
  117. ceres::internal::FixedArray<int> array(4);
  118. EXPECT_TRUE(IsOnStack(array));
  119. }
  120. {
  121. // Large arrays should be on the heap
  122. ceres::internal::FixedArray<int> array(1048576);
  123. EXPECT_FALSE(IsOnStack(array));
  124. }
  125. {
  126. // Arrays of <= default size should be on the stack
  127. ceres::internal::FixedArray<int, 100> array(100);
  128. EXPECT_TRUE(IsOnStack(array));
  129. }
  130. {
  131. // Arrays of > default size should be on the heap
  132. ceres::internal::FixedArray<int, 100> array(101);
  133. EXPECT_FALSE(IsOnStack(array));
  134. }
  135. {
  136. // Arrays with different size elements should use approximately
  137. // same amount of stack space
  138. ceres::internal::FixedArray<int> array1(0);
  139. ceres::internal::FixedArray<char> array2(0);
  140. EXPECT_LE(sizeof(array1), sizeof(array2) + 100);
  141. EXPECT_LE(sizeof(array2), sizeof(array1) + 100);
  142. }
  143. {
  144. // Ensure that vectors are properly constructed inside a fixed array.
  145. ceres::internal::FixedArray<std::vector<int>> array(2);
  146. EXPECT_EQ(0, array[0].size());
  147. EXPECT_EQ(0, array[1].size());
  148. }
  149. {
  150. // Regardless of ceres::internal::FixedArray implementation, check that a
  151. // type with a low alignment requirement and a non power-of-two size is
  152. // initialized correctly.
  153. ThreeInts::counter = 1;
  154. ceres::internal::FixedArray<ThreeInts> array(2);
  155. EXPECT_EQ(1, array[0].x_);
  156. EXPECT_EQ(1, array[0].y_);
  157. EXPECT_EQ(1, array[0].z_);
  158. EXPECT_EQ(2, array[1].x_);
  159. EXPECT_EQ(2, array[1].y_);
  160. EXPECT_EQ(2, array[1].z_);
  161. }
  162. }
  163. TEST(FixedArrayRelationalsTest, EqualArrays) {
  164. for (int i = 0; i < 10; ++i) {
  165. ceres::internal::FixedArray<int, 5> a1(i);
  166. std::iota(a1.begin(), a1.end(), 0);
  167. ceres::internal::FixedArray<int, 5> a2(a1.begin(), a1.end());
  168. EXPECT_TRUE(a1 == a2);
  169. EXPECT_FALSE(a1 != a2);
  170. EXPECT_TRUE(a2 == a1);
  171. EXPECT_FALSE(a2 != a1);
  172. EXPECT_FALSE(a1 < a2);
  173. EXPECT_FALSE(a1 > a2);
  174. EXPECT_FALSE(a2 < a1);
  175. EXPECT_FALSE(a2 > a1);
  176. EXPECT_TRUE(a1 <= a2);
  177. EXPECT_TRUE(a1 >= a2);
  178. EXPECT_TRUE(a2 <= a1);
  179. EXPECT_TRUE(a2 >= a1);
  180. }
  181. }
  182. TEST(FixedArrayRelationalsTest, UnequalArrays) {
  183. for (int i = 1; i < 10; ++i) {
  184. ceres::internal::FixedArray<int, 5> a1(i);
  185. std::iota(a1.begin(), a1.end(), 0);
  186. ceres::internal::FixedArray<int, 5> a2(a1.begin(), a1.end());
  187. --a2[i / 2];
  188. EXPECT_FALSE(a1 == a2);
  189. EXPECT_TRUE(a1 != a2);
  190. EXPECT_FALSE(a2 == a1);
  191. EXPECT_TRUE(a2 != a1);
  192. EXPECT_FALSE(a1 < a2);
  193. EXPECT_TRUE(a1 > a2);
  194. EXPECT_TRUE(a2 < a1);
  195. EXPECT_FALSE(a2 > a1);
  196. EXPECT_FALSE(a1 <= a2);
  197. EXPECT_TRUE(a1 >= a2);
  198. EXPECT_TRUE(a2 <= a1);
  199. EXPECT_FALSE(a2 >= a1);
  200. }
  201. }
  202. template <int stack_elements>
  203. static void TestArray(int n) {
  204. SCOPED_TRACE(n);
  205. SCOPED_TRACE(stack_elements);
  206. ConstructionTester::constructions = 0;
  207. ConstructionTester::destructions = 0;
  208. {
  209. ceres::internal::FixedArray<ConstructionTester, stack_elements> array(n);
  210. EXPECT_THAT(array.size(), n);
  211. EXPECT_THAT(array.memsize(), sizeof(ConstructionTester) * n);
  212. EXPECT_THAT(array.begin() + n, array.end());
  213. // Check that all elements were constructed
  214. for (int i = 0; i < n; i++) {
  215. array[i].CheckConstructed();
  216. }
  217. // Check that no other elements were constructed
  218. EXPECT_THAT(ConstructionTester::constructions, n);
  219. // Test operator[]
  220. for (int i = 0; i < n; i++) {
  221. array[i].set(i);
  222. }
  223. for (int i = 0; i < n; i++) {
  224. EXPECT_THAT(array[i].get(), i);
  225. EXPECT_THAT(array.data()[i].get(), i);
  226. }
  227. // Test data()
  228. for (int i = 0; i < n; i++) {
  229. array.data()[i].set(i + 1);
  230. }
  231. for (int i = 0; i < n; i++) {
  232. EXPECT_THAT(array[i].get(), i + 1);
  233. EXPECT_THAT(array.data()[i].get(), i + 1);
  234. }
  235. } // Close scope containing 'array'.
  236. // Check that all constructed elements were destructed.
  237. EXPECT_EQ(ConstructionTester::constructions,
  238. ConstructionTester::destructions);
  239. }
  240. template <int elements_per_inner_array, int inline_elements>
  241. static void TestArrayOfArrays(int n) {
  242. SCOPED_TRACE(n);
  243. SCOPED_TRACE(inline_elements);
  244. SCOPED_TRACE(elements_per_inner_array);
  245. ConstructionTester::constructions = 0;
  246. ConstructionTester::destructions = 0;
  247. {
  248. using InnerArray = ConstructionTester[elements_per_inner_array];
  249. // Heap-allocate the FixedArray to avoid blowing the stack frame.
  250. auto array_ptr = std::unique_ptr<
  251. ceres::internal::FixedArray<InnerArray, inline_elements>>(
  252. new ceres::internal::FixedArray<InnerArray, inline_elements>(n));
  253. auto& array = *array_ptr;
  254. ASSERT_EQ(array.size(), n);
  255. ASSERT_EQ(array.memsize(),
  256. sizeof(ConstructionTester) * elements_per_inner_array * n);
  257. ASSERT_EQ(array.begin() + n, array.end());
  258. // Check that all elements were constructed
  259. for (int i = 0; i < n; i++) {
  260. for (int j = 0; j < elements_per_inner_array; j++) {
  261. (array[i])[j].CheckConstructed();
  262. }
  263. }
  264. // Check that no other elements were constructed
  265. ASSERT_EQ(ConstructionTester::constructions, n * elements_per_inner_array);
  266. // Test operator[]
  267. for (int i = 0; i < n; i++) {
  268. for (int j = 0; j < elements_per_inner_array; j++) {
  269. (array[i])[j].set(i * elements_per_inner_array + j);
  270. }
  271. }
  272. for (int i = 0; i < n; i++) {
  273. for (int j = 0; j < elements_per_inner_array; j++) {
  274. ASSERT_EQ((array[i])[j].get(), i * elements_per_inner_array + j);
  275. ASSERT_EQ((array.data()[i])[j].get(), i * elements_per_inner_array + j);
  276. }
  277. }
  278. // Test data()
  279. for (int i = 0; i < n; i++) {
  280. for (int j = 0; j < elements_per_inner_array; j++) {
  281. (array.data()[i])[j].set((i + 1) * elements_per_inner_array + j);
  282. }
  283. }
  284. for (int i = 0; i < n; i++) {
  285. for (int j = 0; j < elements_per_inner_array; j++) {
  286. ASSERT_EQ((array[i])[j].get(), (i + 1) * elements_per_inner_array + j);
  287. ASSERT_EQ((array.data()[i])[j].get(),
  288. (i + 1) * elements_per_inner_array + j);
  289. }
  290. }
  291. } // Close scope containing 'array'.
  292. // Check that all constructed elements were destructed.
  293. EXPECT_EQ(ConstructionTester::constructions,
  294. ConstructionTester::destructions);
  295. }
  296. TEST(IteratorConstructorTest, NonInline) {
  297. int const kInput[] = {2, 3, 5, 7, 11, 13, 17};
  298. ceres::internal::FixedArray<int, CERES_INTERNAL_ARRAYSIZE(kInput) - 1> const
  299. fixed(kInput, kInput + CERES_INTERNAL_ARRAYSIZE(kInput));
  300. ASSERT_EQ(CERES_INTERNAL_ARRAYSIZE(kInput), fixed.size());
  301. for (size_t i = 0; i < CERES_INTERNAL_ARRAYSIZE(kInput); ++i) {
  302. ASSERT_EQ(kInput[i], fixed[i]);
  303. }
  304. }
  305. TEST(IteratorConstructorTest, Inline) {
  306. int const kInput[] = {2, 3, 5, 7, 11, 13, 17};
  307. ceres::internal::FixedArray<int, CERES_INTERNAL_ARRAYSIZE(kInput)> const
  308. fixed(kInput, kInput + CERES_INTERNAL_ARRAYSIZE(kInput));
  309. ASSERT_EQ(CERES_INTERNAL_ARRAYSIZE(kInput), fixed.size());
  310. for (size_t i = 0; i < CERES_INTERNAL_ARRAYSIZE(kInput); ++i) {
  311. ASSERT_EQ(kInput[i], fixed[i]);
  312. }
  313. }
  314. TEST(IteratorConstructorTest, NonPod) {
  315. char const* kInput[] = {
  316. "red", "orange", "yellow", "green", "blue", "indigo", "violet"};
  317. ceres::internal::FixedArray<std::string> const fixed(
  318. kInput, kInput + CERES_INTERNAL_ARRAYSIZE(kInput));
  319. ASSERT_EQ(CERES_INTERNAL_ARRAYSIZE(kInput), fixed.size());
  320. for (size_t i = 0; i < CERES_INTERNAL_ARRAYSIZE(kInput); ++i) {
  321. ASSERT_EQ(kInput[i], fixed[i]);
  322. }
  323. }
  324. TEST(IteratorConstructorTest, FromEmptyVector) {
  325. std::vector<int> const empty;
  326. ceres::internal::FixedArray<int> const fixed(empty.begin(), empty.end());
  327. EXPECT_EQ(0, fixed.size());
  328. EXPECT_EQ(empty.size(), fixed.size());
  329. }
  330. TEST(IteratorConstructorTest, FromNonEmptyVector) {
  331. int const kInput[] = {2, 3, 5, 7, 11, 13, 17};
  332. std::vector<int> const items(kInput,
  333. kInput + CERES_INTERNAL_ARRAYSIZE(kInput));
  334. ceres::internal::FixedArray<int> const fixed(items.begin(), items.end());
  335. ASSERT_EQ(items.size(), fixed.size());
  336. for (size_t i = 0; i < items.size(); ++i) {
  337. ASSERT_EQ(items[i], fixed[i]);
  338. }
  339. }
  340. TEST(IteratorConstructorTest, FromBidirectionalIteratorRange) {
  341. int const kInput[] = {2, 3, 5, 7, 11, 13, 17};
  342. std::list<int> const items(kInput, kInput + CERES_INTERNAL_ARRAYSIZE(kInput));
  343. ceres::internal::FixedArray<int> const fixed(items.begin(), items.end());
  344. EXPECT_THAT(fixed, testing::ElementsAreArray(kInput));
  345. }
  346. TEST(InitListConstructorTest, InitListConstruction) {
  347. ceres::internal::FixedArray<int> fixed = {1, 2, 3};
  348. EXPECT_THAT(fixed, testing::ElementsAreArray({1, 2, 3}));
  349. }
  350. TEST(FillConstructorTest, NonEmptyArrays) {
  351. ceres::internal::FixedArray<int> stack_array(4, 1);
  352. EXPECT_THAT(stack_array, testing::ElementsAreArray({1, 1, 1, 1}));
  353. ceres::internal::FixedArray<int, 0> heap_array(4, 1);
  354. EXPECT_THAT(stack_array, testing::ElementsAreArray({1, 1, 1, 1}));
  355. }
  356. TEST(FillConstructorTest, EmptyArray) {
  357. ceres::internal::FixedArray<int> empty_fill(0, 1);
  358. ceres::internal::FixedArray<int> empty_size(0);
  359. EXPECT_EQ(empty_fill, empty_size);
  360. }
  361. TEST(FillConstructorTest, NotTriviallyCopyable) {
  362. std::string str = "abcd";
  363. ceres::internal::FixedArray<std::string> strings = {str, str, str, str};
  364. ceres::internal::FixedArray<std::string> array(4, str);
  365. EXPECT_EQ(array, strings);
  366. }
  367. TEST(FillConstructorTest, Disambiguation) {
  368. ceres::internal::FixedArray<size_t> a(1, 2);
  369. EXPECT_THAT(a, testing::ElementsAre(2));
  370. }
  371. TEST(FixedArrayTest, ManySizedArrays) {
  372. std::vector<int> sizes;
  373. for (int i = 1; i < 100; i++) sizes.push_back(i);
  374. for (int i = 100; i <= 1000; i += 100) sizes.push_back(i);
  375. for (int n : sizes) {
  376. TestArray<0>(n);
  377. TestArray<1>(n);
  378. TestArray<64>(n);
  379. TestArray<1000>(n);
  380. }
  381. }
  382. TEST(FixedArrayTest, ManySizedArraysOfArraysOf1) {
  383. for (int n = 1; n < 1000; n++) {
  384. ASSERT_NO_FATAL_FAILURE((TestArrayOfArrays<1, 0>(n)));
  385. ASSERT_NO_FATAL_FAILURE((TestArrayOfArrays<1, 1>(n)));
  386. ASSERT_NO_FATAL_FAILURE((TestArrayOfArrays<1, 64>(n)));
  387. ASSERT_NO_FATAL_FAILURE((TestArrayOfArrays<1, 1000>(n)));
  388. }
  389. }
  390. TEST(FixedArrayTest, ManySizedArraysOfArraysOf2) {
  391. for (int n = 1; n < 1000; n++) {
  392. TestArrayOfArrays<2, 0>(n);
  393. TestArrayOfArrays<2, 1>(n);
  394. TestArrayOfArrays<2, 64>(n);
  395. TestArrayOfArrays<2, 1000>(n);
  396. }
  397. }
  398. // If value_type is put inside of a struct container,
  399. // we might evoke this error in a hardened build unless data() is carefully
  400. // written, so check on that.
  401. // error: call to int __builtin___sprintf_chk(etc...)
  402. // will always overflow destination buffer [-Werror]
  403. TEST(FixedArrayTest, AvoidParanoidDiagnostics) {
  404. ceres::internal::FixedArray<char, 32> buf(32);
  405. snprintf(buf.data(), 32, "foo");
  406. }
  407. TEST(FixedArrayTest, TooBigInlinedSpace) {
  408. struct TooBig {
  409. char c[1 << 20];
  410. }; // too big for even one on the stack
  411. // Simulate the data members of ceres::internal::FixedArray, a pointer and a
  412. // size_t.
  413. struct Data {
  414. std::tuple<size_t, std::allocator<double>> size_alloc_;
  415. TooBig* p;
  416. };
  417. // Make sure TooBig objects are not inlined for 0 or default size.
  418. static_assert(
  419. sizeof(ceres::internal::FixedArray<TooBig, 0>) == sizeof(Data),
  420. "0-sized ceres::internal::FixedArray should have same size as Data.");
  421. static_assert(
  422. alignof(ceres::internal::FixedArray<TooBig, 0>) == alignof(Data),
  423. "0-sized ceres::internal::FixedArray should have same alignment as "
  424. "Data.");
  425. static_assert(sizeof(ceres::internal::FixedArray<TooBig>) == sizeof(Data),
  426. "default-sized ceres::internal::FixedArray should have same "
  427. "size as Data");
  428. static_assert(alignof(ceres::internal::FixedArray<TooBig>) == alignof(Data),
  429. "default-sized ceres::internal::FixedArray should have same "
  430. "alignment as Data.");
  431. }
  432. // PickyDelete EXPECTs its class-scope deallocation funcs are unused.
  433. struct PickyDelete {
  434. void operator delete(void* p) {
  435. EXPECT_TRUE(false) << __FUNCTION__;
  436. ::operator delete(p);
  437. }
  438. void operator delete[](void* p) {
  439. EXPECT_TRUE(false) << __FUNCTION__;
  440. ::operator delete[](p);
  441. }
  442. };
  443. TEST(FixedArrayTest, UsesGlobalAlloc) {
  444. ceres::internal::FixedArray<PickyDelete, 0> a(5);
  445. }
  446. TEST(FixedArrayTest, Data) {
  447. static const int kInput[] = {2, 3, 5, 7, 11, 13, 17};
  448. ceres::internal::FixedArray<int> fa(std::begin(kInput), std::end(kInput));
  449. EXPECT_EQ(fa.data(), &*fa.begin());
  450. EXPECT_EQ(fa.data(), &fa[0]);
  451. const ceres::internal::FixedArray<int>& cfa = fa;
  452. EXPECT_EQ(cfa.data(), &*cfa.begin());
  453. EXPECT_EQ(cfa.data(), &cfa[0]);
  454. }
  455. TEST(FixedArrayTest, Empty) {
  456. ceres::internal::FixedArray<int> empty(0);
  457. ceres::internal::FixedArray<int> inline_filled(1);
  458. ceres::internal::FixedArray<int, 0> heap_filled(1);
  459. EXPECT_TRUE(empty.empty());
  460. EXPECT_FALSE(inline_filled.empty());
  461. EXPECT_FALSE(heap_filled.empty());
  462. }
  463. TEST(FixedArrayTest, FrontAndBack) {
  464. ceres::internal::FixedArray<int, 3 * sizeof(int)> inlined = {1, 2, 3};
  465. EXPECT_EQ(inlined.front(), 1);
  466. EXPECT_EQ(inlined.back(), 3);
  467. ceres::internal::FixedArray<int, 0> allocated = {1, 2, 3};
  468. EXPECT_EQ(allocated.front(), 1);
  469. EXPECT_EQ(allocated.back(), 3);
  470. ceres::internal::FixedArray<int> one_element = {1};
  471. EXPECT_EQ(one_element.front(), one_element.back());
  472. }
  473. TEST(FixedArrayTest, ReverseIteratorInlined) {
  474. ceres::internal::FixedArray<int, 5 * sizeof(int)> a = {0, 1, 2, 3, 4};
  475. int counter = 5;
  476. for (ceres::internal::FixedArray<int>::reverse_iterator iter = a.rbegin();
  477. iter != a.rend();
  478. ++iter) {
  479. counter--;
  480. EXPECT_EQ(counter, *iter);
  481. }
  482. EXPECT_EQ(counter, 0);
  483. counter = 5;
  484. for (ceres::internal::FixedArray<int>::const_reverse_iterator iter =
  485. a.rbegin();
  486. iter != a.rend();
  487. ++iter) {
  488. counter--;
  489. EXPECT_EQ(counter, *iter);
  490. }
  491. EXPECT_EQ(counter, 0);
  492. counter = 5;
  493. for (auto iter = a.crbegin(); iter != a.crend(); ++iter) {
  494. counter--;
  495. EXPECT_EQ(counter, *iter);
  496. }
  497. EXPECT_EQ(counter, 0);
  498. }
  499. TEST(FixedArrayTest, ReverseIteratorAllocated) {
  500. ceres::internal::FixedArray<int, 0> a = {0, 1, 2, 3, 4};
  501. int counter = 5;
  502. for (ceres::internal::FixedArray<int>::reverse_iterator iter = a.rbegin();
  503. iter != a.rend();
  504. ++iter) {
  505. counter--;
  506. EXPECT_EQ(counter, *iter);
  507. }
  508. EXPECT_EQ(counter, 0);
  509. counter = 5;
  510. for (ceres::internal::FixedArray<int>::const_reverse_iterator iter =
  511. a.rbegin();
  512. iter != a.rend();
  513. ++iter) {
  514. counter--;
  515. EXPECT_EQ(counter, *iter);
  516. }
  517. EXPECT_EQ(counter, 0);
  518. counter = 5;
  519. for (auto iter = a.crbegin(); iter != a.crend(); ++iter) {
  520. counter--;
  521. EXPECT_EQ(counter, *iter);
  522. }
  523. EXPECT_EQ(counter, 0);
  524. }
  525. TEST(FixedArrayTest, Fill) {
  526. ceres::internal::FixedArray<int, 5 * sizeof(int)> inlined(5);
  527. int fill_val = 42;
  528. inlined.fill(fill_val);
  529. for (int i : inlined) EXPECT_EQ(i, fill_val);
  530. ceres::internal::FixedArray<int, 0> allocated(5);
  531. allocated.fill(fill_val);
  532. for (int i : allocated) EXPECT_EQ(i, fill_val);
  533. // It doesn't do anything, just make sure this compiles.
  534. ceres::internal::FixedArray<int> empty(0);
  535. empty.fill(fill_val);
  536. }
  537. // TODO(johnsoncj): Investigate InlinedStorage default initialization in GCC 4.x
  538. #ifndef __GNUC__
  539. TEST(FixedArrayTest, DefaultCtorDoesNotValueInit) {
  540. using T = char;
  541. constexpr auto capacity = 10;
  542. using FixedArrType = ceres::internal::FixedArray<T, capacity>;
  543. using FixedArrBuffType =
  544. typename std::aligned_storage<sizeof(FixedArrType),
  545. alignof(FixedArrType)>::type;
  546. constexpr auto scrubbed_bits = 0x95;
  547. constexpr auto length = capacity / 2;
  548. FixedArrBuffType buff;
  549. std::memset(std::addressof(buff), scrubbed_bits, sizeof(FixedArrBuffType));
  550. FixedArrType* arr =
  551. ::new (static_cast<void*>(std::addressof(buff))) FixedArrType(length);
  552. EXPECT_THAT(*arr, testing::Each(scrubbed_bits));
  553. arr->~FixedArrType();
  554. }
  555. #endif // __GNUC__
  556. // This is a stateful allocator, but the state lives outside of the
  557. // allocator (in whatever test is using the allocator). This is odd
  558. // but helps in tests where the allocator is propagated into nested
  559. // containers - that chain of allocators uses the same state and is
  560. // thus easier to query for aggregate allocation information.
  561. template <typename T>
  562. class CountingAllocator : public std::allocator<T> {
  563. public:
  564. using Alloc = std::allocator<T>;
  565. using size_type = typename Alloc::size_type;
  566. CountingAllocator() = default;
  567. explicit CountingAllocator(int64_t* b) : bytes_used_(b) {}
  568. CountingAllocator(int64_t* b, int64_t* a)
  569. : bytes_used_(b), instance_count_(a) {}
  570. template <typename U>
  571. explicit CountingAllocator(const CountingAllocator<U>& x)
  572. : Alloc(x),
  573. bytes_used_(x.bytes_used_),
  574. instance_count_(x.instance_count_) {}
  575. T* allocate(size_type n) {
  576. assert(bytes_used_ != nullptr);
  577. *bytes_used_ += n * sizeof(T);
  578. return Alloc::allocate(n);
  579. }
  580. void deallocate(T* p, size_type n) {
  581. Alloc::deallocate(p, n);
  582. assert(bytes_used_ != nullptr);
  583. *bytes_used_ -= n * sizeof(T);
  584. }
  585. int64_t* bytes_used_{nullptr};
  586. int64_t* instance_count_{nullptr};
  587. };
  588. TEST(AllocatorSupportTest, CountInlineAllocations) {
  589. constexpr size_t inlined_size = 4;
  590. using Alloc = CountingAllocator<int>;
  591. using AllocFxdArr = ceres::internal::FixedArray<int, inlined_size, Alloc>;
  592. int64_t allocated = 0;
  593. int64_t active_instances = 0;
  594. {
  595. const int ia[] = {0, 1, 2, 3, 4, 5, 6, 7};
  596. Alloc alloc(&allocated, &active_instances);
  597. AllocFxdArr arr(ia, ia + inlined_size, alloc);
  598. static_cast<void>(arr);
  599. }
  600. EXPECT_EQ(allocated, 0);
  601. EXPECT_EQ(active_instances, 0);
  602. }
  603. TEST(AllocatorSupportTest, CountOutoflineAllocations) {
  604. constexpr size_t inlined_size = 4;
  605. using Alloc = CountingAllocator<int>;
  606. using AllocFxdArr = ceres::internal::FixedArray<int, inlined_size, Alloc>;
  607. int64_t allocated = 0;
  608. int64_t active_instances = 0;
  609. {
  610. const int ia[] = {0, 1, 2, 3, 4, 5, 6, 7};
  611. Alloc alloc(&allocated, &active_instances);
  612. AllocFxdArr arr(ia, ia + CERES_INTERNAL_ARRAYSIZE(ia), alloc);
  613. EXPECT_EQ(allocated, arr.size() * sizeof(int));
  614. static_cast<void>(arr);
  615. }
  616. EXPECT_EQ(active_instances, 0);
  617. }
  618. TEST(AllocatorSupportTest, CountCopyInlineAllocations) {
  619. constexpr size_t inlined_size = 4;
  620. using Alloc = CountingAllocator<int>;
  621. using AllocFxdArr = ceres::internal::FixedArray<int, inlined_size, Alloc>;
  622. int64_t allocated1 = 0;
  623. int64_t allocated2 = 0;
  624. int64_t active_instances = 0;
  625. Alloc alloc(&allocated1, &active_instances);
  626. Alloc alloc2(&allocated2, &active_instances);
  627. {
  628. int initial_value = 1;
  629. AllocFxdArr arr1(inlined_size / 2, initial_value, alloc);
  630. EXPECT_EQ(allocated1, 0);
  631. AllocFxdArr arr2(arr1, alloc2);
  632. EXPECT_EQ(allocated2, 0);
  633. static_cast<void>(arr1);
  634. static_cast<void>(arr2);
  635. }
  636. EXPECT_EQ(active_instances, 0);
  637. }
  638. TEST(AllocatorSupportTest, CountCopyOutoflineAllocations) {
  639. constexpr size_t inlined_size = 4;
  640. using Alloc = CountingAllocator<int>;
  641. using AllocFxdArr = ceres::internal::FixedArray<int, inlined_size, Alloc>;
  642. int64_t allocated1 = 0;
  643. int64_t allocated2 = 0;
  644. int64_t active_instances = 0;
  645. Alloc alloc(&allocated1, &active_instances);
  646. Alloc alloc2(&allocated2, &active_instances);
  647. {
  648. int initial_value = 1;
  649. AllocFxdArr arr1(inlined_size * 2, initial_value, alloc);
  650. EXPECT_EQ(allocated1, arr1.size() * sizeof(int));
  651. AllocFxdArr arr2(arr1, alloc2);
  652. EXPECT_EQ(allocated2, inlined_size * 2 * sizeof(int));
  653. static_cast<void>(arr1);
  654. static_cast<void>(arr2);
  655. }
  656. EXPECT_EQ(active_instances, 0);
  657. }
  658. TEST(AllocatorSupportTest, SizeValAllocConstructor) {
  659. using testing::AllOf;
  660. using testing::Each;
  661. using testing::SizeIs;
  662. constexpr size_t inlined_size = 4;
  663. using Alloc = CountingAllocator<int>;
  664. using AllocFxdArr = ceres::internal::FixedArray<int, inlined_size, Alloc>;
  665. {
  666. auto len = inlined_size / 2;
  667. auto val = 0;
  668. int64_t allocated = 0;
  669. AllocFxdArr arr(len, val, Alloc(&allocated));
  670. EXPECT_EQ(allocated, 0);
  671. EXPECT_THAT(arr, AllOf(SizeIs(len), Each(0)));
  672. }
  673. {
  674. auto len = inlined_size * 2;
  675. auto val = 0;
  676. int64_t allocated = 0;
  677. AllocFxdArr arr(len, val, Alloc(&allocated));
  678. EXPECT_EQ(allocated, len * sizeof(int));
  679. EXPECT_THAT(arr, AllOf(SizeIs(len), Each(0)));
  680. }
  681. }
  682. struct EigenStruct {
  683. Eigen::Vector4d data;
  684. };
  685. static_assert(
  686. std::is_same<ceres::internal::FixedArrayDefaultAllocator<double>,
  687. std::allocator<double>>::value,
  688. "Double is a trivial type, so std::allocator should be used here.");
  689. static_assert(
  690. std::is_same<ceres::internal::FixedArrayDefaultAllocator<double*>,
  691. std::allocator<double*>>::value,
  692. "A pointer is a trivial type, so std::allocator should be used here.");
  693. static_assert(
  694. std::is_same<ceres::internal::FixedArrayDefaultAllocator<Eigen::Matrix4d>,
  695. Eigen::aligned_allocator<Eigen::Matrix4d>>::value,
  696. "An Eigen::Matrix4d needs the Eigen::aligned_allocator for proper "
  697. "alignment.");
  698. static_assert(
  699. std::is_same<ceres::internal::FixedArrayDefaultAllocator<EigenStruct>,
  700. Eigen::aligned_allocator<EigenStruct>>::value,
  701. "A struct containing fixed size Eigen types needs Eigen::aligned_allocator "
  702. "for proper alignment.");
  703. } // namespace