Cogs.Foundation
Loading...
Searching...
No Matches
FixedIndexQueue.h
Go to the documentation of this file.
1#pragma once
2#include "../Memory/MemoryBuffer.h"
3#include "../BitTwiddling/PowerOfTwo.h"
4
5#include <type_traits>
6#include <cassert>
7
8namespace Cogs
9{
10 namespace Collections
11 {
12
16 template<typename Element, typename IndexBaseType>
18 {
20 typedef typename std::make_signed<IndexBaseType>::type SignedIndexType;
21 public:
23 typedef typename std::make_unsigned<IndexBaseType>::type IndexType;
24
27
29 const IndexType capacity() const { return sizeMask + 1u; }
30
33 {
34 IndexType frontOffsetWrap = frontOffset & sizeMask;
35 IndexType backOffsetWrap = backOffset & sizeMask;
36 return frontOffsetWrap == backOffsetWrap;
37 }
38
41 {
42 IndexType frontOffsetWrap = frontOffset & sizeMask;
43 IndexType backOffsetWrap = backOffset & sizeMask;
44 return backOffsetWrap - frontOffsetWrap + (backOffsetWrap < frontOffsetWrap ? capacity() : static_cast<IndexType>(0));
45 }
46
48 void clear()
49 {
51 frontOffset = 0;
52 backOffset = 0;
53 }
54
56 void reset()
57 {
58 frontOffset = 0;
59 backOffset = 0;
61 }
62
64 void shrink()
65 {
66 IndexType sizeL2New = static_cast<IndexType>(roundUpToPowerOfTwoShift(count() + 1u));
67 if (sizeL2New == sizeL2) return;
68
69 resize(sizeL2New);
70 }
71
73 void pushBack(Element e)
74 {
75 if (noCapacity()) grow();
76
78 backOffset++;
79 }
80
82 void pushFront(Element e)
83 {
84 if (noCapacity()) grow();
85
88 }
89
91 void popFront()
92 {
93 if (empty()) {
94 assert(false && "queue is empty");
95 return;
96 }
98 }
99
101 Element& operator[](IndexType fixedIndex)
102 {
103 assert(empty() == false);
104 assert(0 <= static_cast<SignedIndexType>(fixedIndex - frontIndex()));
105 assert(static_cast<SignedIndexType>(fixedIndex - backIndex()) <= 0);
106 IndexType offset = fixedIndex - offsetToFixedIndexShift;
107 return storage[offset & sizeMask];
108 }
109
111 const Element& operator[](IndexType fixedIndex) const
112 {
113 assert(empty() == false);
114 assert(0 <= static_cast<SignedIndexType>(fixedIndex - frontIndex()));
115 assert(static_cast<SignedIndexType>(fixedIndex - backIndex()) <= 0);
116 IndexType offset = fixedIndex - offsetToFixedIndexShift;
117 return storage[offset & sizeMask];
118 }
119
121 Element& front() { assert(empty() == false); return storage[frontOffset & sizeMask]; }
122
124 const Element& front() const { assert(empty() == false); return storage[frontOffset & sizeMask]; }
125
127 Element& back() { assert(empty() == false); return storage[(backOffset - IndexType(1)) & sizeMask]; }
128
130 const Element& back() const { assert(empty() == false); return storage[(backOffset - IndexType(1)) & sizeMask]; }
131
133 IndexType frontIndex() const { assert(empty() == false); return frontOffset + offsetToFixedIndexShift; }
134
136 IndexType backIndex() const { assert(empty() == false); return backOffset - IndexType(1) + offsetToFixedIndexShift; }
137
139 bool validIndex(uint32_t fixedIndex) const
140 {
141 if (empty()) return false;
142 // Correct as long as distance is less than SignedIndexType::Max.
143 if (static_cast<SignedIndexType>(fixedIndex - frontIndex()) < 0) return false;
144 if (0 < static_cast<SignedIndexType>(fixedIndex - backIndex())) return false;
145 return true;
146 }
147
148 private:
149 IndexType sizeL2 = 0; // size is 1<<0 = 1.
155
157 bool noCapacity() const { return ((frontOffset & sizeMask) == ((backOffset + 1) & sizeMask)); }
158
160 void grow()
161 {
162 IndexType sizeL2New = sizeL2 + 1u;
163 IndexType sizeNew = (1u << sizeL2New);
164 assert(capacity() < sizeNew); // Check if we grow beyond domain of representation.
165 resize(sizeL2New);
166 }
167
168 void resize(IndexType sizeL2New)
169 {
170 IndexType sizeNew = 1u << sizeL2New;
171 assert(isPowerOfTwo(sizeNew));
172
173 IndexType N = count();
174 assert(N < sizeNew);
175
176 Cogs::Memory::TypedBuffer<Element> storageNew(sizeNew);
177 for (uint32_t i = 0; i < N; i++) {
178 storageNew[i] = storage[(frontOffset + i) & sizeMask];
179 }
181 frontOffset = 0;
182 backOffset = N;
183
184 sizeL2 = sizeL2New;
185 sizeMask = sizeNew - 1u;
186 storage.swap(storageNew);
187 }
188
189 };
190
191 }
192}
Indexable queue where an element index is fixed through arbitrary enqueues and dequeues.
Definition: FixedIndexQueue.h:18
void pushFront(Element e)
Adds a new element to the front of the queue.
Definition: FixedIndexQueue.h:82
IndexType count() const
Returns number of elements currently in the queue.
Definition: FixedIndexQueue.h:40
bool validIndex(uint32_t fixedIndex) const
Check if a fixed index is valid, that is, refers to an element in the queue.
Definition: FixedIndexQueue.h:139
Element & operator[](IndexType fixedIndex)
Look up an element in the queue by a fixed index.
Definition: FixedIndexQueue.h:101
void clear()
Removes all entries from the queue, but will continue with new unused indices.
Definition: FixedIndexQueue.h:48
Element & front()
Returns front element.
Definition: FixedIndexQueue.h:121
const Element & front() const
Returns front element.
Definition: FixedIndexQueue.h:124
IndexType frontOffset
Definition: FixedIndexQueue.h:151
void shrink()
Reduce capacity to the minimum needed to preserve the contents.
Definition: FixedIndexQueue.h:64
bool noCapacity() const
True if there is no free capacity left.
Definition: FixedIndexQueue.h:157
void resize(IndexType sizeL2New)
Definition: FixedIndexQueue.h:168
void pushBack(Element e)
Adds a new element to the back of the queue.
Definition: FixedIndexQueue.h:73
IndexType frontIndex() const
Returns fixed index of front.
Definition: FixedIndexQueue.h:133
void reset()
Removes all entries from the queue, recycles indices and starts from zero.
Definition: FixedIndexQueue.h:56
IndexType empty() const
Returns true if there are currently no elements in the queue.
Definition: FixedIndexQueue.h:32
const IndexType capacity() const
Returns the current capacity of the queue.
Definition: FixedIndexQueue.h:29
IndexType sizeL2
Definition: FixedIndexQueue.h:149
IndexType backOffset
Definition: FixedIndexQueue.h:152
const Element & operator[](IndexType fixedIndex) const
Look up an element in the queue by a fixed index.
Definition: FixedIndexQueue.h:111
Element & back()
Returns back element.
Definition: FixedIndexQueue.h:127
std::make_signed< IndexBaseType >::type SignedIndexType
Signed helper type.
Definition: FixedIndexQueue.h:20
IndexType offsetToFixedIndexShift
Definition: FixedIndexQueue.h:153
void grow()
Double the capacity of the queue.
Definition: FixedIndexQueue.h:160
Cogs::Memory::TypedBuffer< Element > storage
Definition: FixedIndexQueue.h:154
const Element & back() const
Returns back element.
Definition: FixedIndexQueue.h:130
IndexType sizeMask
Definition: FixedIndexQueue.h:150
void popFront()
Removes the front from the queue.
Definition: FixedIndexQueue.h:91
IndexType backIndex() const
Returns fixed index of current back element.
Definition: FixedIndexQueue.h:136
std::make_unsigned< IndexBaseType >::type IndexType
Unsigned type used for indices, typically uint32_t or uin64_t.
Definition: FixedIndexQueue.h:23
FixedIndexQueue()
Constructor.
Definition: FixedIndexQueue.h:26
Definition: MemoryBuffer.h:197
void swap(TypedBuffer &other)
Definition: MemoryBuffer.h:235
bool resize(size_t size, bool keep=true, bool forceRealloc=false)
Definition: MemoryBuffer.h:213
Main Cogs namespace.
Definition: MortonCode.h:5
bool isPowerOfTwo(T x)
Definition: PowerOfTwo.h:15
uint8_t roundUpToPowerOfTwoShift(uint8_t x)
Definition: PowerOfTwo.h:170