uLib  User mode C/C++ extended API library for Win32 programmers.
RingBuffer.cpp
Go to the documentation of this file.
1 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2 // Project: uLib - User mode library.
3 // Module: RingBuffer -- A simple circular FIFO data buffer.
4 // Author: Copyright (c) Love Nystrom
5 // License: NNOSL (BSD descendant, see NNOSL.txt in the base directory).
6 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
7 
8 #include <uLib\RingBuffer.h>
9 #include <uLib\MemFunc.h>
10 #include <uLib\Debug.h>
11 #include <memory.h>
12 
13 #define RINGBUF_BURST_XFER 1
14 
15 RingBuffer::RingBuffer( PBYTE Array, UINT Size )
16 {
17  UserData = NULL;
18  Attach( Array, Size );
19  _dyna = false;
20 }
21 
23 {
24  UserData = NULL;
25  PBYTE buf = (PBYTE) mem_Alloc( Size );
26  _dyna = (buf != NULL);
27  if (!_dyna) Size = 0;
28  Attach( buf, Size );
29 }
30 
32 {
33  if (_dyna) mem_Free( _buffer );
34 }
35 
36 void RingBuffer::Attach( PBYTE Array, UINT Size )
37 {
38  _buffer = Array;
39  _size = Size;
40  _head = _tail = 0; // _head == _tail means the buffer is *empty OR full*!
41  _full = false;
42 }
43 
44 bool RingBuffer::Get( BYTE* Data )
45 {
46  bool ok = !Empty();
47  if ( ok )
48  {
49  *Data = *(_buffer + _tail);
50  if (++_tail >= _size) _tail = 0;
51  _full = false;
52  }
53  return ok;
54 }
55 
56 bool RingBuffer::Put( BYTE Data )
57 {
58  bool ok = !_full;
59  if ( ok )
60  {
61  *(_buffer + _head) = Data;
62  if (++_head >= _size) _head = 0;
63  if (_head == _tail) _full = true;
64  }
65  return ok;
66 }
67 
68 #if !RINGBUF_BURST_XFER // One by one slug transfer...
69 
70 bool RingBuffer::PutBlock( BYTE* Data, UINT Count )
71 {
72  bool ok = (Unused() >= Count);
73  if (ok) {
74  while( Count-- ) Put( *Data++ );
75  }
76  return ok;
77 }
78 
79 bool RingBuffer::GetBlock( BYTE* Data, UINT Count )
80 {
81  bool ok = (Used() >= Count); // Enough stored ?
82  if ( ok )
83  {
84  while( Count-- ) Get( Data++ );
85  }
86  return ok;
87 }
88 
89 #else // Burst transfer - Beta
90 
91 bool RingBuffer::PutBlock( BYTE* Data, UINT Count )
92 {
93  bool ok = (Unused() >= Count);
94  if ( ok )
95  {
96  if (_head + Count <= _size) // One burst
97  {
98  memcpy( _buffer + _head, Data, Count );
99  _head += Count;
100  }
101  else // Split insertion in two bursts
102  {
103  UINT nfirst = _size - _head;
104  UINT nsecond = Count - nfirst;
105  if ( nfirst ) memcpy( _buffer + _head, Data, nfirst );
106  if ( nsecond ) memcpy( _buffer, Data + nfirst, nsecond );
107  _head = nsecond;
108  }
109  IF_DEBUG( if (_head > _size) __debugbreak() );
110  if (_head == _size) _head = 0;
111  int diff = _head - _tail; // Check if buffer is full..
112  if (diff < 0) diff += _size; // unwrap..
113  if (!diff || (diff == (int)_size)) _full = true;
114  }
115  return ok;
116 }
117 
118 bool RingBuffer::GetBlock( BYTE* Data, UINT Count )
119 {
120  bool ok = (Used() >= Count); // Enough stored ?
121  if ( ok )
122  {
123  if (_tail + Count <= _size) // One burst
124  {
125  memcpy( Data, _buffer + _tail, Count );
126  _tail += Count;
127  }
128  else // Split withdrawal in two bursts
129  {
130  UINT nfirst = _size - _tail;
131  UINT nsecond = Count - nfirst;
132  if ( nfirst ) memcpy( Data, _buffer + _tail, nfirst );
133  if ( nsecond ) memcpy( Data + nfirst, _buffer, nsecond );
134  _tail = nsecond;
135  }
136  IF_DEBUG( if (_tail > _size) __debugbreak() );
137  if (_tail == _size) _tail = 0;
138  _full = false;
139  }
140  return ok;
141 }
142 
143 #endif // RINGBUF_BURST_XFER
144 
145 bool RingBuffer::GetStr( ASTR Buf, UINT BufSize )
146 {
147  UINT strLen = 0;
148  UINT start = _tail;
149  UINT offs = _tail;
150  while( *(_buffer + offs) != 0 )
151  {
152  strLen++;
153  if (++offs >= _size) offs = 0;
154  if (offs == start) return false; // No NUL terminator found.
155  }
156  strLen++; // Include NUL terminator
157  bool ok = (BufSize >= strLen);
158  if (ok) GetBlock( (PBYTE)Buf, strLen );
159  else
160  {
161  ok = GetBlock( (PBYTE)Buf, BufSize-1 );
162  Buf[ BufSize-1 ] = 0; // NUL terminate clipped string.
163  TRACE( DP_WARNING, _F("Clipping: strLen=%lu, BufSize=%lu\n"), strLen, BufSize );
164  Discard( strLen-BufSize );
165  }
166  return ok;
167 }
168 
169 bool RingBuffer::PutStr( ACSTR Str, UINT StrLen )
170 {
171  bool counted = (StrLen != 0);
172  if (!counted) StrLen = (UINT) strlen( Str );
173  bool ok = (Unused() > StrLen);
174  if (ok)
175  {
176  UINT length = counted ? StrLen : StrLen+1;
177  PutBlock( (PBYTE)Str, length );
178  if (counted && (Str[ length-1 ] != 0)) Put( 0 ); // Add NUL terminator
179  }
180  return ok;
181 }
182 
184 {
185  _full = false;
186  _head = _tail = 0;
187 }
188 
189 void RingBuffer::Discard( UINT Count )
190 {
191  if ( Count )
192  {
193  UINT avail = Used(); // Stored amount
194  if (Count >= avail) Clear();
195  else
196  {
197  _tail += Count;
198  _tail %= _size;
199  _full = false;
200  }
201  }
202 }
203 
205 {
206  if ( _full ) return _size;
207  INT count = _head - _tail;
208  if (count < 0) count += _size;
209  return count;
210 }
211 
213 {
214  return _size - Used();
215 }
216 
218 {
219  return ((_tail == _head) && !_full);
220 }
221 
223 {
224  if (Empty() || Index >= Used()) // If Index out of bounds..
225  {
226  #if 0
227  RaiseException( EXCEPTION_ARRAY_BOUNDS_EXCEEDED, 0, 0, NULL ); // Generic
228  #else
229  ULONG_PTR info[ 2 ] = { (ULONG_PTR) this, Index }; // Just because we can.. ;)
230  RaiseException( EXCEPTION_RINGBUFFER_INVALID_INDEX, 0, 2, info ); // Specific
231  #endif
232  }
233  Index += _tail;
234  Index %= _size;
235  return _buffer[ Index ];
236 }
237 
238 // EOF
PVOID UserData
Definition: RingBuffer.h:36
const char * ACSTR
Definition: Common.h:345
#define IF_DEBUG(code)
Definition: Debug.h:236
void Attach(PBYTE Array, UINT Size)
Definition: RingBuffer.cpp:36
BYTE & operator[](UINT Index)
Definition: RingBuffer.cpp:222
bool GetStr(ASTR Buf, UINT BufLen)
Definition: RingBuffer.cpp:145
void * mem_Alloc(size_t Bytes)
Definition: MemFunc.cpp:33
unsigned char * PBYTE
Definition: Common.h:412
char * ASTR
Definition: Common.h:344
bool PutBlock(BYTE *Data, UINT nBytes)
Definition: RingBuffer.cpp:91
bool PutStr(ACSTR Str, UINT Len=0)
Definition: RingBuffer.cpp:169
#define TRACE(_lvl,...)
Definition: Debug.h:216
RingBuffer(PBYTE Array, UINT Size)
Definition: RingBuffer.cpp:15
UINT Unused()
Definition: RingBuffer.cpp:212
UINT Size()
Definition: RingBuffer.h:54
UINT Used()
Definition: RingBuffer.cpp:204
void * mem_Free(void *pBlk)
Definition: MemFunc.cpp:124
Debug and error handling support.
void Clear()
Definition: RingBuffer.cpp:183
bool GetBlock(BYTE *Data, UINT nBytes)
Definition: RingBuffer.cpp:118
bool Put(BYTE Data)
Definition: RingBuffer.cpp:56
#define _F(s)
Definition: Debug.h:49
#define EXCEPTION_RINGBUFFER_INVALID_INDEX
Definition: RingBuffer.h:115
void Discard(UINT nBytes)
Definition: RingBuffer.cpp:189
bool Get(BYTE *Data)
Definition: RingBuffer.cpp:44
#define DP_WARNING
Definition: Debug.h:83
unsigned char BYTE
Definition: Common.h:412
bool Empty()
Definition: RingBuffer.cpp:217