Tezzeret  1
Tezzeret
GmArrayRingBuffer.hpp
1 
2 #ifndef GMARRAYRINGBUFFER_HPP_
3 #define GMARRAYRINGBUFFER_HPP_
4 
5 /*
6  * GmArrayingBuffer.hpp
7  *
8  */
9 
10 #include <array>
11 
12 namespace Geometrics
13 {
14  // Initially, this is FIFO only.
15  // This class has no concurrency control. That must occur
16  // in the clients of this class.
17  // Would be nice to add priority, so that for purposes
18  // such as task switching,
19  // we could put higher-priority items in the buffer.
20  template<typename T, int C>
21  class GmArrayRingBuffer : private std::array<T, C>
22  {
23  public:
24 
25  GmArrayRingBuffer ( Bool bOkToOverrun,
26  Bool bNotices);
27  virtual ~GmArrayRingBuffer () {};
28  int WriteRecord (T *pcSource);
29  int ReadRecord (T *pcDestination);
30  int NoticeRecord (int *piDestination);
31  int ForgetNextRecord ();
32  int CheckToWrite ();
33  void SetEmpty ();
34  Bool IsEmpty ();
35  Bool HasData ();
36  Bool HasUnnoticedData ();
37  int ReserveRecord (int *pIndex);
38  T& GetBuffer (int iBufferIndex);
39  int CopyAndCommitData (T *pcSource,
40  int index);
41  int CommitData (int index);
42  int Size();
43  int MaxSize();
44 
45  protected:
46  int InternalWriteRecord (T *pcSource);
47  int m_iLastBufferRead,
48  m_iLastBufferNoticed,
49  m_iLastBufferWritten;
50 
51  // To manage overruns. See notes in CPP
52  Bool m_bNextWriteWouldOverrun,
53  m_bNextWriteWouldOverrunNotice,
54  m_bOkToOverrun,
55  m_bNotices;
56 
57  };
58 }
59 
60 /****************/
61 #ifndef _GEO_APPDEFS_HPP
62 #include <GeoAppDefs.hpp>
63 #endif
64 
65 #include "string.h"
66 #ifdef linux
67 #include <stdint.h>
68 #endif
69 
70 #ifdef acs
71 #include <xdc/std.h>
72 #include <xdc/cfg/global.h>
73 #include <xdc/runtime/Error.h>
74 #include <xdc/runtime/System.h>
75 #include <xdc/runtime/Memory.h>
76 #endif
77 #include "geotypes.hpp"
78 
79 #include "GmRingBuffer.hpp"
80 
81 #include "GmArrayRingBuffer.hpp"
82 
83 using namespace Geometrics;
84 
85 //#define DEBUGGING_COMPILE_ISSUES
86 #ifdef DEBUGGING_COMPILE_ISSUES
87 GmArrayRingBuffer<uint8_t,20> theArray(true,true);
88 uint8_t aTestItem;
89 #endif
90 
91 /******************************************************************************************************************/
92 /* Notes:
93  * The read and write pointers can be the same in two cases - if the read pointer has caught up with the
94  * write pointer, in which case the FIFO is empty; or if the write pointer has caught up with the read pointer,
95  * in which case the buffer is full.
96  */
97 /******************************************************************************************************************/
98 template<typename T, int C>
100  Bool bNotices)
101  : std::array<T,C>(),
102  m_bOkToOverrun (bOkToOverrun),
103  m_bNotices (bNotices)
104 {
105 /* // If we fail to allocate the space, the buffer will be NULL, and
106  // we will check for it.
107  if (uiBufferSize == (iMaxItems * iItemSize))
108  m_Buffer = puiBuffer;
109  else
110  m_Buffer = NULL;
111  */
112  SetEmpty ();
113 #ifdef DEBUGGING_COMPILE_ISSUES
114  GetBuffer(0);
115  IsEmpty ();
116  MaxSize();
117  Size();
118  ReadRecord (&aTestItem);
119  ForgetNextRecord ();
120  WriteRecord(&aTestItem);
121 #endif
122 }
123 
124 template<typename T, int C>
126 {
127  // Just reset the counters and flags.
128  m_iLastBufferRead = -1;
129  m_iLastBufferWritten = -1;
130  m_iLastBufferNoticed = -1;
131  m_bNextWriteWouldOverrun = FALSE;
132  m_bNextWriteWouldOverrunNotice = FALSE;
133 }
134 
135 template<typename T, int C>
136 T& GmArrayRingBuffer<T,C>::GetBuffer (int iBufferIndex)
137 {
138  if ((iBufferIndex < 0) ||
139  (iBufferIndex >= this->size()))
140  return this->at(0); //nullptr;
141  // auto it = this->begin();
142  // return it. [iBufferIndex];
143  //return this->begin()[iBufferIndex];
144  return this->at(iBufferIndex);
145 }
146 
147 template<typename T, int C>
149 {
150  return ((m_iLastBufferRead == m_iLastBufferWritten)&&
151  !m_bNextWriteWouldOverrun);
152 }
153 
154 
155 template<typename T, int C>
157 {
158  return this->size();
159 }
160 
161 template<typename T, int C>
163 {
164  if (m_iLastBufferRead < m_iLastBufferWritten)
165  {
166  return (m_iLastBufferWritten - m_iLastBufferRead);
167  }
168  else if (m_iLastBufferWritten < m_iLastBufferRead)
169  {
170  return (this->size() - m_iLastBufferRead + m_iLastBufferWritten);
171  }
172  else if (m_iLastBufferWritten == -1)
173  {
174  return 0;
175  }
176  else
177  {
178  return MaxSize();
179  }
180 }
181 
182 template<typename T, int C>
184 {
185  return (!IsEmpty ());
186 }
187 
188 template<typename T, int C>
190 {
191  return (HasData () && (this->m_iLastBufferNoticed != m_iLastBufferRead));
192 }
193 
194 // ===============================================================
195 // Non-destructive peek. This allows a consumer (e.g. another buffer
196 // that c<T,C>onsolidates the contents of several buffers) to keep a
197 // reference lock on an item in this buffer.
198 // TODO RHC not perfectly happy with this implementation. it's
199 // pretty single-purpose.
200 // ===============================================================
201 template<typename T, int C>
202 int GmArrayRingBuffer<T,C>::NoticeRecord (int *piDestination)
203 {
204  int iNotice;
205 
206  if (m_Buffer == NULL)
207  return GM_RING_BUFFER_FAILURE;
208 
209  if (IsEmpty ())
210  return GM_RING_BUFFER_EMPTY;
211 
212  if (!HasUnnoticedData ())
213  {
214  return GM_RING_BUFFER_NO_UNNOTICED;
215  }
216 
217  // Prep to read the buffer. Don't yet mark it as having been read.
218  iNotice = m_iLastBufferNoticed + 1;
219 
220  if (iNotice == m_iMaxItems)
221  iNotice = 0;
222  *piDestination = iNotice;
223 
224  // A notice always unsets the overrun flag.
225  // TODO RHC I don't think this is correct. Can allow an overrun, if the point
226  /* is to reserve a record for view, and the system writes again */
227  m_bNextWriteWouldOverrunNotice = FALSE;
228 
229  // We are done with this buffer. Advance the counter.
230  m_iLastBufferNoticed = iNotice;
231 
232  return GM_RING_BUFFER_OK;
233 }
234 
235 // ===============================================================
236 // Destructive read - fetch the data and advance the read pointer.
237 // The record is no longer available for reading.
238 // ===============================================================
239 template<typename T, int C>
240 int GmArrayRingBuffer<T,C>::ReadRecord (T* pcDestination)
241 {
242  int iReadBuffer;
243  // UInt8 *wrkBuffer;
244 
245  if (IsEmpty ())
246  return GM_RING_BUFFER_EMPTY;
247 
248  // Prep to read the buffer. Don't yet mark it as having been read.
249  iReadBuffer = m_iLastBufferRead + 1;
250 
251  if (iReadBuffer == this->size())
252  iReadBuffer = 0;
253 
254  if (pcDestination != nullptr)
255  {
256  *pcDestination = GetBuffer (iReadBuffer);
257  }
258 
259  // A data read always unsets the overrun flag.
260  m_bNextWriteWouldOverrun = FALSE;
261 
262  // We are done with this buffer. Advance the counter.
263  if (iReadBuffer == m_iLastBufferWritten)
264  {
265  m_iLastBufferWritten = -1;
266  m_iLastBufferRead = -1;
267  }
268  else
269  {
270  m_iLastBufferRead = iReadBuffer;
271  }
272 
273  if (pcDestination == nullptr)
274  return GM_RING_BUFFER_NULL_DESTINATION;
275  else
276  return GM_RING_BUFFER_OK;
277 }
278 
279 template<typename T, int C>
281 {
282 
283  int iTest = ReadRecord (NULL);
284  switch (iTest)
285  {
286  case GM_RING_BUFFER_NULL_DESTINATION:
287  return GM_RING_BUFFER_OK;
288 
289  // Should never return OK.
290  case GM_RING_BUFFER_OK:
291  return GM_RING_BUFFER_FAILURE;
292 
293  default:
294  return iTest;
295  }
296 }
297 
298 template<typename T, int C>
299 int GmArrayRingBuffer<T,C>::WriteRecord (T* pcSource)
300 {
301  #ifndef NDEBUG
302  int iTest;
303  iTest = CheckToWrite ( iSize);
304  if (iTest == GM_RING_BUFFER_OK)
305  #endif
306  return InternalWriteRecord (pcSource);
307  #ifndef NDEBUG
308  else
309  return iTest;
310  #endif
311 }
312 
313 template<typename T, int C>
315 {
316  return GM_RING_BUFFER_OK;
317 }
318 
319 template<typename T, int C>
321 {
322  int iWriteBuffer;
323  // UInt8 *wrkBuffer;
324  int iReturn = GM_RING_BUFFER_OK;
325 
326  // If the write pointer caught up with the read pointer on the
327  // last write, then this write would overwrite existing,
328  // unread data.
329  if (m_bNextWriteWouldOverrun)
330  {
331  if (m_bOkToOverrun)
332  {
333  SetEmpty ();
334  m_bNextWriteWouldOverrun = FALSE;
335 
336  // Recurse. With empty system, should write just fine.
337  iReturn = ReserveRecord (pIndex);
338 
339  // But we will return the fact that we did overwrite...
340  if (iReturn == GM_RING_BUFFER_OK)
341  return GM_RING_BUFFER_OVERRUN_OVERWROTE;
342  else
343  return iReturn;
344  }
345  // ... but if we've said it's not OK to overrun the buffer, then we won't
346  // write the data, and will simply abort the write.
347  else
348  {
349  return GM_RING_BUFFER_OVERRUN_NO_WRITE;
350  }
351  }
352 
353  // TODO RHC not so sure about this.
354  if (m_bNextWriteWouldOverrunNotice)
355  {
356  m_iLastBufferNoticed++;
357  if (m_iLastBufferNoticed == this->size())
358  m_iLastBufferNoticed = 0;
359  }
360 
361  iWriteBuffer = m_iLastBufferWritten + 1;
362  if (iWriteBuffer == this->size())
363  iWriteBuffer = 0;
364 
365  // ======= Have we caught up with the read pointer? ======
366  if (iWriteBuffer == m_iLastBufferRead)
367  {
368  m_bNextWriteWouldOverrun = TRUE;
369  }
370  else
371  {
372  if (iWriteBuffer == m_iLastBufferNoticed)
373  {
374  m_bNextWriteWouldOverrunNotice = TRUE;
375  }
376  }
377  *pIndex = iWriteBuffer;
378  return GM_RING_BUFFER_OK;
379 }
380 
381 template<typename T, int C>
383 {
384  m_iLastBufferWritten = index;
385  return GM_RING_BUFFER_OK;
386 }
387 
388 
389 template<typename T, int C>
391  int index)
392 {
393  // T wrkBuffer;
394  // Finally, write the data and update the counters.
395  // wrkBuffer = GetBuffer (index);
396  GetBuffer(index) = *pcSource;
397  //*pcSource = GetBuffer(index);asdf
398  //wrkBuffer;
399 
400  // We are done with this buffer. Advance the counter.
401  m_iLastBufferWritten = index;
402 
403  return GM_RING_BUFFER_OK;
404 }
405 
406 
407 template<typename T, int C>
409 {
410  int iWriteBuffer;
411 
412 
413  int iReturn = ReserveRecord (&iWriteBuffer);
414 
415  if ((iReturn == GM_RING_BUFFER_OK) ||
416  (iReturn == GM_RING_BUFFER_OVERRUN_OVERWROTE))
417  {
418  int iWriteTest = CopyAndCommitData (pcSource,iWriteBuffer);
419  if (iWriteTest != GM_RING_BUFFER_OK)
420  return iWriteTest;
421  }
422  return iReturn;
423  }
424 
425 #endif /* GMRINGBUFFER_HPP_ */
Definition: GmArrayRingBuffer.hpp:22
GmApp/GmLoggingApp.hpp>
Definition: Analogs.hpp:47