1
0

RingBuffer.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464
  1. /*
  2. * RingBuffer.cpp
  3. * Lock-free ring buffer data structure.
  4. * One thread can be consumer and one can be producer
  5. *
  6. * Created by Ben Allison on 11/10/07.
  7. * Copyright 2007 Nullsoft, Inc. All rights reserved.
  8. *
  9. */
  10. #include "RingBuffer.h"
  11. #include "foundation/error.h"
  12. #include "foundation/types.h"
  13. #include <stdlib.h>
  14. #include <string.h>
  15. #include <stdint.h>
  16. #define MIN(a,b) ((a<b)?(a):(b))
  17. RingBuffer::RingBuffer()
  18. {
  19. ringBuffer = 0;
  20. ringBufferSize = 0;
  21. ringBufferUsed = 0;
  22. ringWritePosition = 0;
  23. ringReadPosition = 0;
  24. }
  25. RingBuffer::~RingBuffer()
  26. {
  27. if ( ringBuffer )
  28. free( ringBuffer );
  29. ringBuffer = 0;
  30. }
  31. void RingBuffer::Reset()
  32. {
  33. if ( ringBuffer )
  34. free( ringBuffer );
  35. ringBuffer = 0;
  36. }
  37. bool RingBuffer::reserve( size_t bytes )
  38. {
  39. Reset();
  40. ringBufferSize = bytes;
  41. ringBuffer = (char *)calloc( ringBufferSize, sizeof( char ) );
  42. if ( !ringBuffer )
  43. return false;
  44. clear();
  45. return true;
  46. }
  47. int RingBuffer::expand( size_t bytes )
  48. {
  49. if ( bytes > ringBufferSize )
  50. {
  51. char *new_buffer = (char *)realloc( ringBuffer, bytes );
  52. if ( !new_buffer )
  53. return NErr_OutOfMemory;
  54. size_t write_offset = ringReadPosition - ringBuffer;
  55. size_t read_offset = ringWritePosition - ringBuffer;
  56. /* update write pointer for the new buffer */
  57. ringWritePosition = new_buffer + write_offset;
  58. if ( write_offset > read_offset || !ringBufferUsed ) /* ringBufferUsed will resolve the ambiguity when ringWritePosition == ringReadPosition */
  59. {
  60. /* the ring buffer looks like [ RXXXW ], so we don't need to move anything.
  61. Just update the read pointer */
  62. ringReadPosition = new_buffer + write_offset;
  63. }
  64. else
  65. {
  66. /* [XXW RXX] needs to become [XXW RXX] */
  67. size_t end_bytes = ringBufferSize - read_offset; // number of bytes that we need to relocate (the RXX portion)
  68. char *new_read_pointer = &new_buffer[ bytes - end_bytes ];
  69. memmove( new_read_pointer, ringReadPosition, end_bytes );
  70. ringReadPosition = new_read_pointer; /* update read pointer */
  71. }
  72. ringBufferSize = bytes;
  73. ringBuffer = new_buffer;
  74. return NErr_Success;
  75. }
  76. else
  77. return NErr_NoAction;
  78. }
  79. bool RingBuffer::empty() const
  80. {
  81. return ( ringBufferUsed == 0 );
  82. }
  83. size_t RingBuffer::read( void *dest, size_t len )
  84. {
  85. int8_t *out = (int8_t *)dest; // lets us do pointer math easier
  86. size_t toCopy = MIN( ringBufferUsed, len );
  87. size_t copied = 0;
  88. len -= toCopy;
  89. // read to the end of the ring buffer
  90. size_t end = ringBufferSize - ( ringReadPosition - ringBuffer );
  91. size_t read1 = MIN( end, toCopy );
  92. memcpy( out, ringReadPosition, read1 );
  93. copied += read1;
  94. ringReadPosition += read1;
  95. if ( ringReadPosition == ringBuffer + ringBufferSize )
  96. ringReadPosition = ringBuffer;
  97. // update positions
  98. ringBufferUsed -= read1;
  99. toCopy -= read1;
  100. out = (int8_t *)out + read1;
  101. // see if we still have more to read after wrapping around
  102. if ( toCopy )
  103. {
  104. memcpy( out, ringReadPosition, toCopy );
  105. copied += toCopy;
  106. ringReadPosition += toCopy;
  107. ringBufferUsed -= toCopy;
  108. if ( ringReadPosition == ringBuffer + ringBufferSize )
  109. ringReadPosition = ringBuffer;
  110. }
  111. return copied;
  112. }
  113. size_t RingBuffer::at( size_t offset, void *dest, size_t len ) const
  114. {
  115. size_t toCopy = ringBufferUsed;
  116. // make a local copy of this so we don't blow the original
  117. char *ringReadPosition = this->ringReadPosition;
  118. /* --- do a "dummy read" to deal with the offset request --- */
  119. size_t dummy_end = ringBufferSize - ( ringReadPosition - ringBuffer );
  120. offset = MIN( toCopy, offset );
  121. size_t read0 = MIN( dummy_end, offset );
  122. ringReadPosition += read0;
  123. if ( ringReadPosition == ringBuffer + ringBufferSize )
  124. ringReadPosition = ringBuffer;
  125. // update positions
  126. toCopy -= read0;
  127. offset -= read0;
  128. // do second-half read (wraparound)
  129. if ( offset )
  130. {
  131. ringReadPosition += offset;
  132. toCopy -= offset;
  133. }
  134. // dummy read done
  135. /* --- set up destination buffer and copy size --- */
  136. int8_t *out = (int8_t *)dest; // lets us do pointer math easier
  137. if ( toCopy > len )
  138. toCopy = len;
  139. size_t copied = 0;
  140. /* --- read to the end of the ring buffer --- */
  141. size_t end = ringBufferSize - ( ringReadPosition - ringBuffer );
  142. size_t read1 = MIN( end, toCopy );
  143. memcpy( out, ringReadPosition, read1 );
  144. copied += read1;
  145. ringReadPosition += read1;
  146. if ( ringReadPosition == ringBuffer + ringBufferSize )
  147. ringReadPosition = ringBuffer;
  148. // update positions
  149. toCopy -= read1;
  150. out = (int8_t *)out + read1;
  151. /* --- see if we still have more to read after wrapping around --- */
  152. if ( toCopy )
  153. {
  154. memcpy( out, ringReadPosition, toCopy );
  155. copied += toCopy;
  156. ringReadPosition += toCopy;
  157. }
  158. return copied;
  159. }
  160. size_t RingBuffer::peek( void *dest, size_t len ) const
  161. {
  162. int8_t *out = (int8_t *)dest; // lets us do pointer math easier
  163. size_t toCopy = MIN( ringBufferUsed, len );
  164. size_t copied = 0;
  165. // make a local copy of this so we don't blow the original
  166. char *ringReadPosition = this->ringReadPosition;
  167. // read to the end of the ring buffer
  168. size_t end = ringBufferSize - ( ringReadPosition - ringBuffer );
  169. size_t read1 = MIN( end, toCopy );
  170. memcpy( out, ringReadPosition, read1 );
  171. copied += read1;
  172. ringReadPosition += read1;
  173. if ( ringReadPosition == ringBuffer + ringBufferSize )
  174. ringReadPosition = ringBuffer;
  175. // update positions
  176. toCopy -= read1;
  177. out = (int8_t *)out + read1;
  178. // see if we still have more to read after wrapping around
  179. if ( toCopy )
  180. {
  181. memcpy( out, ringReadPosition, toCopy );
  182. copied += toCopy;
  183. ringReadPosition += toCopy;
  184. }
  185. return copied;
  186. }
  187. size_t RingBuffer::advance( size_t len )
  188. {
  189. size_t toCopy = MIN( ringBufferUsed, len );
  190. size_t copied = 0;
  191. len -= toCopy;
  192. // read to the end of the ring buffer
  193. size_t end = ringBufferSize - ( ringReadPosition - ringBuffer );
  194. size_t read1 = MIN( end, toCopy );
  195. copied += read1;
  196. ringReadPosition += read1;
  197. if ( ringReadPosition == ringBuffer + ringBufferSize )
  198. ringReadPosition = ringBuffer;
  199. // update positions
  200. toCopy -= read1;
  201. ringBufferUsed -= read1;
  202. // see if we still have more to read after wrapping around
  203. if ( toCopy )
  204. {
  205. copied += toCopy;
  206. ringReadPosition += toCopy;
  207. ringBufferUsed -= toCopy;
  208. if ( ringReadPosition == ringBuffer + ringBufferSize )
  209. ringReadPosition = ringBuffer;
  210. }
  211. return copied;
  212. }
  213. size_t RingBuffer::avail() const
  214. {
  215. return ringBufferSize - ringBufferUsed;
  216. }
  217. size_t RingBuffer::write( const void *buffer, size_t bytes )
  218. {
  219. size_t used = ringBufferUsed;
  220. size_t avail = ringBufferSize - used;
  221. bytes = MIN( avail, bytes );
  222. // write to the end of the ring buffer
  223. size_t end = ringBufferSize - ( ringWritePosition - ringBuffer );
  224. size_t copied = 0;
  225. size_t write1 = MIN( end, bytes );
  226. memcpy( ringWritePosition, buffer, write1 );
  227. copied += write1;
  228. ringWritePosition += write1;
  229. if ( ringWritePosition == ringBuffer + ringBufferSize )
  230. ringWritePosition = ringBuffer;
  231. // update positions
  232. ringBufferUsed += write1;
  233. bytes -= write1;
  234. buffer = (const int8_t *)buffer + write1;
  235. // see if we still have more to write after wrapping around
  236. if ( bytes )
  237. {
  238. memcpy( ringWritePosition, buffer, bytes );
  239. copied += bytes;
  240. ringWritePosition += bytes;
  241. ringBufferUsed += bytes;
  242. if ( ringWritePosition == ringBuffer + ringBufferSize )
  243. ringWritePosition = ringBuffer;
  244. }
  245. return copied;
  246. }
  247. size_t RingBuffer::drain( Drainer *drainer, size_t max_bytes )
  248. {
  249. // read to the end of the ring buffer
  250. size_t used = ringBufferUsed;
  251. size_t bytes = used;
  252. bytes = MIN( bytes, max_bytes );
  253. size_t copied = 0;
  254. size_t end = ringBufferSize - ( ringReadPosition - ringBuffer );
  255. size_t drain1 = MIN( end, bytes );
  256. if ( !drain1 )
  257. return 0;
  258. size_t read1 = drainer->Write( ringReadPosition, drain1 );
  259. if ( read1 == 0 )
  260. return 0;
  261. copied += read1;
  262. ringReadPosition += read1;
  263. if ( ringReadPosition == ringBuffer + ringBufferSize )
  264. ringReadPosition = ringBuffer;
  265. // update positions
  266. ringBufferUsed -= read1;
  267. bytes -= read1;
  268. // see if we still have more to read after wrapping around
  269. if ( drain1 == read1 && bytes )
  270. {
  271. size_t read2 = drainer->Write( ringReadPosition, bytes );
  272. copied += read2;
  273. ringReadPosition += read2;
  274. ringBufferUsed -= read2;
  275. if ( ringReadPosition == ringBuffer + ringBufferSize )
  276. ringReadPosition = ringBuffer;
  277. }
  278. return copied;
  279. }
  280. size_t RingBuffer::fill( Filler *filler, size_t max_bytes )
  281. {
  282. // write to the end of the ring buffer
  283. size_t used = ringBufferUsed;
  284. size_t bytes = ringBufferSize - used;
  285. bytes = MIN( bytes, max_bytes );
  286. size_t copied = 0;
  287. size_t end = ringBufferSize - ( ringWritePosition - ringBuffer );
  288. size_t fill1 = MIN( end, bytes );
  289. if ( !fill1 )
  290. return 0;
  291. size_t write1 = filler->Read( ringWritePosition, fill1 );
  292. if ( write1 == 0 )
  293. return 0;
  294. copied += write1;
  295. ringWritePosition += write1;
  296. if ( ringWritePosition == ringBuffer + ringBufferSize )
  297. ringWritePosition = ringBuffer;
  298. // update positions
  299. ringBufferUsed += write1;
  300. bytes -= write1;
  301. // see if we still have more to write after wrapping around
  302. if ( fill1 == write1 && bytes )
  303. {
  304. size_t write2 = filler->Read( ringWritePosition, bytes );
  305. copied += write2;
  306. ringWritePosition += write2;
  307. ringBufferUsed += write2;
  308. if ( ringWritePosition == ringBuffer + ringBufferSize )
  309. ringWritePosition = ringBuffer;
  310. }
  311. return copied;
  312. }
  313. size_t RingBuffer::size() const
  314. {
  315. return ringBufferUsed;
  316. }
  317. void RingBuffer::clear()
  318. {
  319. ringBufferUsed = 0;
  320. ringWritePosition = ringBuffer;
  321. ringReadPosition = ringBuffer;
  322. }
  323. void *RingBuffer::LockBuffer()
  324. {
  325. return ringBuffer;
  326. }
  327. void RingBuffer::UnlockBuffer( size_t written )
  328. {
  329. ringWritePosition = ringBuffer + written;
  330. ringBufferUsed = written;
  331. }
  332. size_t RingBuffer::write_position() const
  333. {
  334. return (size_t)ringWritePosition;
  335. }
  336. size_t RingBuffer::read_position() const
  337. {
  338. return (size_t)ringReadPosition;
  339. }
  340. void RingBuffer::get_read_buffer( size_t bytes, const void **buffer, size_t *bytes_available ) const
  341. {
  342. size_t toCopy = MIN( ringBufferUsed, bytes );
  343. // read to the end of the ring buffer
  344. size_t end = ringBufferSize - ( ringReadPosition - ringBuffer );
  345. *bytes_available = MIN( end, toCopy );
  346. *buffer = ringReadPosition;
  347. }