map.cpp 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. /*
  2. * Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>
  3. */
  4. #if __GNUC__
  5. // We need auto_ptr for compatibility reasons
  6. # pragma GCC diagnostic ignored "-Wdeprecated-declarations"
  7. # pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant"
  8. #endif
  9. #include <string>
  10. #include <cstdio>
  11. #include <memory>
  12. #include <gtest/gtest.h>
  13. #include <uavcan/util/map.hpp>
  14. /*
  15. * TODO: This one test has been temporarily disabled because it is not compatible with newer versions of libstdc++
  16. * that ship with newer versions of GCC. The problem is that std::string has become too large to fit into a 64-byte
  17. * large memory block. This should be fixed in the future.
  18. */
  19. #if 0
  20. static std::string toString(long x)
  21. {
  22. char buf[80];
  23. std::snprintf(buf, sizeof(buf), "%li", x);
  24. return std::string(buf);
  25. }
  26. static bool oddValuePredicate(const std::string& key, const std::string& value)
  27. {
  28. EXPECT_FALSE(key.empty());
  29. EXPECT_FALSE(value.empty());
  30. const int num = atoi(value.c_str());
  31. return num & 1;
  32. }
  33. struct KeyFindPredicate
  34. {
  35. const std::string target;
  36. KeyFindPredicate(std::string target) : target(target) { }
  37. bool operator()(const std::string& key, const std::string&) const { return key == target; }
  38. };
  39. struct ValueFindPredicate
  40. {
  41. const std::string target;
  42. ValueFindPredicate(std::string target) : target(target) { }
  43. bool operator()(const std::string&, const std::string& value) const { return value == target; }
  44. };
  45. TEST(Map, Basic)
  46. {
  47. using uavcan::Map;
  48. static const int POOL_BLOCKS = 3;
  49. uavcan::PoolAllocator<uavcan::MemPoolBlockSize * POOL_BLOCKS, uavcan::MemPoolBlockSize> pool;
  50. typedef Map<std::string, std::string> MapType;
  51. std::auto_ptr<MapType> map(new MapType(pool));
  52. // Empty
  53. ASSERT_FALSE(map->access("hi"));
  54. map->remove("foo");
  55. ASSERT_EQ(0, pool.getNumUsedBlocks());
  56. ASSERT_FALSE(map->getByIndex(0));
  57. ASSERT_FALSE(map->getByIndex(1));
  58. ASSERT_FALSE(map->getByIndex(10000));
  59. // Insertion
  60. ASSERT_EQ("a", *map->insert("1", "a"));
  61. ASSERT_EQ("b", *map->insert("2", "b"));
  62. ASSERT_EQ(1, pool.getNumUsedBlocks());
  63. ASSERT_EQ(2, map->getSize());
  64. // Ordering
  65. ASSERT_TRUE(map->getByIndex(0)->match("1"));
  66. ASSERT_TRUE(map->getByIndex(1)->match("2"));
  67. // Insertion
  68. ASSERT_EQ("c", *map->insert("3", "c"));
  69. ASSERT_EQ(1, pool.getNumUsedBlocks());
  70. ASSERT_EQ("d", *map->insert("4", "d"));
  71. ASSERT_EQ(2, pool.getNumUsedBlocks()); // Assuming that at least 2 items fit one block
  72. ASSERT_EQ(4, map->getSize());
  73. // Making sure everything is here
  74. ASSERT_EQ("a", *map->access("1"));
  75. ASSERT_EQ("b", *map->access("2"));
  76. ASSERT_EQ("c", *map->access("3"));
  77. ASSERT_EQ("d", *map->access("4"));
  78. ASSERT_FALSE(map->access("hi"));
  79. // Modifying existing entries
  80. *map->access("1") = "A";
  81. *map->access("2") = "B";
  82. *map->access("3") = "C";
  83. *map->access("4") = "D";
  84. ASSERT_EQ("A", *map->access("1"));
  85. ASSERT_EQ("B", *map->access("2"));
  86. ASSERT_EQ("C", *map->access("3"));
  87. ASSERT_EQ("D", *map->access("4"));
  88. // Finding some keys
  89. ASSERT_EQ("1", *map->find(KeyFindPredicate("1")));
  90. ASSERT_EQ("2", *map->find(KeyFindPredicate("2")));
  91. ASSERT_EQ("3", *map->find(KeyFindPredicate("3")));
  92. ASSERT_EQ("4", *map->find(KeyFindPredicate("4")));
  93. ASSERT_FALSE(map->find(KeyFindPredicate("nonexistent_key")));
  94. // Finding some values
  95. ASSERT_EQ("1", *map->find(ValueFindPredicate("A")));
  96. ASSERT_EQ("2", *map->find(ValueFindPredicate("B")));
  97. ASSERT_EQ("3", *map->find(ValueFindPredicate("C")));
  98. ASSERT_EQ("4", *map->find(ValueFindPredicate("D")));
  99. ASSERT_FALSE(map->find(KeyFindPredicate("nonexistent_value")));
  100. // Removing one
  101. map->remove("1"); // One of dynamics now migrates to the static storage
  102. map->remove("foo"); // There's no such thing anyway
  103. ASSERT_EQ(2, pool.getNumUsedBlocks());
  104. ASSERT_EQ(3, map->getSize());
  105. ASSERT_FALSE(map->access("1"));
  106. ASSERT_EQ("B", *map->access("2"));
  107. ASSERT_EQ("C", *map->access("3"));
  108. ASSERT_EQ("D", *map->access("4"));
  109. // Removing another
  110. map->remove("2");
  111. ASSERT_EQ(2, map->getSize());
  112. ASSERT_EQ(2, pool.getNumUsedBlocks());
  113. ASSERT_FALSE(map->access("1"));
  114. ASSERT_FALSE(map->access("2"));
  115. ASSERT_EQ("C", *map->access("3"));
  116. ASSERT_EQ("D", *map->access("4"));
  117. // Adding some new
  118. unsigned max_key_integer = 0;
  119. for (int i = 0; i < 100; i++)
  120. {
  121. const std::string key = toString(i);
  122. const std::string value = toString(i);
  123. std::string* res = map->insert(key, value); // Will override some from the above
  124. if (res == UAVCAN_NULLPTR)
  125. {
  126. ASSERT_LT(2, i);
  127. break;
  128. }
  129. else
  130. {
  131. ASSERT_EQ(value, *res);
  132. }
  133. max_key_integer = unsigned(i);
  134. }
  135. std::cout << "Max key/value: " << max_key_integer << std::endl;
  136. ASSERT_LT(4, max_key_integer);
  137. // Making sure there is true OOM
  138. ASSERT_EQ(0, pool.getNumFreeBlocks());
  139. ASSERT_FALSE(map->insert("nonexistent", "value"));
  140. ASSERT_FALSE(map->access("nonexistent"));
  141. ASSERT_FALSE(map->access("value"));
  142. // Removing odd values - nearly half of them
  143. map->removeAllWhere(oddValuePredicate);
  144. // Making sure there's no odd values left
  145. for (unsigned kv_int = 0; kv_int <= max_key_integer; kv_int++)
  146. {
  147. const std::string* val = map->access(toString(kv_int));
  148. if (val)
  149. {
  150. ASSERT_FALSE(kv_int & 1);
  151. }
  152. else
  153. {
  154. ASSERT_TRUE(kv_int & 1);
  155. }
  156. }
  157. // Making sure the memory will be released
  158. map.reset();
  159. ASSERT_EQ(0, pool.getNumUsedBlocks());
  160. }
  161. #endif
  162. TEST(Map, PrimitiveKey)
  163. {
  164. using uavcan::Map;
  165. static const int POOL_BLOCKS = 3;
  166. uavcan::PoolAllocator<uavcan::MemPoolBlockSize * POOL_BLOCKS, uavcan::MemPoolBlockSize> pool;
  167. typedef Map<short, short> MapType;
  168. std::auto_ptr<MapType> map(new MapType(pool));
  169. // Empty
  170. ASSERT_FALSE(map->access(1));
  171. map->remove(8);
  172. ASSERT_EQ(0, pool.getNumUsedBlocks());
  173. ASSERT_EQ(0, map->getSize());
  174. ASSERT_FALSE(map->getByIndex(0));
  175. // Insertion
  176. ASSERT_EQ(1, *map->insert(1, 1));
  177. ASSERT_EQ(1, map->getSize());
  178. ASSERT_EQ(2, *map->insert(2, 2));
  179. ASSERT_EQ(2, map->getSize());
  180. ASSERT_EQ(3, *map->insert(3, 3));
  181. ASSERT_EQ(4, *map->insert(4, 4));
  182. ASSERT_EQ(4, map->getSize());
  183. // Ordering
  184. ASSERT_TRUE(map->getByIndex(0)->match(1));
  185. ASSERT_TRUE(map->getByIndex(1)->match(2));
  186. ASSERT_TRUE(map->getByIndex(2)->match(3));
  187. ASSERT_TRUE(map->getByIndex(3)->match(4));
  188. ASSERT_FALSE(map->getByIndex(5));
  189. ASSERT_FALSE(map->getByIndex(1000));
  190. }