SparseSet.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  1. //===- llvm/ADT/SparseSet.h - Sparse set ------------------------*- C++ -*-===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. //
  9. // This file defines the SparseSet class derived from the version described in
  10. // Briggs, Torczon, "An efficient representation for sparse sets", ACM Letters
  11. // on Programming Languages and Systems, Volume 2 Issue 1-4, March-Dec. 1993.
  12. //
  13. // A sparse set holds a small number of objects identified by integer keys from
  14. // a moderately sized universe. The sparse set uses more memory than other
  15. // containers in order to provide faster operations.
  16. //
  17. //===----------------------------------------------------------------------===//
  18. #ifndef LLVM_ADT_SPARSESET_H
  19. #define LLVM_ADT_SPARSESET_H
  20. #include "llvm/ADT/STLExtras.h"
  21. #include "llvm/ADT/SmallVector.h"
  22. #include "llvm/Support/AllocatorBase.h"
  23. #include <cassert>
  24. #include <cstdint>
  25. #include <cstdlib>
  26. #include <limits>
  27. #include <utility>
  28. namespace llvm {
  29. /// SparseSetValTraits - Objects in a SparseSet are identified by keys that can
  30. /// be uniquely converted to a small integer less than the set's universe. This
  31. /// class allows the set to hold values that differ from the set's key type as
  32. /// long as an index can still be derived from the value. SparseSet never
  33. /// directly compares ValueT, only their indices, so it can map keys to
  34. /// arbitrary values. SparseSetValTraits computes the index from the value
  35. /// object. To compute the index from a key, SparseSet uses a separate
  36. /// KeyFunctorT template argument.
  37. ///
  38. /// A simple type declaration, SparseSet<Type>, handles these cases:
  39. /// - unsigned key, identity index, identity value
  40. /// - unsigned key, identity index, fat value providing getSparseSetIndex()
  41. ///
  42. /// The type declaration SparseSet<Type, UnaryFunction> handles:
  43. /// - unsigned key, remapped index, identity value (virtual registers)
  44. /// - pointer key, pointer-derived index, identity value (node+ID)
  45. /// - pointer key, pointer-derived index, fat value with getSparseSetIndex()
  46. ///
  47. /// Only other, unexpected cases require specializing SparseSetValTraits.
  48. ///
  49. /// For best results, ValueT should not require a destructor.
  50. ///
  51. template<typename ValueT>
  52. struct SparseSetValTraits {
  53. static unsigned getValIndex(const ValueT &Val) {
  54. return Val.getSparseSetIndex();
  55. }
  56. };
  57. /// SparseSetValFunctor - Helper class for selecting SparseSetValTraits. The
  58. /// generic implementation handles ValueT classes which either provide
  59. /// getSparseSetIndex() or specialize SparseSetValTraits<>.
  60. ///
  61. template<typename KeyT, typename ValueT, typename KeyFunctorT>
  62. struct SparseSetValFunctor {
  63. unsigned operator()(const ValueT &Val) const {
  64. return SparseSetValTraits<ValueT>::getValIndex(Val);
  65. }
  66. };
  67. /// SparseSetValFunctor<KeyT, KeyT> - Helper class for the common case of
  68. /// identity key/value sets.
  69. template<typename KeyT, typename KeyFunctorT>
  70. struct SparseSetValFunctor<KeyT, KeyT, KeyFunctorT> {
  71. unsigned operator()(const KeyT &Key) const {
  72. return KeyFunctorT()(Key);
  73. }
  74. };
  75. /// SparseSet - Fast set implementation for objects that can be identified by
  76. /// small unsigned keys.
  77. ///
  78. /// SparseSet allocates memory proportional to the size of the key universe, so
  79. /// it is not recommended for building composite data structures. It is useful
  80. /// for algorithms that require a single set with fast operations.
  81. ///
  82. /// Compared to DenseSet and DenseMap, SparseSet provides constant-time fast
  83. /// clear() and iteration as fast as a vector. The find(), insert(), and
  84. /// erase() operations are all constant time, and typically faster than a hash
  85. /// table. The iteration order doesn't depend on numerical key values, it only
  86. /// depends on the order of insert() and erase() operations. When no elements
  87. /// have been erased, the iteration order is the insertion order.
  88. ///
  89. /// Compared to BitVector, SparseSet<unsigned> uses 8x-40x more memory, but
  90. /// offers constant-time clear() and size() operations as well as fast
  91. /// iteration independent on the size of the universe.
  92. ///
  93. /// SparseSet contains a dense vector holding all the objects and a sparse
  94. /// array holding indexes into the dense vector. Most of the memory is used by
  95. /// the sparse array which is the size of the key universe. The SparseT
  96. /// template parameter provides a space/speed tradeoff for sets holding many
  97. /// elements.
  98. ///
  99. /// When SparseT is uint32_t, find() only touches 2 cache lines, but the sparse
  100. /// array uses 4 x Universe bytes.
  101. ///
  102. /// When SparseT is uint8_t (the default), find() touches up to 2+[N/256] cache
  103. /// lines, but the sparse array is 4x smaller. N is the number of elements in
  104. /// the set.
  105. ///
  106. /// For sets that may grow to thousands of elements, SparseT should be set to
  107. /// uint16_t or uint32_t.
  108. ///
  109. /// @tparam ValueT The type of objects in the set.
  110. /// @tparam KeyFunctorT A functor that computes an unsigned index from KeyT.
  111. /// @tparam SparseT An unsigned integer type. See above.
  112. ///
  113. template<typename ValueT,
  114. typename KeyFunctorT = identity<unsigned>,
  115. typename SparseT = uint8_t>
  116. class SparseSet {
  117. static_assert(std::numeric_limits<SparseT>::is_integer &&
  118. !std::numeric_limits<SparseT>::is_signed,
  119. "SparseT must be an unsigned integer type");
  120. using KeyT = typename KeyFunctorT::argument_type;
  121. using DenseT = SmallVector<ValueT, 8>;
  122. using size_type = unsigned;
  123. DenseT Dense;
  124. SparseT *Sparse = nullptr;
  125. unsigned Universe = 0;
  126. KeyFunctorT KeyIndexOf;
  127. SparseSetValFunctor<KeyT, ValueT, KeyFunctorT> ValIndexOf;
  128. public:
  129. using value_type = ValueT;
  130. using reference = ValueT &;
  131. using const_reference = const ValueT &;
  132. using pointer = ValueT *;
  133. using const_pointer = const ValueT *;
  134. SparseSet() = default;
  135. SparseSet(const SparseSet &) = delete;
  136. SparseSet &operator=(const SparseSet &) = delete;
  137. ~SparseSet() { free(Sparse); }
  138. /// setUniverse - Set the universe size which determines the largest key the
  139. /// set can hold. The universe must be sized before any elements can be
  140. /// added.
  141. ///
  142. /// @param U Universe size. All object keys must be less than U.
  143. ///
  144. void setUniverse(unsigned U) {
  145. // It's not hard to resize the universe on a non-empty set, but it doesn't
  146. // seem like a likely use case, so we can add that code when we need it.
  147. assert(empty() && "Can only resize universe on an empty map");
  148. // Hysteresis prevents needless reallocations.
  149. if (U >= Universe/4 && U <= Universe)
  150. return;
  151. free(Sparse);
  152. // The Sparse array doesn't actually need to be initialized, so malloc
  153. // would be enough here, but that will cause tools like valgrind to
  154. // complain about branching on uninitialized data.
  155. Sparse = static_cast<SparseT*>(safe_calloc(U, sizeof(SparseT)));
  156. Universe = U;
  157. }
  158. // Import trivial vector stuff from DenseT.
  159. using iterator = typename DenseT::iterator;
  160. using const_iterator = typename DenseT::const_iterator;
  161. const_iterator begin() const { return Dense.begin(); }
  162. const_iterator end() const { return Dense.end(); }
  163. iterator begin() { return Dense.begin(); }
  164. iterator end() { return Dense.end(); }
  165. /// empty - Returns true if the set is empty.
  166. ///
  167. /// This is not the same as BitVector::empty().
  168. ///
  169. bool empty() const { return Dense.empty(); }
  170. /// size - Returns the number of elements in the set.
  171. ///
  172. /// This is not the same as BitVector::size() which returns the size of the
  173. /// universe.
  174. ///
  175. size_type size() const { return Dense.size(); }
  176. /// clear - Clears the set. This is a very fast constant time operation.
  177. ///
  178. void clear() {
  179. // Sparse does not need to be cleared, see find().
  180. Dense.clear();
  181. }
  182. /// findIndex - Find an element by its index.
  183. ///
  184. /// @param Idx A valid index to find.
  185. /// @returns An iterator to the element identified by key, or end().
  186. ///
  187. iterator findIndex(unsigned Idx) {
  188. assert(Idx < Universe && "Key out of range");
  189. const unsigned Stride = std::numeric_limits<SparseT>::max() + 1u;
  190. for (unsigned i = Sparse[Idx], e = size(); i < e; i += Stride) {
  191. const unsigned FoundIdx = ValIndexOf(Dense[i]);
  192. assert(FoundIdx < Universe && "Invalid key in set. Did object mutate?");
  193. if (Idx == FoundIdx)
  194. return begin() + i;
  195. // Stride is 0 when SparseT >= unsigned. We don't need to loop.
  196. if (!Stride)
  197. break;
  198. }
  199. return end();
  200. }
  201. /// find - Find an element by its key.
  202. ///
  203. /// @param Key A valid key to find.
  204. /// @returns An iterator to the element identified by key, or end().
  205. ///
  206. iterator find(const KeyT &Key) {
  207. return findIndex(KeyIndexOf(Key));
  208. }
  209. const_iterator find(const KeyT &Key) const {
  210. return const_cast<SparseSet*>(this)->findIndex(KeyIndexOf(Key));
  211. }
  212. /// Check if the set contains the given \c Key.
  213. ///
  214. /// @param Key A valid key to find.
  215. bool contains(const KeyT &Key) const { return find(Key) == end() ? 0 : 1; }
  216. /// count - Returns 1 if this set contains an element identified by Key,
  217. /// 0 otherwise.
  218. ///
  219. size_type count(const KeyT &Key) const { return contains(Key) ? 1 : 0; }
  220. /// insert - Attempts to insert a new element.
  221. ///
  222. /// If Val is successfully inserted, return (I, true), where I is an iterator
  223. /// pointing to the newly inserted element.
  224. ///
  225. /// If the set already contains an element with the same key as Val, return
  226. /// (I, false), where I is an iterator pointing to the existing element.
  227. ///
  228. /// Insertion invalidates all iterators.
  229. ///
  230. std::pair<iterator, bool> insert(const ValueT &Val) {
  231. unsigned Idx = ValIndexOf(Val);
  232. iterator I = findIndex(Idx);
  233. if (I != end())
  234. return std::make_pair(I, false);
  235. Sparse[Idx] = size();
  236. Dense.push_back(Val);
  237. return std::make_pair(end() - 1, true);
  238. }
  239. /// array subscript - If an element already exists with this key, return it.
  240. /// Otherwise, automatically construct a new value from Key, insert it,
  241. /// and return the newly inserted element.
  242. ValueT &operator[](const KeyT &Key) {
  243. return *insert(ValueT(Key)).first;
  244. }
  245. ValueT pop_back_val() {
  246. // Sparse does not need to be cleared, see find().
  247. return Dense.pop_back_val();
  248. }
  249. /// erase - Erases an existing element identified by a valid iterator.
  250. ///
  251. /// This invalidates all iterators, but erase() returns an iterator pointing
  252. /// to the next element. This makes it possible to erase selected elements
  253. /// while iterating over the set:
  254. ///
  255. /// for (SparseSet::iterator I = Set.begin(); I != Set.end();)
  256. /// if (test(*I))
  257. /// I = Set.erase(I);
  258. /// else
  259. /// ++I;
  260. ///
  261. /// Note that end() changes when elements are erased, unlike std::list.
  262. ///
  263. iterator erase(iterator I) {
  264. assert(unsigned(I - begin()) < size() && "Invalid iterator");
  265. if (I != end() - 1) {
  266. *I = Dense.back();
  267. unsigned BackIdx = ValIndexOf(Dense.back());
  268. assert(BackIdx < Universe && "Invalid key in set. Did object mutate?");
  269. Sparse[BackIdx] = I - begin();
  270. }
  271. // This depends on SmallVector::pop_back() not invalidating iterators.
  272. // std::vector::pop_back() doesn't give that guarantee.
  273. Dense.pop_back();
  274. return I;
  275. }
  276. /// erase - Erases an element identified by Key, if it exists.
  277. ///
  278. /// @param Key The key identifying the element to erase.
  279. /// @returns True when an element was erased, false if no element was found.
  280. ///
  281. bool erase(const KeyT &Key) {
  282. iterator I = find(Key);
  283. if (I == end())
  284. return false;
  285. erase(I);
  286. return true;
  287. }
  288. };
  289. } // end namespace llvm
  290. #endif // LLVM_ADT_SPARSESET_H