ringbuffer.h 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. /*
  2. * Copyright 2010-2012 Branimir Karadzic. All rights reserved.
  3. * License: http://www.opensource.org/licenses/BSD-2-Clause
  4. */
  5. #ifndef __BX_RINGBUFFER_H__
  6. #define __BX_RINGBUFFER_H__
  7. #include "bx.h"
  8. #include "cpu.h"
  9. #include "uint32_t.h"
  10. namespace bx
  11. {
  12. class RingBufferControl
  13. {
  14. public:
  15. RingBufferControl(uint32_t _size)
  16. : m_size(_size)
  17. , m_current(0)
  18. , m_write(0)
  19. , m_read(0)
  20. {
  21. }
  22. ~RingBufferControl()
  23. {
  24. }
  25. uint32_t available() const
  26. {
  27. return distance(m_read, m_current);
  28. }
  29. uint32_t consume(uint32_t _size) // consumer only
  30. {
  31. const uint32_t maxSize = distance(m_read, m_current);
  32. const uint32_t sizeNoSign = uint32_and(_size, 0x7FFFFFFF);
  33. const uint32_t test = uint32_sub(sizeNoSign, maxSize);
  34. const uint32_t size = uint32_sels(test, _size, maxSize);
  35. const uint32_t advance = uint32_add(m_read, size);
  36. const uint32_t read = uint32_mod(advance, m_size);
  37. m_read = read;
  38. return size;
  39. }
  40. uint32_t reserve(uint32_t _size) // producer only
  41. {
  42. const uint32_t dist = distance(m_write, m_read)-1;
  43. const uint32_t maxSize = uint32_sels(dist, m_size-1, dist);
  44. const uint32_t sizeNoSign = uint32_and(_size, 0x7FFFFFFF);
  45. const uint32_t test = uint32_sub(sizeNoSign, maxSize);
  46. const uint32_t size = uint32_sels(test, _size, maxSize);
  47. const uint32_t advance = uint32_add(m_write, size);
  48. const uint32_t write = uint32_mod(advance, m_size);
  49. m_write = write;
  50. return size;
  51. }
  52. uint32_t commit(uint32_t _size) // producer only
  53. {
  54. const uint32_t maxSize = distance(m_current, m_write);
  55. const uint32_t sizeNoSign = uint32_and(_size, 0x7FFFFFFF);
  56. const uint32_t test = uint32_sub(sizeNoSign, maxSize);
  57. const uint32_t size = uint32_sels(test, _size, maxSize);
  58. const uint32_t advance = uint32_add(m_current, size);
  59. const uint32_t current = uint32_mod(advance, m_size);
  60. m_current = current;
  61. return size;
  62. }
  63. uint32_t distance(uint32_t _from, uint32_t _to) const // both
  64. {
  65. const uint32_t diff = uint32_sub(_to, _from);
  66. const uint32_t le = uint32_add(m_size, diff);
  67. const uint32_t result = uint32_sels(diff, le, diff);
  68. return result;
  69. }
  70. const uint32_t m_size;
  71. uint32_t m_current;
  72. uint32_t m_write;
  73. uint32_t m_read;
  74. private:
  75. RingBufferControl(const RingBufferControl&);
  76. void operator=(const RingBufferControl&);
  77. };
  78. class SpScRingBufferControl
  79. {
  80. public:
  81. SpScRingBufferControl(uint32_t _size)
  82. : m_size(_size)
  83. , m_current(0)
  84. , m_write(0)
  85. , m_read(0)
  86. {
  87. }
  88. ~SpScRingBufferControl()
  89. {
  90. }
  91. uint32_t available() const
  92. {
  93. return distance(m_read, m_current);
  94. }
  95. uint32_t consume(uint32_t _size) // consumer only
  96. {
  97. const uint32_t maxSize = distance(m_read, m_current);
  98. const uint32_t sizeNoSign = uint32_and(_size, 0x7FFFFFFF);
  99. const uint32_t test = uint32_sub(sizeNoSign, maxSize);
  100. const uint32_t size = uint32_sels(test, _size, maxSize);
  101. const uint32_t advance = uint32_add(m_read, size);
  102. const uint32_t read = uint32_mod(advance, m_size);
  103. m_read = read;
  104. return size;
  105. }
  106. uint32_t reserve(uint32_t _size) // producer only
  107. {
  108. const uint32_t dist = distance(m_write, m_read)-1;
  109. const uint32_t maxSize = uint32_sels(dist, m_size-1, dist);
  110. const uint32_t sizeNoSign = uint32_and(_size, 0x7FFFFFFF);
  111. const uint32_t test = uint32_sub(sizeNoSign, maxSize);
  112. const uint32_t size = uint32_sels(test, _size, maxSize);
  113. const uint32_t advance = uint32_add(m_write, size);
  114. const uint32_t write = uint32_mod(advance, m_size);
  115. m_write = write;
  116. return size;
  117. }
  118. uint32_t commit(uint32_t _size) // producer only
  119. {
  120. const uint32_t maxSize = distance(m_current, m_write);
  121. const uint32_t sizeNoSign = uint32_and(_size, 0x7FFFFFFF);
  122. const uint32_t test = uint32_sub(sizeNoSign, maxSize);
  123. const uint32_t size = uint32_sels(test, _size, maxSize);
  124. const uint32_t advance = uint32_add(m_current, size);
  125. const uint32_t current = uint32_mod(advance, m_size);
  126. // must commit all memory writes before moving m_current pointer
  127. // once m_current pointer moves data is used by consumer thread
  128. memoryBarrier();
  129. m_current = current;
  130. return size;
  131. }
  132. uint32_t distance(uint32_t _from, uint32_t _to) const // both
  133. {
  134. const uint32_t diff = uint32_sub(_to, _from);
  135. const uint32_t le = uint32_add(m_size, diff);
  136. const uint32_t result = uint32_sels(diff, le, diff);
  137. return result;
  138. }
  139. const uint32_t m_size;
  140. uint32_t m_current;
  141. uint32_t m_write;
  142. uint32_t m_read;
  143. private:
  144. SpScRingBufferControl(const SpScRingBufferControl&);
  145. void operator=(const SpScRingBufferControl&);
  146. };
  147. template <typename Control>
  148. class ReadRingBufferT
  149. {
  150. public:
  151. ReadRingBufferT(Control& _control, const char* _buffer, uint32_t _size)
  152. : m_control(_control)
  153. , m_read(_control.m_read)
  154. , m_end(m_read+_size)
  155. , m_size(_size)
  156. , m_buffer(_buffer)
  157. {
  158. BX_CHECK(_control.available() >= _size, "%d >= %d", _control.available(), _size);
  159. }
  160. ~ReadRingBufferT()
  161. {
  162. }
  163. void end()
  164. {
  165. m_control.consume(m_size);
  166. }
  167. void read(char* _data, uint32_t _len)
  168. {
  169. const uint32_t end = (m_read + _len) % m_control.m_size;
  170. uint32_t wrap = 0;
  171. const char* from = &m_buffer[m_read];
  172. if (end < m_read)
  173. {
  174. wrap = m_control.m_size - m_read;
  175. memcpy(_data, from, wrap);
  176. _data += wrap;
  177. from = (const char*)&m_buffer[0];
  178. }
  179. memcpy(_data, from, _len-wrap);
  180. m_read = end;
  181. }
  182. void skip(uint32_t _len)
  183. {
  184. m_read += _len;
  185. m_read %= m_control.m_size;
  186. }
  187. private:
  188. template <typename Ty>
  189. friend class WriteRingBufferT;
  190. ReadRingBufferT();
  191. ReadRingBufferT(const Control&);
  192. void operator=(const Control&);
  193. Control& m_control;
  194. uint32_t m_read;
  195. uint32_t m_end;
  196. const uint32_t m_size;
  197. const char* m_buffer;
  198. };
  199. typedef ReadRingBufferT<RingBufferControl> ReadRingBuffer;
  200. typedef ReadRingBufferT<SpScRingBufferControl> SpScReadRingBuffer;
  201. template <typename Control>
  202. class WriteRingBufferT
  203. {
  204. public:
  205. WriteRingBufferT(Control& _control, char* _buffer, uint32_t _size)
  206. : m_control(_control)
  207. , m_size(_size)
  208. , m_buffer(_buffer)
  209. {
  210. uint32_t size = m_control.reserve(_size);
  211. BX_UNUSED(size);
  212. BX_CHECK(size == _size, "%d == %d", size, _size);
  213. m_write = m_control.m_current;
  214. m_end = m_write+_size;
  215. }
  216. ~WriteRingBufferT()
  217. {
  218. }
  219. void end()
  220. {
  221. m_control.commit(m_size);
  222. }
  223. void write(const char* _data, uint32_t _len)
  224. {
  225. const uint32_t end = (m_write + _len) % m_control.m_size;
  226. uint32_t wrap = 0;
  227. char* to = &m_buffer[m_write];
  228. if (end < m_write)
  229. {
  230. wrap = m_control.m_size - m_write;
  231. memcpy(to, _data, wrap);
  232. _data += wrap;
  233. to = (char*)&m_buffer[0];
  234. }
  235. memcpy(to, _data, _len-wrap);
  236. m_write = end;
  237. }
  238. void write(ReadRingBufferT<Control>& _read, uint32_t _len)
  239. {
  240. const uint32_t end = (_read.m_read + _len) % _read.m_control.m_size;
  241. uint32_t wrap = 0;
  242. const char* from = &_read.m_buffer[_read.m_read];
  243. if (end < _read.m_read)
  244. {
  245. wrap = _read.m_control.m_size - _read.m_read;
  246. write(from, wrap);
  247. from = (const char*)&_read.m_buffer[0];
  248. }
  249. write(from, _len-wrap);
  250. _read.m_read = end;
  251. }
  252. void skip(uint32_t _len)
  253. {
  254. m_write += _len;
  255. m_write %= m_control.m_size;
  256. }
  257. private:
  258. WriteRingBufferT();
  259. WriteRingBufferT(const WriteRingBufferT<Control>&);
  260. void operator=(const WriteRingBufferT<Control>&);
  261. Control& m_control;
  262. uint32_t m_write;
  263. uint32_t m_end;
  264. const uint32_t m_size;
  265. char* m_buffer;
  266. };
  267. typedef WriteRingBufferT<RingBufferControl> WriteRingBuffer;
  268. typedef WriteRingBufferT<SpScRingBufferControl> SpScWriteRingBuffer;
  269. } // namespace bx
  270. #endif // __BX_RINGBUFFER_H__