FreeRDP
Loading...
Searching...
No Matches
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
51extern "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