CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
hrydgard

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

GitHub Repository: hrydgard/ppsspp
Path: blob/master/Common/Data/Collections/FixedSizeQueue.h
Views: 1401
1
// Copyright (C) 2003 Dolphin Project.
2
3
// This program is free software: you can redistribute it and/or modify
4
// it under the terms of the GNU General Public License as published by
5
// the Free Software Foundation, version 2.0 or later versions.
6
7
// This program is distributed in the hope that it will be useful,
8
// but WITHOUT ANY WARRANTY; without even the implied warranty of
9
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
// GNU General Public License 2.0 for more details.
11
12
// A copy of the GPL 2.0 should have been included with the program.
13
// If not, see http://www.gnu.org/licenses/
14
15
// Official SVN repository and contact information can be found at
16
// http://code.google.com/p/dolphin-emu/
17
18
#pragma once
19
20
#include <cstring>
21
#include "Common/MemoryUtil.h"
22
#include "Common/Serialize/Serializer.h"
23
24
// STL-look-a-like interface, but name is mixed case to distinguish it clearly from the
25
// real STL classes.
26
27
// Not fully featured, no safety checking yet. Add features as needed.
28
29
template <class T, int N>
30
class FixedSizeQueue {
31
public:
32
FixedSizeQueue() {
33
storage_ = new T[N];
34
clear();
35
}
36
37
~FixedSizeQueue() {
38
delete [] storage_;
39
}
40
41
// Disallow copies.
42
FixedSizeQueue(FixedSizeQueue &other) = delete;
43
FixedSizeQueue& operator=(const FixedSizeQueue &other) = delete;
44
45
void clear() {
46
head_ = 0;
47
tail_ = 0;
48
count_ = 0;
49
// Not entirely necessary, but keeps things clean.
50
memset(storage_, 0, sizeof(T) * N);
51
}
52
53
void push(T t) {
54
storage_[tail_] = t;
55
tail_++;
56
if (tail_ == N)
57
tail_ = 0;
58
count_++;
59
}
60
61
// Gets pointers to write to directly.
62
void pushPointers(size_t size, T **dest1, size_t *sz1, T **dest2, size_t *sz2) {
63
if (tail_ + (int)size < N) {
64
*dest1 = &storage_[tail_];
65
*sz1 = size;
66
tail_ += (int)size;
67
if (tail_ == N) tail_ = 0;
68
*dest2 = 0;
69
*sz2 = 0;
70
} else {
71
*dest1 = &storage_[tail_];
72
*sz1 = N - tail_;
73
tail_ = (int)(size - *sz1);
74
*dest2 = &storage_[0];
75
*sz2 = tail_;
76
}
77
count_ += (int)size;
78
}
79
80
void popPointers(size_t size, const T **src1, size_t *sz1, const T **src2, size_t *sz2) {
81
if ((int)size > count_) size = count_;
82
83
if (head_ + size < N) {
84
*src1 = &storage_[head_];
85
*sz1 = size;
86
head_ += (int)size;
87
if (head_ == N) head_ = 0;
88
*src2 = 0;
89
*sz2 = 0;
90
} else {
91
*src1 = &storage_[head_];
92
*sz1 = N - head_;
93
head_ = (int)(size - *sz1);
94
*src2 = &storage_[0];
95
*sz2 = head_;
96
}
97
count_ -= (int)size;
98
}
99
100
void pop() {
101
head_++;
102
if (head_ == N)
103
head_ = 0;
104
count_--;
105
}
106
107
/*
108
void push_array(const T *ptr, size_t num) {
109
// TODO: memcpy
110
for (size_t i = 0; i < num; i++) {
111
push(ptr[i]);
112
}
113
}
114
115
void pop_array(T *outptr, size_t num) {
116
for (size_t i = 0; i < num; i++) {
117
outptr[i] = front();
118
pop();
119
}
120
}*/
121
122
T pop_front() {
123
const T &temp = storage_[head_];
124
pop();
125
return temp;
126
}
127
128
T &front() { return storage_[head_]; }
129
130
const T &front() const { return storage_[head_]; }
131
132
size_t size() const {
133
return count_;
134
}
135
136
size_t capacity() const {
137
return N;
138
}
139
140
int room() const {
141
return N - count_;
142
}
143
144
bool empty() {
145
return count_ == 0;
146
}
147
148
void DoState(PointerWrap &p) {
149
int size = N;
150
Do(p, size);
151
if (size != N)
152
{
153
ERROR_LOG(Log::Common, "Savestate failure: Incompatible queue size.");
154
return;
155
}
156
// TODO: This is quite wasteful, could just store the actual data. Would be slightly more complex though.
157
DoArray<T>(p, storage_, N);
158
Do(p, head_);
159
Do(p, tail_);
160
Do(p, count_);
161
p.DoMarker("FixedSizeQueue");
162
}
163
164
private:
165
T *storage_;
166
int head_;
167
int tail_;
168
int count_; // sacrifice 4 bytes for a simpler implementation. may optimize away in the future.
169
};
170
171
172
// I'm not sure this is 100% safe but it might be "Good Enough" :)
173
// TODO: Use this, maybe make it safer first by using proper atomics
174
// instead of volatile
175
template<class T, int blockSize, int numBlocks>
176
class LockFreeBlockQueue {
177
public:
178
LockFreeBlockQueue() {
179
curReadBlock = 0;
180
curWriteBlock = 0;
181
for (size_t i = 0; i < numBlocks; i++) {
182
blocks[i] = new T[blockSize];
183
}
184
}
185
~LockFreeBlockQueue() {
186
for (size_t i = 0; i < numBlocks; i++) {
187
delete [] blocks[i];
188
}
189
}
190
191
// Write to the returned pointer then call EndPush to finish the push.
192
T *BeginPush() {
193
return blocks[curWriteBlock];
194
}
195
void EndPush() {
196
curWriteBlock++;
197
if (curWriteBlock == NUM_BLOCKS)
198
curWriteBlock = 0;
199
}
200
201
bool CanPush() {
202
int nextBlock = curWriteBlock + 1;
203
if (nextBlock == NUM_BLOCKS) nextBlock = 0;
204
return nextBlock != curReadBlock;
205
}
206
207
bool CanPop() { return curReadBlock != curWriteBlock; }
208
209
// Read from the returned pointer then call EndPush to finish the pop.
210
T *BeginPop() {
211
return blocks[curReadBlock];
212
}
213
void EndPop() {
214
curReadBlock++;
215
if (curReadBlock == NUM_BLOCKS)
216
curReadBlock = 0;
217
}
218
219
private:
220
enum { NUM_BLOCKS = 16 };
221
T **blocks[NUM_BLOCKS];
222
223
volatile int curReadBlock;
224
volatile int curWriteBlock;
225
};
226
227