Gray C++ Libraries  0.0.2
A set of C++ libraries for MSVC, GNU on Windows, WinCE, Linux
cQueue.h
Go to the documentation of this file.
1 //
4 //
5 
6 #ifndef _INC_cQueue_H
7 #define _INC_cQueue_H
8 #ifndef NO_PRAGMA_ONCE
9 #pragma once
10 #endif
11 
12 #include "cHeap.h"
13 #include "HResult.h"
14 #include "cArray.h"
15 #include "cStreamProgress.h"
16 
17 namespace Gray
18 {
20  {
25 
26  protected:
29 
30  public:
31  cQueueBase(ITERATE_t iReadLast = 0, ITERATE_t iWriteLast = 0) noexcept
32  : m_iReadLast(iReadLast)
33  , m_iWriteLast(iWriteLast)
34  {
35  }
36  void InitQ(ITERATE_t iReadLast = 0, ITERATE_t iWriteLast = 0) noexcept
37  {
38  m_iReadLast = iReadLast;
39  m_iWriteLast = iWriteLast; // put new data here.
40  }
41  bool isEmptyQ() const noexcept
42  {
43  return m_iReadLast == m_iWriteLast;
44  }
45  void EmptyQ() noexcept
46  {
47  m_iReadLast = m_iWriteLast = 0;
48  }
49 
50  ITERATE_t get_ReadIndex() const noexcept
51  {
53  return m_iReadLast;
54  }
55  ITERATE_t get_WriteIndex() const noexcept
56  {
58  return m_iWriteLast;
59  }
60  inline ITERATE_t get_ReadQty() const
61  {
64  ASSERT(m_iWriteLast >= m_iReadLast); // Assume will not will wrap to fill.
65  return m_iWriteLast - m_iReadLast;
66  }
67 
68  inline void AdvanceRead(ITERATE_t iCount = 1)
69  {
70  // Assume will not will wrap to fill.
71  m_iReadLast += iCount;
72  ASSERT(m_iReadLast >= 0 && m_iReadLast <= m_iWriteLast); // Assume will not will wrap to fill.
73  }
74 
75  STREAM_SEEKRET_t SeekQ(STREAM_OFFSET_t iOffset, SEEK_ORIGIN_TYPE eSeekOrigin = SEEK_Set); // support virtual
76 
77  UNITTEST_FRIEND(cQueue);
78  };
79 
80  //*********************************************************************
81 
82  template<class TYPE = BYTE, ITERATE_t _QTY = 1024>
84  {
87 
88  TYPE m_Data[_QTY];
89  ITERATE_t m_iWriteNext;
90 
91  public:
92  inline cStackStatic() noexcept
93  : m_iWriteNext(0)
94  {
95  STATIC_ASSERT(_QTY > 0, cStackStatic);
96  }
97  inline bool isEmpty() const noexcept
98  {
99  return m_iWriteNext == 0;
100  }
101  inline bool isFull() const noexcept
102  {
103  return m_iWriteNext >= _QTY;
104  }
105  inline TYPE Pop()
106  {
107  ASSERT(m_iWriteNext >= 1);
108  return m_Data[--m_iWriteNext];
109  }
110  inline void Push(TYPE v)
111  {
112  ASSERT(m_iWriteNext < _QTY);
113  m_Data[m_iWriteNext++] = v;
114  }
115  };
116 
117  template<class TYPE = BYTE, ITERATE_t _QTY = 1024>
119  {
125 
126  public:
127  TYPE m_Data[_QTY]; // Not heap allocation.
128 
129  protected:
130  inline ITERATE_t GetWrapIndex(ITERATE_t i) const noexcept
131  {
132  return i % _QTY;
133  }
134 
135  private:
136  inline ITERATE_t get_ReadQty() const // Don't use this if we wrap.
137  {
138  ASSERT(false);
139  return 0;
140  }
141 
142  public:
143  cQueueStatic() noexcept
144  {
145  STATIC_ASSERT(_QTY > 0, _QTY);
146 #if defined(_DEBUG)
147  cMem::Zero(m_Data, sizeof(m_Data));
148 #endif
149  }
150  bool isFullQ() const noexcept
151  {
152  return GetWrapIndex(m_iWriteLast + 1) == m_iReadLast;
153  }
154  void EmptyQ() noexcept
155  {
158  m_iReadLast = m_iWriteLast;
159  }
160  ITERATE_t get_ReadQtyT() const noexcept
161  {
163  ITERATE_t iWrite = m_iWriteLast;
164  ITERATE_t iRead = m_iReadLast;
165  if (iRead > iWrite) // wrap
166  {
167  iWrite += _QTY;
168  DEBUG_ASSERT(iWrite > iRead, "get_ReadQtyT"); // sanity check. should never happen!
169  }
170  return iWrite - iRead;
171  }
172  ITERATE_t get_ReadQtyC() const noexcept
173  {
175  ITERATE_t iTop = (m_iWriteLast >= m_iReadLast) ? m_iWriteLast : _QTY;
176  return iTop - m_iReadLast;
177  }
178  const TYPE* get_ReadPtr() const
179  {
181  ASSERT(!isEmptyQ()); // ONLY call this if there is data to read.
182  return &m_Data[m_iReadLast];
183  }
184  void AdvanceRead(ITERATE_t iCount = 1)
185  {
186  ITERATE_t iReadCount = get_ReadQtyT();
187  if (iCount > iReadCount)
188  iCount = iReadCount;
189  m_iReadLast = GetWrapIndex(m_iReadLast + iCount);
190  }
191 
192  ITERATE_t get_WriteQtyT() const noexcept
193  {
196  return (_QTY - 1) - get_ReadQtyT();
197  }
198 
200  {
204  ASSERT(!isEmptyQ());
205  ITERATE_t iRead = m_iReadLast;
206  ASSERT(IS_INDEX_GOOD(iRead, _QTY));
207  ITERATE_t iReadNext = GetWrapIndex(iRead + 1);
208  TYPE val = m_Data[iRead];
209  m_iReadLast = iReadNext;
210  return val;
211  }
212  ITERATE_t ReadQty(TYPE* pBuf, ITERATE_t nCountMax)
213  {
216 
217  ITERATE_t i = 0;
218  for (; !isEmptyQ() && i < nCountMax; i++)
219  {
220  pBuf[i] = Read1();
221  }
222  return i;
223  }
225  {
227  ITERATE_t i = 0;
228  for (; !isEmptyQ() && i < nCountMax; i++)
229  {
230  pBuf[i] = Read1();
231  }
232  return i;
233  }
234 
235  bool WriteQ(TYPE val)
236  {
241  ITERATE_t iWrite = m_iWriteLast;
242  ASSERT(IS_INDEX_GOOD(iWrite, _QTY));
243  ITERATE_t iWriteNext = GetWrapIndex(iWrite + 1);
244  if (iWriteNext == m_iReadLast) // isFullQ() ?
245  return false;
246  m_Data[iWrite] = val;
247  m_iWriteLast = iWriteNext;
248  return true;
249  }
250  HRESULT WriteQty(const TYPE* pVal, ITERATE_t iLength)
251  {
256  ITERATE_t iRoom = get_WriteQtyT();
257  ASSERT(iRoom >= 0 && iRoom <= _QTY);
258  ITERATE_t iWrite = m_iWriteLast;
259  ASSERT(iWrite >= 0 && iWrite < _QTY);
260  ITERATE_t iLengthMin = MIN(iRoom, iLength); // max i can write and hold.
261  if (iWrite + iLengthMin > _QTY) // will overflow/wrap?
262  {
263  ITERATE_t iTmp1 = _QTY - iWrite;
264  CopyElements(m_Data + iWrite, pVal, iTmp1); // Write to end of buffer.
265  ITERATE_t iTmp2 = iLengthMin - iTmp1;
266  CopyElements(m_Data, pVal + iTmp1, iTmp2); // Wrap back from beginning.
267  m_iWriteLast = iTmp2;
268  }
269  else
270  {
271  CopyElements(m_Data + iWrite, pVal, iLengthMin);
272  m_iWriteLast = iWrite + iLengthMin;
273  }
274  return (HRESULT)iLengthMin;
275  }
276 
277  HRESULT WriteQtySafe(const TYPE* pVal, ITERATE_t iLength)
278  {
280  ITERATE_t i = 0;
281  for (; !isFullQ() && i < iLength; i++)
282  {
283  WriteQ(pVal[i]);
284  }
285  return i;
286  }
287  };
288 
289  //*********************************************************************
290 
291  template <class TYPE = BYTE>
293  {
296 
297  protected:
299 
300  public:
301  cQueueRead(const TYPE* pData = nullptr, ITERATE_t iReadLast = 0, ITERATE_t iWriteLast = 0) noexcept
302  : cQueueBase(iReadLast, iWriteLast)
303  , m_pData(const_cast<TYPE*>(pData))
304  {
305  }
307  {
308  // NOT free m_pData memory.
309  }
310 
311  // Peek into/read from the Queue's data.
312  inline const TYPE* get_ReadPtr() const
313  {
316  ASSERT(m_pData != nullptr);
317  return(m_pData + m_iReadLast);
318  }
319  void SetQueueRead(const TYPE* pData, ITERATE_t iReadLast = 0, ITERATE_t iWriteLast = 0)
320  {
321  m_pData = const_cast<TYPE*>(pData);
322  InitQ(iReadLast, iWriteLast);
323  }
324 
325  TYPE Read1(void)
326  {
328  ASSERT(!isEmptyQ());
329  return m_pData[m_iReadLast++];
330  }
331  HRESULT ReadPeek(TYPE* pData, ITERATE_t iDataMaxQty)
332  {
336  ITERATE_t iQtyAvail = get_ReadQty();
337  if (iDataMaxQty > iQtyAvail)
338  iDataMaxQty = iQtyAvail;
339  if (pData != nullptr)
340  {
342  CopyElements(pData, m_pData + m_iReadLast, iDataMaxQty);
343  }
344  return (HRESULT)iDataMaxQty;
345  }
346 
347  HRESULT ReadQty(TYPE* pData, ITERATE_t iDataMaxQty)
348  {
352 
353  const ITERATE_t iQtyAvail = get_ReadQty();
354  if (iDataMaxQty > iQtyAvail)
355  iDataMaxQty = iQtyAvail;
356  if (pData != nullptr)
357  {
359  CopyElements(pData, m_pData + m_iReadLast, iDataMaxQty);
360  }
361  AdvanceRead(iDataMaxQty); // advance m_iReadLast pointer.
362  return (HRESULT)iDataMaxQty;
363  }
364 
366  {
372  if (this->m_iReadLast <= 0) // next read is already at 0.
373  return;
374  ITERATE_t iSize = this->get_ReadQty();
375  if (iSize > 0) // there is data to move ?
376  {
377  const TYPE* pTmp = this->m_pData + this->m_iReadLast;
378  cMem::CopyOverlap(this->m_pData, pTmp, iSize * sizeof(TYPE));
379  }
380  this->InitQ(0, iSize);
381  }
382  };
383 
384  //*********************************************************************
385 
386  template <class TYPE = BYTE>
387  class GRAYCORE_LINK cQueueRW : public cQueueRead < TYPE >
388  {
395 
396  typedef cQueueRead<TYPE> SUPER_t;
397 
398  protected:
401 
402  public:
403  cQueueRW() noexcept
404  : cQueueRead<TYPE>(nullptr, 0, 0)
405  , m_iDataSizeAlloc(0)
406  , m_iAutoReadCommit(0)
407  {
408  // empty.
409  }
410  explicit cQueueRW(TYPE* pData, ITERATE_t iDataAlloc, ITERATE_t iReadLast, ITERATE_t iWriteLast, ITERATE_t iAutoReadCommit = 0)
411  : cQueueRead<TYPE>(pData, iReadLast, iWriteLast)
412  , m_iDataSizeAlloc(iDataAlloc)
413  , m_iAutoReadCommit(iAutoReadCommit)
414  {
415  // Read / Write.
416  }
417  explicit cQueueRW(const TYPE* pData, ITERATE_t iDataMax)
418  : cQueueRead<TYPE>(const_cast<TYPE*>(pData), 0, iDataMax)
419  , m_iDataSizeAlloc(iDataMax)
420  , m_iAutoReadCommit(0)
421  {
422  // Read Only iDataMax.
423  }
425  {
427  }
428 
429  //***************************************************
430  // Reader functions.
431 
433  {
436  if (m_iAutoReadCommit != 0 && this->m_iReadLast >= m_iAutoReadCommit) // (ITERATE_t) m_nGrowSizeChunk
437  {
438  this->ReadCommitNow();
439  }
440  }
442  {
443  return m_iAutoReadCommit;
444  }
445  void put_AutoReadCommit(ITERATE_t iAutoReadCommit = 8 * 1024)
446  {
450  m_iAutoReadCommit = iAutoReadCommit;
451  if (iAutoReadCommit != 0)
452  {
453  this->ReadCommitNow();
454  }
455  }
456 
457  void put_ReadIndex(ITERATE_t iReadLo)
458  {
460  ASSERT(iReadLo >= 0);
461  ASSERT(iReadLo <= this->m_iWriteLast);
462  this->m_iReadLast = iReadLo;
463  ReadCommitCheck();
464  }
465 
466  // Act as a stream
468  {
475  SUPER_t::SeekQ(iOffset, eSeekOrigin);
476  ReadCommitCheck();
477  return this->m_iReadLast;
478  }
479 
480  HRESULT ReadQty(TYPE* pData, ITERATE_t iDataMaxQty)
481  {
484  HRESULT iReadQty = SUPER_t::ReadQty(pData, iDataMaxQty);
485  ReadCommitCheck();
486  return iReadQty;
487  }
488 
489  HRESULT ReadX(void* pData, size_t nDataSize)
490  {
492  HRESULT iReadQty = ReadQty((TYPE*)pData, (ITERATE_t)(nDataSize / sizeof(TYPE)));
493  return iReadQty * sizeof(TYPE);
494  }
495 
496  //***************************************************
497  // Writer functions.
498 
499  inline bool isFullQ() const
500  {
501  // Cant fit any more. would have to grow buffer.
502  return(this->m_iWriteLast >= m_iDataSizeAlloc);
503  }
504 
505  inline ITERATE_t get_WriteQty() const
506  {
509  ASSERT(this->m_iWriteLast <= m_iDataSizeAlloc);
510  return(m_iDataSizeAlloc - this->m_iWriteLast);
511  }
512  inline TYPE* get_WritePtr() const
513  {
515  ASSERT(this->m_pData != nullptr);
516  return(this->m_pData + this->m_iWriteLast);
517  }
518 
519  HRESULT WriteQty(const TYPE* pData, ITERATE_t iQtyMax)
520  {
524 
525  ITERATE_t iWriteSpace = get_WriteQty();
526  if (iWriteSpace <= 0)
527  return 0;
528  if ((ITERATE_t)iQtyMax > iWriteSpace)
529  iQtyMax = iWriteSpace;
530  if (pData != nullptr)
531  {
532  WriteQN(pData, iQtyMax);
533  }
534  return (HRESULT)iQtyMax;
535  }
536 
537  HRESULT WriteX(const void* pData, size_t nDataSize)
538  {
540  HRESULT iReadQty = WriteQty((TYPE*)pData, (ITERATE_t)(nDataSize / sizeof(TYPE)));
541  return iReadQty * sizeof(TYPE);
542  }
543 
544  inline void AdvanceWrite(ITERATE_t iCount = 1)
545  {
547  ASSERT_N(iCount <= get_WriteQty());
548  this->m_iWriteLast += iCount;
549  ASSERT(m_iDataSizeAlloc >= this->m_iWriteLast);
550  }
551 
552  protected:
553  void WriteQN(const TYPE* pData, ITERATE_t iQtyMax)
554  {
557  if (iQtyMax <= 0)
558  return;
559  ASSERT_N(this->m_iWriteLast + iQtyMax <= m_iDataSizeAlloc);
560  if (pData != nullptr)
561  {
562  CopyElements(this->m_pData + this->m_iWriteLast, pData, iQtyMax);
563  }
564  AdvanceWrite(iQtyMax);
565  }
566  };
567 
568  //*********************************************************************
569 
570  template<class TYPE = BYTE>
571  class cQueueDyn : public cQueueRW < TYPE >
572  {
578 
579  typedef cQueueRW<TYPE> SUPER_t;
580 
581  private:
582  cArrayVal<TYPE> m_aData;
583 
584  protected:
587 
588  protected:
589  bool AllocSizeMaxQ(ITERATE_t iDataAlloc)
590  {
592  if (iDataAlloc > m_nGrowSizeMax) // too big !
593  {
594  return false;
595  }
596  if (this->m_iDataSizeAlloc != iDataAlloc)
597  {
598  m_aData.SetSize(iDataAlloc); // realloc
599  this->m_pData = m_aData.get_DataWork();
600  this->m_iDataSizeAlloc = iDataAlloc;
601  }
602  return true;
603  }
604 
605  public:
606  cQueueDyn(ITERATE_t nGrowSizeChunk = 128, ITERATE_t nGrowSizeMax = (cHeap::k_ALLOC_MAX / sizeof(TYPE))) noexcept
607  : m_nGrowSizeChunk(nGrowSizeChunk)
608  , m_nGrowSizeMax(nGrowSizeMax)
609  {
611 
612  ASSERT(m_nGrowSizeChunk >= 0);
613  ASSERT(m_nGrowSizeMax >= 0);
614  if (m_nGrowSizeMax > 0)
615  {
616  if (m_nGrowSizeChunk < 128)
617  m_nGrowSizeChunk = 128;
620  }
621  else
622  {
623  m_nGrowSizeChunk = 0; // Must both be 0.
624  }
626  this->put_AutoReadCommit(m_nGrowSizeChunk / 2); // default = half buffer.
627  }
629  {
631  }
632 
633  void put_GrowSizeChunk(ITERATE_t nGrowSizeChunk) noexcept
634  {
636  if (nGrowSizeChunk > m_nGrowSizeMax) // Must not be greater!
637  m_nGrowSizeMax = nGrowSizeChunk;
638  m_nGrowSizeChunk = nGrowSizeChunk;
639  }
640  ITERATE_t get_GrowSizeChunk() const noexcept
641  {
642  return m_nGrowSizeChunk;
643  }
644 
645  bool MakeWritePrepared(ITERATE_t iDesiredCount = 1)
646  {
649  ITERATE_t iRoom = this->get_WriteQty();
650  if (iRoom >= iDesiredCount) // all set.
651  return true;
652 
653  ITERATE_t iGrowRequest = iDesiredCount - iRoom; // how much MORE do i need?
654  ASSERT(iGrowRequest > 0);
655  ITERATE_t iChunksGrow = iGrowRequest / m_nGrowSizeChunk;
656  ITERATE_t iRem = iGrowRequest % m_nGrowSizeChunk;
657  if (iRem != 0)
658  iChunksGrow++;
659 
660  ITERATE_t iTotalSize = this->m_iDataSizeAlloc + iChunksGrow * m_nGrowSizeChunk;
661  if (iTotalSize > m_nGrowSizeMax) // too big !
662  iTotalSize = m_nGrowSizeMax;
663 
664  if (iTotalSize - this->m_iWriteLast <= 0) // can i get any?
665  return false; // Got no more space. we must wait?
666 
667  return AllocSizeMaxQ(iTotalSize);
668  }
669  TYPE* GetWritePrepared(ITERATE_t iDesiredCount = 1)
670  {
673  if (!MakeWritePrepared(iDesiredCount))
674  return nullptr;
675  // ASSERT(get_WriteQty() >= iDesiredCount); except for m_nGrowSizeMax
676  return this->get_WritePtr();
677  }
678 
679  bool WriteQ(TYPE val)
680  {
682  if (this->m_iWriteLast >= this->m_iDataSizeAlloc)
683  {
684  if (!AllocSizeMaxQ(this->m_iDataSizeAlloc + m_nGrowSizeChunk))
685  {
686  return false;
687  }
688  }
689  ITERATE_t iWrite = this->m_iWriteLast++;
690  m_aData[iWrite] = val;
691  return true;
692  }
693  HRESULT WriteQty(const TYPE* pVal, ITERATE_t iCount)
694  {
697  if (!MakeWritePrepared(iCount))
698  {
699  return HRESULT_WIN32_C(ERROR_DATABASE_FULL); // full!
700  }
701  ASSERT(this->get_WriteQty() >= iCount);
702  if (pVal != nullptr)
703  {
704  this->WriteQN(pVal, iCount);
705  }
706  return (HRESULT)iCount;
707  }
708 
710  {
712  WriteQty(queue.get_ReadPtr(), queue.get_ReadQty());
713  queue.EmptyQ();
714  }
715 
716  HRESULT WriteX(const void* pData, size_t nDataSize)
717  {
720  HRESULT hRes = this->WriteQty((const TYPE*)pData, (ITERATE_t)(nDataSize / sizeof(TYPE)));
721  if (FAILED(hRes))
722  return hRes;
723  return (HRESULT)nDataSize; // hRes * sizeof(TYPE)
724  }
725  };
726 
727  //*********************************************************************
728 
729  class GRAYCORE_LINK cQueueBytes : public cQueueDyn < BYTE >
730  {
734 
735  typedef cQueueDyn<BYTE> SUPER_t;
736  public:
737  explicit cQueueBytes(size_t nGrowSizeChunk = 8 * 1024, size_t nGrowSizeMax = cHeap::k_ALLOC_MAX) noexcept
738  : cQueueDyn<BYTE>((ITERATE_t)nGrowSizeChunk, (ITERATE_t)nGrowSizeMax)
739  {
741  }
743  {
744  // Memory is freed
745  }
746 
747  bool InsertDataHead(const BYTE* pDataSrc, size_t iLen)
748  {
750  if (!MakeWritePrepared((ITERATE_t)iLen))
751  return false;
752  cMem::CopyOverlap(m_pData + m_iReadLast + iLen, m_pData + m_iReadLast, get_ReadQty());
753  cMem::Copy(m_pData + m_iReadLast, pDataSrc, iLen);
754  AdvanceWrite((ITERATE_t)iLen);
755  return true;
756  }
757  bool SetAllData(const BYTE* pData, size_t iLen)
758  {
761  if (iLen > (size_t)m_iDataSizeAlloc) // grow a little?
762  {
763  if (!AllocSizeMaxQ((ITERATE_t)iLen))
764  return false;
765  }
766  cMem::CopyOverlap(m_pData, pData, iLen); // may be from the same buffer!? use memmove to be safe.
767  InitQ(0, (ITERATE_t)iLen);
768  return true;
769  }
770  };
771 
772  //***********************************************************************
773 
774  template<class TYPE = BYTE>
776  {
782 
783  public:
784  class cQueueChunk : public cQueueDyn < TYPE >
785  {
788  public:
790  public:
791  cQueueChunk(ITERATE_t nGrowSizeChunk)
792  : cQueueDyn<TYPE>(nGrowSizeChunk)
793  , m_pNext(nullptr)
794  {}
795  };
796 
797  private:
798  const ITERATE_t m_nGrowSizeChunk;
799  ITERATE_t m_nTotalQty;
800  cQueueChunk* m_pFirst;
801  cQueueChunk* m_pLast;
802 
803  public:
804  cQueueChunked(ITERATE_t nGrowSizeChunk)
805  : m_nGrowSizeChunk(nGrowSizeChunk)
806  , m_nTotalQty(0)
807  , m_pFirst(nullptr)
808  , m_pLast(nullptr)
809  {
810  }
812  {
813  EmptyQ();
814  }
815 
816  bool isEmptyQ() const
817  {
818  return(m_nTotalQty == 0);
819  }
820  void EmptyQ()
821  {
822  AdvanceRead(m_nTotalQty);
823  ASSERT(m_nTotalQty == 0);
824  ASSERT(m_pFirst == nullptr);
825  ASSERT(m_pLast == nullptr);
826  }
827 
829  {
831  return m_nTotalQty;
832  }
834  {
836  if (m_pFirst == nullptr)
837  return 0;
838  return m_pFirst->get_ReadQty();
839  }
840  const TYPE* get_ReadPtrC() const
841  {
844  ASSERT(!isEmptyQ());
845  ASSERT_N(m_pFirst != nullptr);
846  return m_pFirst->get_ReadPtr();
847  }
848  void AdvanceRead(ITERATE_t iCount = 1)
849  {
851  ITERATE_t iCountLeft = iCount;
852  while (iCountLeft >= 0)
853  {
854  cQueueChunk* pCur = m_pFirst;
855  if (pCur == nullptr)
856  break;
857  ITERATE_t iSize = pCur->get_ReadQty();
858  if (iCountLeft < iSize)
859  {
860  pCur->AdvanceRead(iCountLeft);
861  break;
862  }
863  pCur->AdvanceRead(iSize);
864  m_pFirst = pCur->m_pNext;
865  delete pCur;
866  iCountLeft -= iSize;
867  }
868  m_nTotalQty -= iCount;
869  ASSERT(m_nTotalQty >= 0);
870  if (m_pFirst == nullptr)
871  {
872  m_pLast = nullptr;
873  }
874  }
876  {
878  if (m_pLast == nullptr)
879  {
880  return m_nGrowSizeChunk;
881  }
882  return m_pLast->get_WriteQty();
883  }
884  TYPE* GetWritePrepared(ITERATE_t iDesiredCount = 1)
885  {
888  cQueueChunk* pCur = m_pLast;
889  if (pCur == nullptr)
890  {
891  m_pFirst = m_pLast = new cQueueChunk(m_nGrowSizeChunk);
892  }
893  else if (m_pLast->isFullQ())
894  {
895  pCur->m_pNext = m_pLast = new cQueueChunk(m_nGrowSizeChunk);
896  }
897  return m_pLast->GetWritePrepared(iDesiredCount);
898  }
899  void AdvanceWrite(ITERATE_t iCount = 1)
900  {
901  // iCount of TYPE
902  ASSERT(m_pLast != nullptr);
903  ASSERT(iCount <= get_WriteQty());
904  m_pLast->AdvanceWrite(iCount);
905  m_nTotalQty += iCount;
906  }
907 
908  TYPE Read1(void)
909  {
910  ASSERT(m_pFirst != nullptr);
911  const TYPE* pBuf = get_ReadPtrC();
912  TYPE val = *pBuf;
913  AdvanceRead(1);
914  return val;
915  }
916  ITERATE_t ReadQty(TYPE* pBuf, ITERATE_t nCountMax)
917  {
919  ITERATE_t i = 0;
920  for (; !isEmptyQ() && i < nCountMax; i++)
921  {
922  pBuf[i] = Read1();
923  }
924  return i;
925  }
926  void WriteQ(TYPE val)
927  {
928  TYPE* pBuf = GetWritePrepared(1);
929  *pBuf = val;
930  AdvanceWrite(1);
931  }
932  HRESULT WriteQty(const TYPE* pBuf, ITERATE_t nCount)
933  {
935  ITERATE_t i = 0;
936  for (; i < nCount; i++)
937  {
938  WriteQ(pBuf[i]);
939  }
940  return (HRESULT)i;
941  }
942  };
943 
944 #ifdef GRAY_DLL // force implementation/instantiate for DLL/SO.
947 #endif
948 
949 } // Gray
950 #endif // _INC_cQueue_H
#define GRAYCORE_LINK
Definition: GrayCore.h:47
#define HRESULT_WIN32_C(x)
a constant LSTATUS/error_status_t with no check, unlike HRESULT_FROM_WIN32()
Definition: HResult.h:79
#define FAILED(x)
Definition: HResult.h:30
#define IS_INDEX_GOOD(i, q)
cast the (likely) int to unsigned to check for negatives.
Definition: Index.h:35
#define TYPE
Definition: StrT.cpp:38
#define MIN(a, b)
Definition: SysTypes.h:457
INT32 HRESULT
_WIN32 style error codes. INT32
Definition: SysTypes.h:465
#define ASSERT(exp)
Definition: cDebugAssert.h:87
#define STATIC_ASSERT(exp, name)
Definition: cDebugAssert.h:24
#define ASSERT_N(exp)
Definition: cDebugAssert.h:70
#define DEBUG_ASSERT(exp, sDesc)
Definition: cDebugAssert.h:93
#define UNITTEST_FRIEND(n)
Define this in the class body to be unit tested. Allow the unit test to access private/protected stuf...
Definition: cUnitTestDecl.h:17
void SetSize(ITERATE_t nNewSize)
Definition: cArray.h:248
TYPE * get_DataWork() const
Definition: cArray.h:682
Definition: cArray.h:914
Definition: cQueue.h:20
ITERATE_t get_ReadIndex() const noexcept
Definition: cQueue.h:50
ITERATE_t get_ReadQty() const
Definition: cQueue.h:60
void AdvanceRead(ITERATE_t iCount=1)
Definition: cQueue.h:68
void EmptyQ() noexcept
Definition: cQueue.h:45
void InitQ(ITERATE_t iReadLast=0, ITERATE_t iWriteLast=0) noexcept
Definition: cQueue.h:36
ITERATE_t m_iReadLast
old items removed/read from here.
Definition: cQueue.h:27
ITERATE_t m_iWriteLast
new items added/written here. end of read.
Definition: cQueue.h:28
ITERATE_t get_WriteIndex() const noexcept
Definition: cQueue.h:55
cQueueBase(ITERATE_t iReadLast=0, ITERATE_t iWriteLast=0) noexcept
Definition: cQueue.h:31
bool isEmptyQ() const noexcept
Definition: cQueue.h:41
Definition: cQueue.h:730
bool InsertDataHead(const BYTE *pDataSrc, size_t iLen)
Definition: cQueue.h:747
cQueueBytes(size_t nGrowSizeChunk=8 *1024, size_t nGrowSizeMax=cHeap::k_ALLOC_MAX) noexcept
Definition: cQueue.h:737
bool SetAllData(const BYTE *pData, size_t iLen)
Definition: cQueue.h:757
~cQueueBytes()
Definition: cQueue.h:742
Definition: cQueue.h:785
cQueueChunk(ITERATE_t nGrowSizeChunk)
Definition: cQueue.h:791
cQueueChunk * m_pNext
Definition: cQueue.h:789
Definition: cQueue.h:776
HRESULT WriteQty(const TYPE *pBuf, ITERATE_t nCount)
Definition: cQueue.h:932
ITERATE_t ReadQty(TYPE *pBuf, ITERATE_t nCountMax)
Definition: cQueue.h:916
~cQueueChunked()
Definition: cQueue.h:811
TYPE Read1(void)
Definition: cQueue.h:908
ITERATE_t get_ReadQtyT() const
Definition: cQueue.h:828
void WriteQ(TYPE val)
Definition: cQueue.h:926
TYPE * GetWritePrepared(ITERATE_t iDesiredCount=1)
Definition: cQueue.h:884
ITERATE_t get_ReadQtyC() const
Definition: cQueue.h:833
cQueueChunked(ITERATE_t nGrowSizeChunk)
Definition: cQueue.h:804
const TYPE * get_ReadPtrC() const
Definition: cQueue.h:840
bool isEmptyQ() const
Definition: cQueue.h:816
ITERATE_t get_WriteQty(void) const
Definition: cQueue.h:875
void EmptyQ()
Definition: cQueue.h:820
void AdvanceRead(ITERATE_t iCount=1)
Definition: cQueue.h:848
void AdvanceWrite(ITERATE_t iCount=1)
Definition: cQueue.h:899
Definition: cQueue.h:572
cQueueDyn(ITERATE_t nGrowSizeChunk=128, ITERATE_t nGrowSizeMax=(cHeap::k_ALLOC_MAX/sizeof(TYPE))) noexcept
Definition: cQueue.h:606
TYPE * GetWritePrepared(ITERATE_t iDesiredCount=1)
Definition: cQueue.h:669
HRESULT WriteX(const void *pData, size_t nDataSize)
Definition: cQueue.h:716
void WriteQ(cQueueRead< BYTE > &queue)
Definition: cQueue.h:709
bool AllocSizeMaxQ(ITERATE_t iDataAlloc)
Definition: cQueue.h:589
ITERATE_t m_nGrowSizeChunk
number of TYPE elements to grow by in a single re-alloc chunk. 0 = never grow.
Definition: cQueue.h:585
~cQueueDyn()
Definition: cQueue.h:628
void put_GrowSizeChunk(ITERATE_t nGrowSizeChunk) noexcept
Definition: cQueue.h:633
bool MakeWritePrepared(ITERATE_t iDesiredCount=1)
Definition: cQueue.h:645
ITERATE_t m_nGrowSizeMax
Total arbitrary max allowed for m_iDataSizeAlloc. 0 = never grow.
Definition: cQueue.h:586
ITERATE_t get_GrowSizeChunk() const noexcept
Definition: cQueue.h:640
bool WriteQ(TYPE val)
Definition: cQueue.h:679
HRESULT WriteQty(const TYPE *pVal, ITERATE_t iCount)
Definition: cQueue.h:693
Definition: cQueue.h:388
cQueueRW(TYPE *pData, ITERATE_t iDataAlloc, ITERATE_t iReadLast, ITERATE_t iWriteLast, ITERATE_t iAutoReadCommit=0)
Definition: cQueue.h:410
ITERATE_t m_iAutoReadCommit
Read data is destroyed once read more than this amount. make more room for writing....
Definition: cQueue.h:400
void WriteQN(const TYPE *pData, ITERATE_t iQtyMax)
Definition: cQueue.h:553
ITERATE_t m_iDataSizeAlloc
The max qty we can write into m_pData. Maybe NOT exactly same as m_pData true OS allocated size?
Definition: cQueue.h:399
void put_AutoReadCommit(ITERATE_t iAutoReadCommit=8 *1024)
Definition: cQueue.h:445
bool isFullQ() const
Definition: cQueue.h:499
HRESULT WriteQty(const TYPE *pData, ITERATE_t iQtyMax)
Definition: cQueue.h:519
HRESULT WriteX(const void *pData, size_t nDataSize)
Definition: cQueue.h:537
void ReadCommitCheck()
Definition: cQueue.h:432
HRESULT ReadQty(TYPE *pData, ITERATE_t iDataMaxQty)
Definition: cQueue.h:480
void AdvanceWrite(ITERATE_t iCount=1)
Definition: cQueue.h:544
TYPE * get_WritePtr() const
Definition: cQueue.h:512
void put_ReadIndex(ITERATE_t iReadLo)
Definition: cQueue.h:457
HRESULT ReadX(void *pData, size_t nDataSize)
Definition: cQueue.h:489
~cQueueRW()
Definition: cQueue.h:424
STREAM_SEEKRET_t SeekQ(STREAM_OFFSET_t iOffset, SEEK_ORIGIN_TYPE eSeekOrigin=SEEK_Set)
Definition: cQueue.h:467
ITERATE_t get_WriteQty() const
Definition: cQueue.h:505
cQueueRW() noexcept
Definition: cQueue.h:403
ITERATE_t get_AutoReadCommit() const
Definition: cQueue.h:441
cQueueRW(const TYPE *pData, ITERATE_t iDataMax)
Definition: cQueue.h:417
Definition: cQueue.h:293
const TYPE * get_ReadPtr() const
Definition: cQueue.h:312
~cQueueRead()
Definition: cQueue.h:306
void ReadCommitNow()
Definition: cQueue.h:365
HRESULT ReadQty(TYPE *pData, ITERATE_t iDataMaxQty)
Definition: cQueue.h:347
HRESULT ReadPeek(TYPE *pData, ITERATE_t iDataMaxQty)
Definition: cQueue.h:331
TYPE Read1(void)
Definition: cQueue.h:325
void SetQueueRead(const TYPE *pData, ITERATE_t iReadLast=0, ITERATE_t iWriteLast=0)
Definition: cQueue.h:319
TYPE * m_pData
NOT owned/managed block of memory I read from. not freed on destruct.
Definition: cQueue.h:298
cQueueRead(const TYPE *pData=nullptr, ITERATE_t iReadLast=0, ITERATE_t iWriteLast=0) noexcept
Definition: cQueue.h:301
Definition: cQueue.h:119
const TYPE * get_ReadPtr() const
Definition: cQueue.h:178
ITERATE_t get_ReadQtyC() const noexcept
Definition: cQueue.h:172
ITERATE_t ReadQty(TYPE *pBuf, ITERATE_t nCountMax)
Definition: cQueue.h:212
void AdvanceRead(ITERATE_t iCount=1)
Definition: cQueue.h:184
HRESULT WriteQty(const TYPE *pVal, ITERATE_t iLength)
Definition: cQueue.h:250
bool WriteQ(TYPE val)
Definition: cQueue.h:235
TYPE Read1()
Definition: cQueue.h:199
ITERATE_t ReadQtySafe(TYPE *pBuf, ITERATE_t nCountMax)
Definition: cQueue.h:224
ITERATE_t get_WriteQtyT() const noexcept
Definition: cQueue.h:192
ITERATE_t GetWrapIndex(ITERATE_t i) const noexcept
Definition: cQueue.h:130
void EmptyQ() noexcept
Definition: cQueue.h:154
bool isFullQ() const noexcept
Definition: cQueue.h:150
HRESULT WriteQtySafe(const TYPE *pVal, ITERATE_t iLength)
Definition: cQueue.h:277
ITERATE_t get_ReadQtyT() const noexcept
Definition: cQueue.h:160
cQueueStatic() noexcept
Definition: cQueue.h:143
Definition: cQueue.h:84
bool isFull() const noexcept
Definition: cQueue.h:101
bool isEmpty() const noexcept
Definition: cQueue.h:97
TYPE Pop()
Definition: cQueue.h:105
void Push(TYPE v)
Definition: cQueue.h:110
cStackStatic() noexcept
Definition: cQueue.h:92
< The main namespace for all Core functions.
Definition: GrayCore.cpp:14
LONG_PTR STREAM_OFFSET_t
Might be 64 or 32 bit. TODO SET USE_FILE_POS64.
Definition: cOSHandle.h:52
void __cdecl CopyElements(TYPE *pDest, const TYPE *pSrc, ITERATE_t nCount)
Definition: cArray.h:72
LONG_PTR STREAM_SEEKRET_t
return from Seek()
Definition: cOSHandle.h:53
int ITERATE_t
like size_t but signed
Definition: Index.h:28
SEEK_ORIGIN_TYPE
Definition: cOSHandle.h:34
@ SEEK_Set
SEEK_SET = FILE_BEGIN = STREAM_SEEK_SET = 0 = relative to the start of the file.
Definition: cOSHandle.h:39
static const size_t k_ALLOC_MAX
256 * 64K = (arbitrary) largest reasonable single malloc.
Definition: cHeap.h:45
static void Copy(void *pDst, const void *pSrc, size_t nSizeBlock) noexcept
Definition: cMem.h:132
static void Zero(void *pData, size_t nSizeBlock) noexcept
Definition: cMem.h:100
static void CopyOverlap(void *pDst, const void *pSrc, size_t nSizeBlock) noexcept
Definition: cMem.h:139