1 /*---------------------------------------------------------------------------*
2 Project: Horizon
3 File: rdt_RingBuffer.cpp
4
5 Copyright (C)2009-2012 Nintendo Co., Ltd. All rights reserved.
6
7 These coded instructions, statements, and computer programs contain
8 proprietary information of Nintendo of America Inc. and/or Nintendo
9 Company Ltd., and are protected by Federal copyright law. They may
10 not be disclosed to third parties or copied or duplicated in any form,
11 in whole or in part, without the prior written consent of Nintendo.
12
13 $Rev: 46347 $
14 *---------------------------------------------------------------------------*/
15
16 #include "stdafx.h"
17
18 #include "rdt_RingBuffer.h"
19
20 #include "rdt_Stopwatch.h"
21
22 #include "Test.h"
23
24
25 #include <string.h>
26
27
28 namespace
29 {
30
31 } // End of anonymous namespace
32
33 namespace nn { namespace rdt { namespace CTR {
34
35 //
RingBuffer(void)36 RingBuffer::RingBuffer(void)
37 :m_initialized(false)
38 {
39 }
40
41
42 //
RingBuffer(void * pBuf,size_t len)43 RingBuffer::RingBuffer(void *pBuf, size_t len)
44 {
45 Initialize(pBuf, len);
46 }
47
48
49 //
~RingBuffer(void)50 RingBuffer::~RingBuffer(void)
51 {
52 if(m_initialized)
53 {
54 Finalize();
55 }
56 }
57
58
Initialize(void * pBuf,size_t len)59 void RingBuffer::Initialize(void *pBuf, size_t len)
60 {
61 ASSERT(pBuf!=NULL);
62 ASSERT(len > 0);
63
64 m_pHeadBuffer = static_cast<u8*>(pBuf);
65 m_bufLength = len;
66 m_pHeadData = m_pHeadBuffer;
67 m_dataLength = 0;
68
69 m_initialized = true;
70 }
71
72
Finalize(void)73 void RingBuffer::Finalize(void)
74 {
75 m_initialized = false;
76 }
77
78
Pop(size_t n)79 void RingBuffer::Pop(size_t n)
80 {
81 ASSERT(m_initialized);
82
83 WARNINGMSG(n > 0, "Argument is not positive number. Do nothing.\n");
84
85 if(n > 0)
86 {
87 size_t len = min(n, m_dataLength);
88 ASSERT((0<len) && (len<=m_dataLength));
89
90 u8 *p = m_pHeadData += n;
91 if(p >= getEndOfBuffer())
92 {
93 m_pHeadData = p - m_bufLength;
94 }
95 else
96 {
97 m_pHeadData = p;
98 }
99 ASSERT(isValidAddress(m_pHeadData));
100
101 m_dataLength -= len;
102 ASSERT((0<=len) && (len<=m_bufLength));
103 }
104 }
105
106
Push(const void * pBuf,size_t n)107 bool RingBuffer::Push(const void *pBuf, size_t n)
108 {
109 ASSERT(m_initialized);
110
111 // TODO. Is n=0 a problem?
112 if(n <= 0)
113 {
114 PANIC("Size of buffer is not positive number.(n=%d)\n", n);
115 return false;
116 }
117
118 if(m_dataLength + n > m_bufLength)
119 {
120 // Cannot fit in buffer.
121 return false;
122 }
123 else
124 {
125 static detail::Stopwatch s_sw("memcpy() in RingBuffer::Push()");
126 s_sw.Start();
127
128 // 01234567
129 u8 *dst = getEndOfData();
130 if(dst + n > getEndOfBuffer())
131 {
132 // Case of data overflow.
133 // The overflow is written to the start of the buffer.
134 size_t n1 = getEndOfBuffer() - dst;
135 size_t n2 = n - n1;
136 memcpy(dst, pBuf, n1);
137 memcpy(getHeadOfBuffer(), static_cast<const u8*>(pBuf)+n1, n2);
138 }
139 else
140 {
141 memcpy(dst, pBuf, n);
142 }
143 s_sw.Stop();
144
145 m_dataLength += n;
146 return true;
147 }
148 }
149
150
Read(void * pBuf,size_t n) const151 size_t RingBuffer::Read(void *pBuf, size_t n) const
152 {
153 ASSERT(pBuf!=NULL);
154 ASSERT(n > 0);
155
156 return read(pBuf, n, 0);
157 }
158
159
Read(void * pBuf,size_t n,size_t offset) const160 size_t RingBuffer::Read(void *pBuf, size_t n, size_t offset) const
161 {
162 ASSERT(pBuf!=NULL);
163 ASSERT(n > 0);
164 ASSERT((0 <= offset) && (offset < m_bufLength));
165
166 return read(pBuf, n, offset);
167 }
168
169
read(void * pBuf,size_t n,size_t offset) const170 size_t RingBuffer::read(void *pBuf, size_t n, size_t offset) const
171 {
172 ASSERT(m_initialized);
173 ASSERT(n > 0);
174 ASSERT((0 <= offset) && (offset < m_bufLength));
175
176 if(offset >= m_dataLength)
177 {
178 // The offset is larger than the data length and cannot be read.
179 return 0;
180 }
181
182 // Calculate the number of bytes to be read.
183 // Even if a large n is passed, it is corrected to the length of the existing data.
184 size_t len = min(m_dataLength - offset, n);
185
186 // Calculate the position to start the read. This also prevents a buffer overflow.
187 u8 *from = m_pHeadData + offset;
188 if(from >= getEndOfBuffer())
189 {
190 from = from - m_bufLength;
191 }
192 ASSERT(isValidAddress(from));
193
194 if(from + len <= getEndOfBuffer())
195 {
196 // When copy does not have to be divided into two parts
197 memcpy(pBuf, from, len);
198 }
199 else
200 {
201 // When copy is divided into two parts because the data to be read straddles the ring buffer boundary
202 //
203 size_t len1 = getEndOfBuffer() - from;
204 size_t len2 = len - len1;
205 memcpy(pBuf, from, len1);
206 memcpy(static_cast<u8*>(pBuf) + len1, getHeadOfBuffer(), len2);
207 }
208
209 return len;
210 }
211
212
213 // Returns the address of the location where the data is to be written next.
getEndOfData(void) const214 u8* RingBuffer::getEndOfData(void) const
215 {
216 u8 *ret = m_pHeadData + m_dataLength;
217 if(ret < getEndOfBuffer())
218 {
219 // Because the data does not extend beyond the buffer, you do not need to modify the ret.
220 }
221 else
222 {
223 ret -= m_bufLength;
224 }
225
226 ASSERT(isValidAddress(ret));
227
228 return ret;
229 }
230
231
232 #ifdef _WIN32
Test(void)233 void RingBuffer::Test(void)
234 {
235 const int BUFSIZE = 8;
236 u8 buffer[BUFSIZE];
237
238 RingBuffer r(buffer, BUFSIZE);
239
240 CU_ASSERT(r.IsEmpty()); // If just created, should be empty.
241
242 CU_ASSERT(r.Push("ABC", 3));
243 CU_ASSERT(!r.IsEmpty());
244 r.Pop(3);
245 CU_ASSERT(r.IsEmpty());
246
247 {
248 r.Clear();
249 const char *msg = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
250 CU_ASSERT(!r.Push(msg, strlen(msg))); // Push of long character strings must fail
251 }
252
253 {
254 r.Clear();
255 CU_ASSERT(r.Push("ABCD", 4));
256 CU_ASSERT(r.GetDataSize()==4);
257 CU_ASSERT(r.Push("EFGH", 4));
258 CU_ASSERT(r.GetDataSize()==8);
259 CU_ASSERT(!(r.Push("XYZ", 3))); // Does not fit
260 char msgBuf[32];
261 CU_ASSERT(r.Read(msgBuf, 32)==8); // 8 characters, should be able to be read
262 CU_ASSERT(strncmp(msgBuf, "ABCDEFGH", 8)==0);
263
264 r.Pop(2);
265 CU_ASSERT(r.GetDataSize()==6);
266 CU_ASSERT(r.Read(msgBuf, 32)==6);
267 CU_ASSERT(strncmp(msgBuf, "CDEFGH", 6)==0);
268
269 r.Pop(2);
270 CU_ASSERT(r.GetDataSize()==4);
271 CU_ASSERT(r.Push("IJKL", 4));
272 CU_ASSERT(r.GetDataSize()==8);
273 CU_ASSERT(r.Read(msgBuf, 32)==8);
274 CU_ASSERT(strncmp(msgBuf, "EFGHIJKL", 8)==0);
275
276 r.Pop(3);
277 CU_ASSERT(r.GetDataSize()==5);
278 r.Pop(5);
279 CU_ASSERT(r.GetDataSize()==0);
280 CU_ASSERT(r.IsEmpty());
281
282 CU_ASSERT(r.Push("M", 1));
283 CU_ASSERT(r.Push("N", 1));
284 CU_ASSERT(r.GetDataSize()==2);
285 CU_ASSERT(r.Push("O", 1));
286 CU_ASSERT(r.Push("P", 1));
287 CU_ASSERT(r.Push("Q", 1));
288 CU_ASSERT(r.GetDataSize()==5);
289 CU_ASSERT(r.Push("R", 1));
290 CU_ASSERT(r.Push("S", 1));
291 CU_ASSERT(r.Push("T", 1));
292 CU_ASSERT(r.GetDataSize()==8);
293 CU_ASSERT(!r.Push("Z", 1));
294 CU_ASSERT(!r.Push("Z", 1));
295
296 r.Pop(1);
297 CU_ASSERT(r.GetDataSize()==7);
298 CU_ASSERT(r.Push("U", 1));
299 r.Pop(2);
300 CU_ASSERT(r.GetDataSize()==6);
301 CU_ASSERT(r.Push("VW", 2));
302 CU_ASSERT(r.Read(msgBuf, 7)==7);
303 CU_ASSERT(strncmp(msgBuf, "PQRSTUV", 7)==0);
304 CU_ASSERT(r.GetDataSize()==8);
305 // r.Pop(0); // Issue WARNING
306 CU_ASSERT(r.GetDataSize()==8);
307
308 // Zero bytes read out
309 r.Pop(8);
310 CU_ASSERT(r.Read(msgBuf, 8)==0);
311 CU_ASSERT(r.IsEmpty());
312
313 // Test of a Read function with an offset.
314 CU_ASSERT(r.Push("123456", 6));
315 CU_ASSERT(!r.IsEmpty());
316 CU_ASSERT(r.GetDataSize()==6);
317 CU_ASSERT(r.Read(msgBuf, 8, 4)==2);
318 CU_ASSERT(strncmp(msgBuf, "56", 2)==0);
319 r.Pop(3);
320 CU_ASSERT(r.Push("789", 3));
321 CU_ASSERT(r.GetDataSize()==6);
322 CU_ASSERT(r.Read(msgBuf, 8, 5)==1);
323 CU_ASSERT(strncmp(msgBuf, "9", 1)==0);
324 }
325 }
326 #endif // end of _WIN32
327
328
329 }}} // namespace nn::rdt::CTR
330