lru_cache.cpp 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  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 <AtomCore/std/containers/lru_cache.h>
  9. #include <AzCore/std/smart_ptr/intrusive_base.h>
  10. #include <AzCore/std/smart_ptr/unique_ptr.h>
  11. #include <AzCore/UnitTest/TestTypes.h>
  12. using namespace AZStd;
  13. namespace UnitTest
  14. {
  15. using HashedContainers = LeakDetectionFixture;
  16. TEST_F(HashedContainers, LRUCacheBasic)
  17. {
  18. lru_cache<int, int> intint_cache;
  19. EXPECT_EQ(intint_cache.capacity(), 0);
  20. EXPECT_EQ(intint_cache.empty(), true);
  21. EXPECT_EQ(intint_cache.size(), 0);
  22. EXPECT_EQ(intint_cache.begin(), intint_cache.end());
  23. EXPECT_EQ(intint_cache.rbegin(), intint_cache.rend());
  24. // should assert since capacity is 0.
  25. AZ_TEST_START_ASSERTTEST;
  26. intint_cache.insert(0, 0);
  27. AZ_TEST_STOP_ASSERTTEST(1);
  28. intint_cache.set_capacity(10);
  29. EXPECT_EQ(intint_cache.capacity(), 10);
  30. int i = 0;
  31. for (; i < 10; ++i)
  32. {
  33. intint_cache.insert(i, 2 * i);
  34. }
  35. EXPECT_EQ(intint_cache.size(), 10);
  36. // We should now have [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], with 9 as the most recent (i.e. at begin()).
  37. i = 0;
  38. for (auto it = intint_cache.rbegin(); it != intint_cache.rend(); ++it, ++i)
  39. {
  40. EXPECT_EQ(it->first, i);
  41. EXPECT_EQ(it->second, 2 * i);
  42. }
  43. EXPECT_EQ(intint_cache.get(9)->first, 9);
  44. EXPECT_EQ(intint_cache.get(9)->second, 9 * 2);
  45. // Bump 2 to most recent.
  46. EXPECT_EQ(intint_cache.get(2)->first, 2);
  47. EXPECT_EQ(intint_cache.get(2)->second, 2 * 2);
  48. // Make sure it's most recent.
  49. EXPECT_EQ(intint_cache.begin()->first, 2);
  50. for (i = 10; i < 20; ++i)
  51. {
  52. intint_cache.insert(i, 2 * i);
  53. }
  54. EXPECT_EQ(intint_cache.size(), 10);
  55. // We should now have [10, 11, 12, 13, 14, 15, 16, 17, 18, 19], with 19 as the most recent (i.e. at begin()).
  56. i = 10;
  57. for (auto it = intint_cache.rbegin(); it != intint_cache.rend(); ++it, ++i)
  58. {
  59. EXPECT_EQ(it->first, i);
  60. EXPECT_EQ(it->second, 2 * i);
  61. }
  62. intint_cache.set_capacity(1);
  63. EXPECT_EQ(intint_cache.size(), 1);
  64. EXPECT_EQ(intint_cache.capacity(), 1);
  65. EXPECT_EQ(intint_cache.begin()->first, 19);
  66. intint_cache.set_capacity(8);
  67. for (i = 0; i < 8; ++i)
  68. {
  69. intint_cache.insert(i, 2 * i);
  70. }
  71. {
  72. auto it = intint_cache.get(5);
  73. EXPECT_EQ(it, intint_cache.begin());
  74. EXPECT_EQ(it->first, 5);
  75. EXPECT_EQ(it->second, 10);
  76. }
  77. // Test adding the same key 10 times.
  78. for (i = 0; i < 10; ++i)
  79. {
  80. intint_cache.insert(0, 0);
  81. }
  82. // the first element should be 0, the rest should be shifted.
  83. EXPECT_EQ(intint_cache.begin()->first, 0);
  84. EXPECT_EQ(intint_cache.begin()->second, 0);
  85. // Asset the second element is (5, 10) the previously added element.
  86. {
  87. auto it = intint_cache.begin();
  88. it++;
  89. EXPECT_EQ(it->first, 5);
  90. EXPECT_EQ(it->second, 10);
  91. }
  92. }
  93. TEST_F(HashedContainers, LRUCacheMoveConstruct)
  94. {
  95. using PtrType = AZStd::unique_ptr<int>;
  96. lru_cache<int, PtrType> intintptr_cache(10);
  97. int i = 0;
  98. for (; i < 10; ++i)
  99. {
  100. intintptr_cache.emplace(i, new int(2 * i));
  101. }
  102. EXPECT_EQ(intintptr_cache.size(), 10);
  103. i = 0;
  104. for (auto it = intintptr_cache.rbegin(); it != intintptr_cache.rend(); ++it, ++i)
  105. {
  106. EXPECT_EQ(it->first, i);
  107. EXPECT_EQ(*(it->second), i * 2);
  108. }
  109. }
  110. TEST_F(HashedContainers, LRUCacheRefCount)
  111. {
  112. class X : public AZStd::intrusive_base
  113. {
  114. public:
  115. X(uint32_t value) : m_value{value} {}
  116. uint32_t m_value;
  117. };
  118. const int TestValue = 123;
  119. using PtrType = AZStd::intrusive_ptr<X>;
  120. lru_cache<int, PtrType> intintptr_cache(10);
  121. PtrType p(new X(TestValue));
  122. intintptr_cache.emplace(0, p);
  123. auto beginIt = intintptr_cache.begin();
  124. EXPECT_EQ(beginIt->second->m_value, TestValue);
  125. EXPECT_EQ(p->use_count(), 2);
  126. int i = 0;
  127. for (; i < 10; ++i)
  128. {
  129. intintptr_cache.emplace(i, p);
  130. }
  131. // Should have all 10 references + the one we hold.
  132. EXPECT_EQ(p->use_count(), 11);
  133. intintptr_cache.clear();
  134. EXPECT_EQ(p->use_count(), 1);
  135. }
  136. }