LinearMap.h 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. #ifndef GUL_LINEAR_MAP_H
  2. #define GUL_LINEAR_MAP_H
  3. #include <limits>
  4. #include <stdexcept>
  5. #include <vector>
  6. #include <unordered_map>
  7. namespace gul
  8. {
  9. /**
  10. * @brief The LinearMap class
  11. *
  12. * A linear map works like an unordered_map
  13. * except the data is stored in a linear array.
  14. *
  15. * There is an indirect unordered map which
  16. * maps the key value to the index into the array
  17. *
  18. *
  19. */
  20. template<typename Key_, typename Value_>
  21. class LinearMap
  22. {
  23. public:
  24. using key_type = Key_;
  25. using value_type = Value_;
  26. using array_type = std::vector<value_type>;
  27. static constexpr size_t npos = std::numeric_limits<size_t>::max();
  28. auto begin()
  29. {
  30. return m_keyToIndex.begin();
  31. }
  32. auto end()
  33. {
  34. return m_keyToIndex.end();
  35. }
  36. auto begin() const
  37. {
  38. return m_keyToIndex.begin();
  39. }
  40. auto end() const
  41. {
  42. return m_keyToIndex.end();
  43. }
  44. /**
  45. * @brief at
  46. * @param k
  47. * @return
  48. *
  49. * Returns the value at a particlar key. Throws an exception
  50. * if the key doesn't exist
  51. */
  52. value_type& at(key_type const &k)
  53. {
  54. return m_data[m_keyToIndex.at(k)];
  55. }
  56. value_type const & at(key_type const &k) const
  57. {
  58. return m_data[m_keyToIndex.at(k)];
  59. }
  60. /**
  61. * @brief operator []
  62. * @param k
  63. * @return
  64. *
  65. * Similar to map[key], returns a reference
  66. * to value with the specified key. Default
  67. * constructs if doesn't exist.
  68. */
  69. value_type& operator[](key_type const &k)
  70. {
  71. auto it = findIndex(k);
  72. if(it != npos)
  73. {
  74. return m_data[it];
  75. }
  76. else
  77. {
  78. m_keyToIndex[k] = m_data.size();
  79. return m_data.emplace_back();
  80. }
  81. }
  82. value_type const & valueAt(size_t i) const
  83. {
  84. return m_data[i];
  85. }
  86. value_type& valueAt(size_t i)
  87. {
  88. return m_data[i];
  89. }
  90. size_t count(key_type const & k) const
  91. {
  92. return m_keyToIndex.count(k);
  93. }
  94. /**
  95. * @brief findIndex
  96. * @param k
  97. * @return
  98. *
  99. * returns the index at which the key was stored
  100. * returns npos if not found
  101. */
  102. size_t findIndex(key_type const & k) const
  103. {
  104. auto it = m_keyToIndex.find(k);
  105. if(it == m_keyToIndex.end())
  106. {
  107. return npos;
  108. }
  109. return it->second;
  110. }
  111. /**
  112. * @brief insert
  113. * @param k
  114. * @param v
  115. * @return
  116. *
  117. * returns the index into the array where the
  118. * value was stored
  119. */
  120. size_t insert(key_type k, value_type const & v)
  121. {
  122. auto it = m_keyToIndex.find(k);
  123. if(it == m_keyToIndex.end())
  124. {
  125. if(!m_freeIndices.empty())
  126. {
  127. auto i = m_freeIndices.back();
  128. m_freeIndices.pop_back();
  129. m_keyToIndex[k] = i;
  130. m_data[i] = v;
  131. return i;
  132. }
  133. m_data.push_back(v);
  134. m_keyToIndex[k] = m_data.size()-1;
  135. return m_data.size()-1;
  136. }
  137. else
  138. {
  139. m_data[it->second] = v;
  140. return it->second;
  141. }
  142. }
  143. /**
  144. * @brief erase
  145. * @param k
  146. * @return
  147. *
  148. * Erases a key from the map, this does not change
  149. * the capacity()
  150. */
  151. bool erase(key_type const & k)
  152. {
  153. auto it = m_keyToIndex.find(k);
  154. if(it == m_keyToIndex.end())
  155. {
  156. return false;
  157. }
  158. auto i = it->second;
  159. m_data[it->second] = {};
  160. m_keyToIndex.erase(it);
  161. m_freeIndices.push_back(i);
  162. return true;
  163. }
  164. /**
  165. * @brief size
  166. * @return
  167. *
  168. * Returns the total number of keys
  169. */
  170. size_t size() const
  171. {
  172. return m_keyToIndex.size();
  173. }
  174. /**
  175. * @brief capacity
  176. * @return
  177. *
  178. * Returns the total number of elements in the array.
  179. * This value does not change erasing elements.
  180. */
  181. size_t capacity() const
  182. {
  183. return m_data.size();
  184. }
  185. /**
  186. * @brief array
  187. * @return
  188. *
  189. * Returns the underlying array data type.
  190. */
  191. array_type const & array() const
  192. {
  193. return m_data;
  194. }
  195. /**
  196. * @brief defragment
  197. *
  198. * Defragments the underlying vector and reorders
  199. * all the keys. Resizes the vector so there is no
  200. * empty spaces
  201. */
  202. void defragment()
  203. {
  204. LinearMap<key_type, value_type> _new;
  205. for(auto & [k,i] : *this)
  206. {
  207. _new.insert(k, valueAt(i));
  208. }
  209. m_data = std::move(_new.m_data);
  210. m_keyToIndex = std::move(_new.m_keyToIndex);
  211. m_freeIndices.clear();
  212. }
  213. protected:
  214. array_type m_data;
  215. std::unordered_map<key_type, std::size_t> m_keyToIndex;
  216. std::vector<size_t> m_freeIndices;
  217. };
  218. }
  219. #endif