21#ifndef LLVM_ADT_SPARSEMULTISET_H
22#define LLVM_ADT_SPARSEMULTISET_H
84 typename KeyFunctorT = identity<unsigned>,
85 typename SparseT = uint8_t>
87 static_assert(std::is_unsigned_v<SparseT>,
88 "SparseT must be an unsigned integer type");
97 static constexpr unsigned INVALID = ~0U;
103 SMSNode(
ValueT D,
unsigned P,
unsigned N) : Data(
D), Prev(
P), Next(
N) {}
106 bool isTail()
const {
107 return Next == INVALID;
111 bool isTombstone()
const {
112 return Prev == INVALID;
117 bool isValid()
const {
return Prev != INVALID; }
120 using KeyT =
typename KeyFunctorT::argument_type;
123 SparseT *Sparse =
nullptr;
124 unsigned Universe = 0;
125 KeyFunctorT KeyIndexOf;
131 unsigned FreelistIdx = SMSNode::INVALID;
132 unsigned NumFree = 0;
134 unsigned sparseIndex(
const ValueT &Val)
const {
135 assert(ValIndexOf(Val) < Universe &&
136 "Invalid key in set. Did object mutate?");
137 return ValIndexOf(Val);
139 unsigned sparseIndex(
const SMSNode &
N)
const {
return sparseIndex(
N.Data); }
144 bool isHead(
const SMSNode &
D)
const {
145 assert(
D.isValid() &&
"Invalid node for head");
146 return Dense[
D.Prev].isTail();
151 bool isSingleton(
const SMSNode &
N)
const {
152 assert(
N.isValid() &&
"Invalid node for singleton");
159 unsigned addValue(
const ValueT& V,
unsigned Prev,
unsigned Next) {
161 Dense.push_back(SMSNode(V, Prev, Next));
162 return Dense.size() - 1;
166 unsigned Idx = FreelistIdx;
167 unsigned NextFree =
Dense[
Idx].Next;
170 Dense[
Idx] = SMSNode(V, Prev, Next);
171 FreelistIdx = NextFree;
177 void makeTombstone(
unsigned Idx) {
205 assert(
empty() &&
"Can only resize universe on an empty map");
207 if (U >= Universe/4 && U <= Universe)
213 Sparse =
static_cast<SparseT*
>(
safe_calloc(U,
sizeof(SparseT)));
235 : SMS(
P),
Idx(
I), SparseIdx(
SI) {}
239 if (
Idx == SMSNode::INVALID)
242 assert(Idx < SMS->
Dense.size() &&
"Out of range, non-INVALID Idx?");
247 bool isKeyed()
const {
return SparseIdx < SMS->Universe; }
249 unsigned Prev()
const {
return SMS->Dense[
Idx].Prev; }
250 unsigned Next()
const {
return SMS->Dense[
Idx].Next; }
252 void setPrev(
unsigned P) { SMS->Dense[
Idx].Prev =
P; }
253 void setNext(
unsigned N) { SMS->Dense[
Idx].Next =
N; }
257 assert(isKeyed() && SMS->sparseIndex(SMS->Dense[
Idx].Data) == SparseIdx &&
258 "Dereferencing iterator of invalid key or index");
260 return SMS->Dense[
Idx].Data;
268 assert((isEnd() || SparseIdx ==
RHS.SparseIdx) &&
269 "Same dense entry, but different keys?");
282 assert(isKeyed() &&
"Decrementing an invalid iterator");
283 assert((isEnd() || !SMS->isHead(SMS->Dense[
Idx])) &&
284 "Decrementing head of list");
288 Idx = SMS->findIndex(SparseIdx).Prev();
295 assert(!isEnd() && isKeyed() &&
"Incrementing an invalid/end iterator");
336 assert(NumFree <=
Dense.size() &&
"Out-of-bounds free entries");
337 return Dense.size() - NumFree;
346 FreelistIdx = SMSNode::INVALID;
355 assert(
Idx < Universe &&
"Key out of range");
356 const unsigned Stride = std::numeric_limits<SparseT>::max() + 1u;
357 for (
unsigned i = Sparse[
Idx], e =
Dense.size(); i < e; i += Stride) {
358 const unsigned FoundIdx = sparseIndex(
Dense[i]);
404 I =
iterator(
this,
I.Prev(), KeyIndexOf(Key));
414 return std::make_pair(
B,
E);
420 unsigned Idx = sparseIndex(Val);
423 unsigned NodeIdx = addValue(Val, SMSNode::INVALID, SMSNode::INVALID);
427 Sparse[
Idx] = NodeIdx;
428 Dense[NodeIdx].Prev = NodeIdx;
433 unsigned HeadIdx =
I.Idx;
434 unsigned TailIdx =
I.Prev();
435 Dense[TailIdx].Next = NodeIdx;
436 Dense[HeadIdx].Prev = NodeIdx;
437 Dense[NodeIdx].Prev = TailIdx;
467 assert(
I.isKeyed() && !
I.isEnd() && !
Dense[
I.Idx].isTombstone() &&
468 "erasing invalid/end/tombstone iterator");
475 makeTombstone(
I.Idx);
490 if (isSingleton(
N)) {
492 assert(
N.Next == SMSNode::INVALID &&
"Singleton has next?");
493 return iterator(
this, SMSNode::INVALID, ValIndexOf(
N.Data));
498 Sparse[sparseIndex(
N)] =
N.Next;
499 Dense[
N.Next].Prev =
N.Prev;
500 return iterator(
this,
N.Next, ValIndexOf(
N.Data));
516 return iterator(
this,
N.Next, ValIndexOf(
N.Data));
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static GCRegistry::Add< StatepointGC > D("statepoint-example", "an example strategy for statepoint")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
Returns the sub type a function will return at a given Idx Should correspond to the result type of an ExtractValue instruction executed with just that one unsigned Idx
StandardInstrumentations SI(Mod->getContext(), Debug, VerifyEach)
static bool isValid(const char C)
Returns true if C is a valid mangled character: <0-9a-zA-Z_>.
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
This file defines the SmallVector class.
This file defines the SparseSet class derived from the version described in Briggs,...
Our iterators are iterators over the collection of objects that share a key.
iterator_base operator++(int)
bool operator!=(const iterator_base &RHS) const
pointer operator->() const
std::bidirectional_iterator_tag iterator_category
reference operator*() const
iterator_base & operator++()
iterator_base & operator--()
Increment and decrement operators.
bool operator==(const iterator_base &RHS) const
Comparison operators.
iterator_base operator--(int)
std::ptrdiff_t difference_type
Fast multiset implementation for objects that can be identified by small unsigned keys.
iterator find(const KeyT &Key)
Find an element by its key.
bool empty() const
Returns true if the set is empty.
iterator_base< const SparseMultiSet * > const_iterator
bool contains(const KeyT &Key) const
Returns true if this set contains an element identified by Key.
iterator findIndex(unsigned Idx)
Find an element by its index.
void clear()
Clears the set.
iterator erase(iterator I)
Erases an existing element identified by a valid iterator.
size_type size() const
Returns the number of elements in the set.
iterator end()
Returns an iterator past this container.
const_iterator find(const KeyT &Key) const
size_type count(const KeyT &Key) const
Returns the number of elements identified by Key.
iterator insert(const ValueT &Val)
Insert a new element at the tail of the subset list.
SparseMultiSet(const SparseMultiSet &)=delete
iterator getHead(const KeyT &Key)
Return the head and tail of the subset's list, otherwise returns end().
const_iterator end() const
iterator getTail(const KeyT &Key)
SparseMultiSet & operator=(const SparseMultiSet &)=delete
void eraseAll(const KeyT &K)
Erase all elements with the given key.
RangePair equal_range(const KeyT &K)
The bounds of the range of items sharing Key K.
iterator_base< SparseMultiSet * > iterator
std::pair< iterator, iterator > RangePair
void setUniverse(unsigned U)
Set the universe size which determines the largest key the set can hold.
This is an optimization pass for GlobalISel generic memory operations.
LLVM_ATTRIBUTE_RETURNS_NONNULL void * safe_calloc(size_t Count, size_t Sz)
SparseSetValFunctor - Helper class for selecting SparseSetValTraits.