BufQ.h 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581
  1. ////////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright 2016 RWS Inc, All Rights Reserved
  4. //
  5. // This program is free software; you can redistribute it and/or modify
  6. // it under the terms of version 2 of the GNU General Public License as published by
  7. // the Free Software Foundation
  8. //
  9. // This program is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU General Public License along
  15. // with this program; if not, write to the Free Software Foundation, Inc.,
  16. // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  17. //
  18. // BufQ.H
  19. //
  20. // History:
  21. // 05/24/97 JMI Started.
  22. //
  23. // 05/24/97 JMI Added UnGet().
  24. //
  25. // 08/14/97 MJR Moved everything into this header so that it would
  26. // inline, which is highly likely considering the small
  27. // size of these functions. Also reworked the endian
  28. // stuff so that the basic nature of the bufQ is to store
  29. // data in standard "network order", which is big endian.
  30. //
  31. // 08/15/97 MJR Changed GetFree() and GetUsed() to return non-linear
  32. // values instead of linear values.
  33. //
  34. // MJR Lots more cleaning up and fixed several serious bugs
  35. // that resulted from incorrect calculations of "linear"
  36. // bytes.
  37. //
  38. //////////////////////////////////////////////////////////////////////////////
  39. //
  40. // This class is designed as a simple means of accessing a circular buffer
  41. // in via two types of interfaces: { Get (deQ), Put (enQ) } and/or { LockBuf,
  42. // ReleaseBuf } styles.
  43. // Potentially bad schtuff:
  44. // - Safety on bad behavior for LockBuf/ReleaseBuf pairs is low.
  45. // - Since different types of data can be written w/o this class
  46. // storing what type it was, reads must be done with the same care
  47. // used when accessing files (i.e., either know the format of the data
  48. // explicitly or 'learn' it by data context).
  49. //
  50. //////////////////////////////////////////////////////////////////////////////
  51. #ifndef BUFQ_H
  52. #define BUFQ_H
  53. #include "System.h"
  54. //////////////////////////////////////////////////////////////////////////////
  55. //
  56. // This impliments a fast buffer queue.
  57. //
  58. // The queue is basically a circular buffer with a get position and a put
  59. // position.
  60. //
  61. // The get and put positions both start out at the same position, which
  62. // happens to be 0. Whenever the get and put positions are the same,
  63. // the queue is empty.
  64. //
  65. // Each time we put a byte to the queue, we put it at the current put
  66. // position and then increment the put position.
  67. //
  68. // Each time we get a byte from the queue, we get it from the current get
  69. // position and then increment the get position.
  70. //
  71. // When either position reaches the end of the queue, it wraps back around to
  72. // the beginning.
  73. //
  74. // When the put position is moved forward so many times that it "wraps
  75. // around" and ends up one position before the get position, then the queue
  76. // is considered full.
  77. //
  78. // Note that because of the way we detect whether the queue is full, we
  79. // need the queue's memory to be one byte larger than the desired "volume"
  80. // of the queue. In other words, if you want the queue to hold 100 bytes,
  81. // the memory buffer must be 101 bytes. Let's say both the get and put
  82. // positions start at 0 and we put 100 bytes into the queue. The put
  83. // position will now be at 100 (0 through 99 have been written to). The
  84. // put position is now 1 position before the get position, and the queue
  85. // is full. If we incremented the put position again, it would wrap around
  86. // and become equal to the get position. We can't let that happen, because
  87. // then we would consider the queue to be empty! Hence, we need that extra
  88. // byte to differentiate between empty and full.
  89. //
  90. //////////////////////////////////////////////////////////////////////////////
  91. class CBufQ
  92. {
  93. //----------------------------------------------------------------------------
  94. // Macros
  95. //----------------------------------------------------------------------------
  96. // Calculate the next position in the queue, relative to the specified position 'i'
  97. #define BUFQ_NEXT(i) (((i)+(short)1) >= QueueSize ? (short)0 : ((i)+(short)1))
  98. // Calculate the previous position in the queue, relative to the specified position 'i'
  99. #define BUFQ_PREV(i) (((i)-(short)1) >= 0 ? ((i)-(short)1) : (QueueSize-(short)1))
  100. //----------------------------------------------------------------------------
  101. // Types, enums, etc.
  102. //----------------------------------------------------------------------------
  103. public:
  104. enum
  105. {
  106. // This is the volume of the queue. In other words, how many bytes
  107. // it can actually hold before it is considered "full".
  108. QueueVolume = 4096,
  109. // This is the actual size (in bytes) of the queue's memory. It is
  110. // one larger than the volume so that we can tell the difference
  111. // between it being empty and full. See above for details.
  112. QueueSize
  113. };
  114. //----------------------------------------------------------------------------
  115. // Variables
  116. //----------------------------------------------------------------------------
  117. public:
  118. U8 m_au8Buf[QueueSize]; // Buffer.
  119. short m_sPutPos; // Current put position in buffer.
  120. short m_sGetPos; // Current get position in buffer.
  121. //----------------------------------------------------------------------------
  122. // Functions
  123. //----------------------------------------------------------------------------
  124. public:
  125. ///////////////////////////////////////////////////////////////////////////////
  126. // Default (and only) constructor
  127. ///////////////////////////////////////////////////////////////////////////////
  128. CBufQ()
  129. {
  130. Reset();
  131. }
  132. ///////////////////////////////////////////////////////////////////////////////
  133. // Destructor
  134. ///////////////////////////////////////////////////////////////////////////////
  135. ~CBufQ()
  136. {
  137. }
  138. ///////////////////////////////////////////////////////////////////////////////
  139. // Reset the queue
  140. ///////////////////////////////////////////////////////////////////////////////
  141. void Reset(void) // Returns nothing.
  142. {
  143. m_sPutPos = 0;
  144. m_sGetPos = 0;
  145. }
  146. ///////////////////////////////////////////////////////////////////////////////
  147. // Simple queries
  148. ///////////////////////////////////////////////////////////////////////////////
  149. // Determine whether queue is full
  150. bool IsFull(void)
  151. {
  152. return BUFQ_NEXT(m_sPutPos) == m_sGetPos;
  153. }
  154. // Determine whether queue is empty
  155. bool IsEmpty(void)
  156. {
  157. return m_sGetPos == m_sPutPos;
  158. }
  159. // Determine whether we can Put() another byte
  160. bool CanPutByte(void)
  161. {
  162. return BUFQ_NEXT(m_sPutPos) != m_sGetPos;
  163. }
  164. // Determine whether we can Get() another byte
  165. bool CanGetByte(void)
  166. {
  167. return m_sGetPos != m_sPutPos;
  168. }
  169. // Check how many bytes can be gotten via Get()
  170. long CheckGetable(void)
  171. {
  172. // Calculate total amount of used space in queue
  173. return (m_sGetPos <= m_sPutPos) ? m_sPutPos - m_sGetPos : QueueSize - m_sGetPos + m_sPutPos;
  174. }
  175. // Check how many bytes can be put via Put()
  176. long CheckPutable(void)
  177. {
  178. // Calculate total amount of free space in queue
  179. return (m_sPutPos < m_sGetPos) ? m_sGetPos - (m_sPutPos + 1) : QueueSize - (m_sPutPos + 1) + m_sGetPos;
  180. }
  181. // Check how many bytes can be gotten via LockGetPtr()
  182. long CheckLockGetPtr(void)
  183. {
  184. // We need to figure out how many bytes can be gotten from the queue
  185. // without wrapping around or hitting the put position.
  186. return (m_sGetPos <= m_sPutPos) ? m_sPutPos - m_sGetPos : QueueSize - m_sGetPos;
  187. }
  188. // Check how many bytes can be put via LockPutPtr()
  189. long CheckLockPutPtr(void)
  190. {
  191. // We need to figure out how many bytes can be put to the queue without
  192. // wrapping around or hitting the get position. A special case exists
  193. // when the get position is at 0, because then we can't fill out to the
  194. // end of the queue, but must instead stop one byte before the end.
  195. long lPutable;
  196. if (m_sPutPos < m_sGetPos)
  197. lPutable = m_sGetPos - (m_sPutPos + 1);
  198. else
  199. {
  200. if (m_sGetPos)
  201. lPutable = QueueSize - m_sPutPos;
  202. else
  203. lPutable = QueueSize - (m_sPutPos + 1);
  204. }
  205. return lPutable;
  206. }
  207. ///////////////////////////////////////////////////////////////////////////////
  208. // Various flavors of Put()
  209. ///////////////////////////////////////////////////////////////////////////////
  210. long Put( // Returns 1 if it fit, 0 if not enough room in queue
  211. U8 u8Val) // In: Data to enqueue in buffer.
  212. {
  213. long lResult = 0;
  214. if (CanPutByte())
  215. {
  216. *(m_au8Buf + m_sPutPos) = u8Val;
  217. m_sPutPos = BUFQ_NEXT(m_sPutPos);
  218. lResult++;
  219. }
  220. return lResult;
  221. }
  222. long Put( // Returns number of items that were put into queue
  223. U8* pu8Buf, // In: Data to enqueue in buffer.
  224. long lNum = 1) // In: Number of bytes to put.
  225. {
  226. long lNumPut = -1;
  227. while (++lNumPut < lNum)
  228. {
  229. if (!Put(*pu8Buf++))
  230. break;
  231. }
  232. return lNumPut;
  233. }
  234. long Put( // Returns 1 if it fit, 0 if not enough room in queue
  235. S8 s8Val) // In: Data to enqueue in buffer.
  236. {
  237. return Put((U8)s8Val);
  238. }
  239. long Put( // Returns number of items that were put into queue
  240. S8* ps8Buf, // In: Data to enqueue in buffer.
  241. long lNum = 1) // In: Number of bytes to put.
  242. {
  243. return Put((U8*)ps8Buf, lNum);
  244. }
  245. long Put( // Returns number of items that were put into queue
  246. void* pvBuf, // In: Data to enqueue in buffer.
  247. long lNum) // In: Number of bytes to put.
  248. {
  249. return Put((U8*)pvBuf, lNum);
  250. }
  251. long Put( // Returns number of items that were put into queue
  252. U16* pu16Buf, // In: Data to enqueue in buffer.
  253. long lNum = 1) // In: Number of U16s to put.
  254. {
  255. long lNumPut = -1;
  256. U8* pu8Buf = (U8*)pu16Buf;
  257. #ifdef SYS_ENDIAN_BIG
  258. while (++lNumPut < lNum)
  259. {
  260. Put(*pu8Buf++);
  261. if (!Put(*pu8Buf++))
  262. break;
  263. }
  264. #else
  265. while (++lNumPut < lNum)
  266. {
  267. Put(*(pu8Buf + 1));
  268. if (!Put(*(pu8Buf + 0)))
  269. break;
  270. pu8Buf += 2;
  271. }
  272. #endif
  273. return lNumPut;
  274. }
  275. long Put( // Returns number of items that were put into queue
  276. S16* ps16Buf, // In: Data to enqueue in buffer.
  277. long lNum = 1) // In: Number of S16s to put.
  278. {
  279. return Put((U16*)ps16Buf, lNum);
  280. }
  281. long Put( // Returns 1 if it fit, 0 if not enough room in queue
  282. U16 u16Val) // In: Data to enqueue in buffer.
  283. {
  284. return Put(&u16Val);
  285. }
  286. long Put( // Returns 1 if it fit, 0 if not enough room in queue
  287. S16 s16Val) // In: Data to enqueue in buffer.
  288. {
  289. return Put(&s16Val);
  290. }
  291. long Put( // Returns number of items that were put into queue
  292. U32* pu32Buf, // In: Data to enqueue in buffer.
  293. long lNum = 1) // In: Number of U32s to put.
  294. {
  295. long lNumPut = -1;
  296. U8* pu8Buf = (U8*)pu32Buf;
  297. #ifdef SYS_ENDIAN_BIG
  298. while (++lNumPut < lNum)
  299. {
  300. Put(*pu8Buf++);
  301. Put(*pu8Buf++);
  302. Put(*pu8Buf++);
  303. if (!Put(*pu8Buf++))
  304. break;
  305. }
  306. #else
  307. while (++lNumPut < lNum)
  308. {
  309. Put(*(pu8Buf + 3));
  310. Put(*(pu8Buf + 2));
  311. Put(*(pu8Buf + 1));
  312. if (!Put(*(pu8Buf + 0)))
  313. break;
  314. pu8Buf += 4;
  315. }
  316. #endif
  317. return lNumPut;
  318. }
  319. long Put( // Returns number of items that were put into queue
  320. S32* ps32Buf, // In: Data to enqueue in buffer.
  321. long lNum = 1) // In: Number of S32s to put.
  322. {
  323. return Put((U32*)ps32Buf, lNum);
  324. }
  325. long Put( // Returns 1 if it fit, 0 if not enough room in queue
  326. U32 u32Val) // In: Data to enqueue in buffer.
  327. {
  328. return Put(&u32Val);
  329. }
  330. long Put( // Returns 1 if it fit, 0 if not enough room in queue
  331. S32 s32Val) // In: Data to enqueue in buffer.
  332. {
  333. return Put(&s32Val);
  334. }
  335. ///////////////////////////////////////////////////////////////////////////////
  336. // Various flavors of Get()
  337. ///////////////////////////////////////////////////////////////////////////////
  338. long Get( // Returns 1 if item was dequeued, 0 otherwise
  339. U8* pu8Val) // Out: Where to dequeue from buffer.
  340. {
  341. long lNumGot = 0;
  342. if (CanGetByte())
  343. {
  344. *pu8Val = *(m_au8Buf + m_sGetPos);
  345. m_sGetPos = BUFQ_NEXT(m_sGetPos);
  346. lNumGot++;
  347. }
  348. return lNumGot;
  349. }
  350. long Get( // Returns number of items dequeued.
  351. U8* pu8Buf, // Out: Where to dequeue from buffer.
  352. long lNum) // In: Number of bytes to get.
  353. {
  354. long lNumGot = -1;
  355. while (++lNumGot < lNum)
  356. {
  357. if (!Get(pu8Buf++))
  358. break;
  359. }
  360. return lNumGot;
  361. }
  362. long Get( // Returns number of items dequeued.
  363. S8* ps8Buf, // Out: Where to dequeue from buffer.
  364. long lNum = 1) // In: Number of bytes to get.
  365. {
  366. return Get((U8*)ps8Buf, lNum);
  367. }
  368. long Get( // Returns number of items dequeued
  369. void* pvBuf, // Out: Where to dequeue from buffer.
  370. long lNum) // In: Number of bytes to get.
  371. {
  372. return Get((U8*)pvBuf, lNum);
  373. }
  374. long Get( // Returns number of items dequeued.
  375. U16* pu16Buf, // Out: Where to dequeue from buffer.
  376. long lNum = 1) // In: Number of U16s to get.
  377. {
  378. long lNumGot = -1;
  379. U8* pu8Buf = (U8*)pu16Buf;
  380. #ifdef SYS_ENDIAN_BIG
  381. while (++lNumGot < lNum)
  382. {
  383. Get(pu8Buf++);
  384. if (!Get(pu8Buf++))
  385. break;
  386. }
  387. #else
  388. while (++lNumGot < lNum)
  389. {
  390. Get(pu8Buf + 1);
  391. if (!Get(pu8Buf + 0))
  392. break;
  393. pu8Buf += 2;
  394. }
  395. #endif
  396. return lNumGot;
  397. }
  398. long Get( // Returns number of items dequeued.
  399. S16* ps16Buf, // Out: Where to dequeue from buffer.
  400. long lNum = 1) // In: Number of S16s to get.
  401. {
  402. return Get((U16*)ps16Buf, lNum);
  403. }
  404. long Get( // Returns number of items dequeued.
  405. U32* pu32Buf, // Out: Where to dequeue from buffer.
  406. long lNum = 1) // In: Number of U32s to get.
  407. {
  408. long lNumGot = -1;
  409. U8* pu8Buf = (U8*)pu32Buf;
  410. #ifdef SYS_ENDIAN_BIG
  411. while (++lNumGot < lNum)
  412. {
  413. Get(pu8Buf++);
  414. Get(pu8Buf++);
  415. Get(pu8Buf++);
  416. if (!Get(pu8Buf++))
  417. break;
  418. }
  419. #else
  420. while (++lNumGot < lNum)
  421. {
  422. Get(pu8Buf + 3);
  423. Get(pu8Buf + 2);
  424. Get(pu8Buf + 1);
  425. if (!Get(pu8Buf + 0))
  426. break;
  427. pu8Buf += 4;
  428. }
  429. #endif
  430. return lNumGot;
  431. }
  432. long Get( // Returns number of items dequeued.
  433. S32* ps32Buf, // Out: Where to dequeue from buffer.
  434. long lNum = 1) // In: Number of S32s to get.
  435. {
  436. return Get((U32*)ps32Buf, lNum);
  437. }
  438. ///////////////////////////////////////////////////////////////////////////////
  439. // Un-put a byte. Can be called repeatedly until all data has been "removed".
  440. // Use caution when mixing with other functions, especially UnGet().
  441. ///////////////////////////////////////////////////////////////////////////////
  442. short UnPut(void) // Returns 1 if able to unput, 0 if nothing to unput
  443. {
  444. short sResult = 0;
  445. // Being able to get a byte also happens to indicate that we can unput a byte!
  446. // In other words, if we can move the get pointer forward 1 byte, it means we
  447. // can instead move the put pointer back 1 byte. Get it?
  448. if (CanGetByte())
  449. {
  450. // Move the put position back by 1 byte
  451. m_sPutPos = BUFQ_PREV(m_sPutPos);
  452. sResult++;
  453. }
  454. return sResult;
  455. }
  456. ///////////////////////////////////////////////////////////////////////////////
  457. // Un-Get a byte. Can be called repeatedly until all data has been "restored".
  458. // Use caution when mixing with other functions, especially UnPut().
  459. ///////////////////////////////////////////////////////////////////////////////
  460. short UnGet(void) // Returns 1 if able to unget, 0 if nothing to unget
  461. {
  462. short sResult = 0;
  463. // Being able to put a byte also happens to indicate that we can unput a byte!
  464. // In other words, if we can move the put pointer forward 1 byte, it means we
  465. // can instead move the get pointer back 1 byte. Get it?
  466. if (CanPutByte())
  467. {
  468. // Move the get position back by 1 byte
  469. m_sGetPos = BUFQ_PREV(m_sGetPos);
  470. sResult++;
  471. }
  472. return sResult;
  473. }
  474. ///////////////////////////////////////////////////////////////////////////////
  475. // Lock down the put ptr so you can write directly into the buffer.
  476. // Don't forget to release this ptr with ReleasePutPtr()!!!!
  477. ///////////////////////////////////////////////////////////////////////////////
  478. void LockPutPtr(
  479. U8** ppu8Put, // Out: Pointer to which up to *plAmountAvail bytes can be put
  480. long* plAvail) // Out: Number of bytes that can be put to above pointer
  481. {
  482. *plAvail = CheckLockPutPtr();
  483. *ppu8Put = m_au8Buf + m_sPutPos;
  484. }
  485. ///////////////////////////////////////////////////////////////////////////////
  486. // Release a put ptr previously locked with LockPutPtr().
  487. // This function is indiscriminant and will screw you if you lie!
  488. ///////////////////////////////////////////////////////////////////////////////
  489. void ReleasePutPtr(
  490. long lBytes) // In: Number of bytes written to locked pointer
  491. {
  492. ASSERT(lBytes <= CheckLockPutPtr());
  493. m_sPutPos += lBytes;
  494. if (m_sPutPos == QueueSize)
  495. m_sPutPos = 0;
  496. }
  497. ///////////////////////////////////////////////////////////////////////////////
  498. // Lock down the get ptr so you can read directly from the buffer.
  499. // Don't forget to release this ptr with ReleaseGetPtr()!!!!
  500. ///////////////////////////////////////////////////////////////////////////////
  501. void LockGetPtr(
  502. U8** ppu8Get, // Out: Pointer from which up to *plAmountAvail bytes can be gotten
  503. long* plAvail) // Out: Number of bytes that can be gotten from above pointer
  504. {
  505. *plAvail = CheckLockGetPtr();
  506. *ppu8Get = m_au8Buf + m_sGetPos;
  507. }
  508. ///////////////////////////////////////////////////////////////////////////////
  509. // Release a get ptr previously locked with LockGetPtr().
  510. // This function is indiscriminant and will screw you if you lie!
  511. ///////////////////////////////////////////////////////////////////////////////
  512. void ReleaseGetPtr(
  513. long lBytes) // In: Number of bytes that were gotten from locked pointer
  514. {
  515. ASSERT(lBytes <= CheckLockGetPtr());
  516. m_sGetPos += lBytes;
  517. if (m_sGetPos == QueueSize)
  518. m_sGetPos = 0;
  519. }
  520. };
  521. #endif // BUFQ_H
  522. //////////////////////////////////////////////////////////////////////////////
  523. // EOF
  524. //////////////////////////////////////////////////////////////////////////////