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:
FixedSizeQueue()32 	FixedSizeQueue() {
33 		// Allocate aligned memory, just because.
34 		//int sizeInBytes = N * sizeof(T);
35 		//storage_ = (T *)AllocateMemoryPages(sizeInBytes);
36 		storage_ = new T[N];
37 		clear();
38 	}
39 
~FixedSizeQueue()40 	~FixedSizeQueue() {
41 		// FreeMemoryPages((void *)storage_, N * sizeof(T));
42 		delete [] storage_;
43 	}
44 
clear()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 
push(T t)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.
pushPointers(size_t size,T ** dest1,size_t * sz1,T ** dest2,size_t * sz2)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 
popPointers(size_t size,const T ** src1,size_t * sz1,const T ** src2,size_t * sz2)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 
pop()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 
pop_front()122 	T pop_front() {
123 		const T &temp = storage_[head_];
124 		pop();
125 		return temp;
126 	}
127 
front()128 	T &front() { return storage_[head_]; }
129 
front()130 	const T &front() const { return storage_[head_]; }
131 
size()132 	size_t size() const {
133 		return count_;
134 	}
135 
capacity()136 	size_t capacity() const {
137 		return N;
138 	}
139 
room()140 	int room() const {
141 		return N - count_;
142 	}
143 
empty()144 	bool empty() {
145 		return count_ == 0;
146 	}
147 
DoState(PointerWrap & p)148 	void DoState(PointerWrap &p) {
149 		int size = N;
150 		Do(p, size);
151 		if (size != N)
152 		{
153 			ERROR_LOG(COMMON, "Savestate failure: Incompatible queue size.");
154 			return;
155 		}
156 		DoArray<T>(p, storage_, N);
157 		Do(p, head_);
158 		Do(p, tail_);
159 		Do(p, count_);
160 		p.DoMarker("FixedSizeQueue");
161 	}
162 
163 private:
164 	T *storage_;
165 	int head_;
166 	int tail_;
167 	int count_;  // sacrifice 4 bytes for a simpler implementation. may optimize away in the future.
168 
169 	// Make copy constructor private for now.
170 	FixedSizeQueue(FixedSizeQueue &other);
171 	FixedSizeQueue& operator=(const FixedSizeQueue &other);
172 };
173 
174 
175 // I'm not sure this is 100% safe but it might be "Good Enough" :)
176 // TODO: Use this, maybe make it safer first by using proper atomics
177 // instead of volatile
178 template<class T, int blockSize, int numBlocks>
179 class LockFreeBlockQueue {
180 public:
LockFreeBlockQueue()181 	LockFreeBlockQueue() {
182 		curReadBlock = 0;
183 		curWriteBlock = 0;
184 		for (size_t i = 0; i < numBlocks; i++) {
185 			blocks[i] = new T[blockSize];
186 		}
187 	}
~LockFreeBlockQueue()188 	~LockFreeBlockQueue() {
189 		for (size_t i = 0; i < numBlocks; i++) {
190 			delete [] blocks[i];
191 		}
192 	}
193 
194 	// Write to the returned pointer then call EndPush to finish the push.
BeginPush()195 	T *BeginPush() {
196 		return blocks[curWriteBlock];
197 	}
EndPush()198 	void EndPush() {
199 		curWriteBlock++;
200 		if (curWriteBlock == NUM_BLOCKS)
201 			curWriteBlock = 0;
202 	}
203 
CanPush()204 	bool CanPush() {
205 		int nextBlock = curWriteBlock + 1;
206 		if (nextBlock == NUM_BLOCKS) nextBlock = 0;
207 		return nextBlock != curReadBlock;
208 	}
209 
CanPop()210 	bool CanPop() { return curReadBlock != curWriteBlock; }
211 
212 	// Read from the returned pointer then call EndPush to finish the pop.
BeginPop()213 	T *BeginPop() {
214 		return blocks[curReadBlock];
215 	}
EndPop()216 	void EndPop() {
217 		curReadBlock++;
218 		if (curReadBlock == NUM_BLOCKS)
219 			curReadBlock = 0;
220 	}
221 
222 private:
223 	enum { NUM_BLOCKS = 16 };
224 	T **blocks[NUM_BLOCKS];
225 
226 	volatile int curReadBlock;
227 	volatile int curWriteBlock;
228 };
229 
230