FreeRDP
TPCircularBuffer.h
1 //
2 // TPCircularBuffer.h
3 // Circular/Ring buffer implementation
4 //
5 // https://github.com/michaeltyson/TPCircularBuffer
6 //
7 // Created by Michael Tyson on 10/12/2011.
8 //
9 //
10 // This implementation makes use of a virtual memory mapping technique that inserts a virtual copy
11 // of the buffer memory directly after the buffer's end, negating the need for any buffer
12 // wrap-around logic. Clients can simply use the returned memory address as if it were contiguous
13 // space.
14 //
15 // The implementation is thread-safe in the case of a single producer and single consumer.
16 //
17 // Virtual memory technique originally proposed by Philip Howard (http://vrb.slashusr.org/), and
18 // adapted to Darwin by Kurt Revis (http://www.snoize.com,
19 // http://www.snoize.com/Code/PlayBufferedSoundFile.tar.gz)
20 //
21 //
22 // Copyright (C) 2012-2013 A Tasty Pixel
23 //
24 // This software is provided 'as-is', without any express or implied
25 // warranty. In no event will the authors be held liable for any damages
26 // arising from the use of this software.
27 //
28 // Permission is granted to anyone to use this software for any purpose,
29 // including commercial applications, and to alter it and redistribute it
30 // freely, subject to the following restrictions:
31 //
32 // 1. The origin of this software must not be misrepresented; you must not
33 // claim that you wrote the original software. If you use this software
34 // in a product, an acknowledgment in the product documentation would be
35 // appreciated but is not required.
36 //
37 // 2. Altered source versions must be plainly marked as such, and must not be
38 // misrepresented as being the original software.
39 //
40 // 3. This notice may not be removed or altered from any source distribution.
41 //
42 
43 #ifndef TPCircularBuffer_h
44 #define TPCircularBuffer_h
45 
46 #include <libkern/OSAtomic.h>
47 #include <string.h>
48 #include <winpr/assert.h>
49 
50 #ifdef __cplusplus
51 extern "C"
52 {
53 #endif
54 
55  typedef struct
56  {
57  void* buffer;
58  int32_t length;
59  int32_t tail;
60  int32_t head;
61  volatile int32_t fillCount;
63 
74  bool TPCircularBufferInit(TPCircularBuffer* buffer, int32_t length);
75 
81  void TPCircularBufferCleanup(TPCircularBuffer* buffer);
82 
91  void TPCircularBufferClear(TPCircularBuffer* buffer);
92 
93  // Reading (consuming)
94 
105  static __inline__ __attribute__((always_inline)) void*
106  TPCircularBufferTail(TPCircularBuffer* buffer, int32_t* availableBytes)
107  {
108  *availableBytes = buffer->fillCount;
109  if (*availableBytes == 0)
110  return NULL;
111  return (void*)((char*)buffer->buffer + buffer->tail);
112  }
113 
122  static __inline__ __attribute__((always_inline)) void
123  TPCircularBufferConsume(TPCircularBuffer* buffer, int32_t amount)
124  {
125  buffer->tail = (buffer->tail + amount) % buffer->length;
126  OSAtomicAdd32Barrier(-amount, &buffer->fillCount);
127  WINPR_ASSERT(buffer->fillCount >= 0);
128  }
129 
134  static __inline__ __attribute__((always_inline)) void
135  TPCircularBufferConsumeNoBarrier(TPCircularBuffer* buffer, int32_t amount)
136  {
137  buffer->tail = (buffer->tail + amount) % buffer->length;
138  buffer->fillCount -= amount;
139  WINPR_ASSERT(buffer->fillCount >= 0);
140  }
141 
152  static __inline__ __attribute__((always_inline)) void*
153  TPCircularBufferHead(TPCircularBuffer* buffer, int32_t* availableBytes)
154  {
155  *availableBytes = (buffer->length - buffer->fillCount);
156  if (*availableBytes == 0)
157  return NULL;
158  return (void*)((char*)buffer->buffer + buffer->head);
159  }
160 
161  // Writing (producing)
162 
171  static __inline__ __attribute__((always_inline)) void
172  TPCircularBufferProduce(TPCircularBuffer* buffer, int amount)
173  {
174  buffer->head = (buffer->head + amount) % buffer->length;
175  OSAtomicAdd32Barrier(amount, &buffer->fillCount);
176  WINPR_ASSERT(buffer->fillCount <= buffer->length);
177  }
178 
183  static __inline__ __attribute__((always_inline)) void
184  TPCircularBufferProduceNoBarrier(TPCircularBuffer* buffer, int amount)
185  {
186  buffer->head = (buffer->head + amount) % buffer->length;
187  buffer->fillCount += amount;
188  WINPR_ASSERT(buffer->fillCount <= buffer->length);
189  }
190 
201  static __inline__ __attribute__((always_inline)) bool
202  TPCircularBufferProduceBytes(TPCircularBuffer* buffer, const void* src, int32_t len)
203  {
204  int32_t space;
205  void* ptr = TPCircularBufferHead(buffer, &space);
206  if (space < len)
207  return false;
208  memcpy(ptr, src, len);
209  TPCircularBufferProduce(buffer, len);
210  return true;
211  }
212 
213 #ifdef __cplusplus
214 }
215 #endif
216 
217 #endif