picox  0.1
xfifo_buffer.h
[詳解]
1 
14 /*
15  * License: MIT license
16  * Copyright (c) <2015> <MaskedW [maskedw00@gmail.com]>
17  *
18  * Permission is hereby granted, free of charge, to any person
19  * obtaining a copy of self software and associated documentation
20  * files (the "Software"), to deal in the Software without
21  * restriction, including without limitation the rights to use, copy,
22  * modify, merge, publish, distribute, sublicense, and/or sell copies
23  * of the Software, and to permit persons to whom the Software is
24  * furnished to do so, subject to the following conditions:
25  *
26  * The above copyright notice and self permission notice shall be
27  * included in all copies or substantial portions of the Software.
28  *
29  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
30  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
31  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
32  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
33  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
34  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
35  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
36  * SOFTWARE.
37  */
38 
39 #ifndef xfifo_h_
40 #define xfifo_h_
41 
42 
43 #include <picox/core/xcore.h>
44 
45 
54 #ifdef __cplusplus
55 extern "C" {
56 #endif // __cplusplus
57 
58 
60 typedef void(*XFifoAtomicAssigner)(size_t* dst, size_t value);
61 
62 
65 typedef struct XFifoBuffer
66 {
68  uint8_t* data;
69  size_t first;
70  size_t last;
71  size_t capacity;
72  XFifoAtomicAssigner assigner;
73 } XFifoBuffer;
74 
75 
76 /* 内部処理用のマクロ */
77 #define XFIFO__ADD_FIRST(x) ((self->first + x) & self->capacity)
78 #define XFIFO__ADD_LAST(x) ((self->last + x) & self->capacity)
79 
80 
81 static inline void
82 XFifoDefaultAtomicAssign(size_t* dst, size_t value)
83 {
84  *dst = value;
85 }
86 
87 
125 static inline void
126 xfifo_init(XFifoBuffer* self, void* buffer, size_t size, XFifoAtomicAssigner assigner)
127 {
128  X_ASSERT(self);
129  X_ASSERT(buffer);
130  X_ASSERT(x_is_power_of_two(size));
131  X_ASSERT(size > 0);
132 
133  self->data = buffer;
134  self->first = self->last = 0;
135  self->capacity = size - 1;
136 
137  if (! assigner)
138  self->assigner = XFifoDefaultAtomicAssign;
139  else
140  self->assigner = assigner;
141 }
142 
143 
146 static inline void
148 {
149  X_ASSERT(self);
150  self->last = self->first;
151 }
152 
153 
156 static inline bool
158 {
159  X_ASSERT(self);
160  return self->last == self->first;
161 }
162 
163 
166 static inline size_t
168 {
169  X_ASSERT(self);
170  return self->capacity;
171 }
172 
175 static inline size_t
177 {
178  X_ASSERT(self);
179  return (self->last - self->first) & self->capacity;
180 }
181 
182 
185 static inline bool
187 {
188  X_ASSERT(self);
189  return xfifo_size(self) == xfifo_capacity(self);
190 }
191 
192 
195 static inline size_t
197 {
198  X_ASSERT(self);
199  return xfifo_capacity(self) - xfifo_size(self);
200 }
201 
202 
205 static inline void*
207 {
208  X_ASSERT(self);
209  return self->data;
210 }
211 
212 
215 static inline void
216 xfifo_push(XFifoBuffer* self, uint8_t data)
217 {
218  X_ASSERT(self);
219  self->data[self->last] = data;
220  self->assigner(&self->last, XFIFO__ADD_LAST(1));
221 }
222 
223 
226 static inline uint8_t
228 {
229  X_ASSERT(self);
230  const uint8_t data = self->data[self->first];
231  self->assigner(&self->first, XFIFO__ADD_FIRST(1));
232 
233  return data;
234 }
235 
236 
246 static inline size_t
247 xfifo_write(XFifoBuffer* self, const void* src, size_t ssize)
248 {
249  X_ASSERT(self);
250  X_ASSERT(src);
251 
252  const size_t reserve = xfifo_reserve(self);
253 
254  if ((reserve <= 0) || (ssize <= 0) || (src == NULL))
255  return 0;
256 
257  /* 書き込む(書き込める)要素数 */
258  size_t to_write = (reserve >= ssize) ? ssize : reserve;
259 
260  /* to_writeは減算される可能性があるので保存しておく。*/
261  const size_t written = to_write;
262  volatile size_t wpos = self->last;
263  const size_t until_tail = xfifo_capacity(self) - wpos + 1;
264 
265  if (to_write > until_tail)
266  {
267  memcpy(&self->data[wpos], src, until_tail);
268  to_write -= until_tail;
269  src = (const char*)src + until_tail;
270  wpos = 0;
271  }
272  memcpy(&self->data[wpos], src, to_write);
273  self->assigner(&self->last, XFIFO__ADD_LAST(written));
274 
275  return written;
276 }
277 
278 
288 static inline size_t
289 xfifo_read(XFifoBuffer* self, void* dst, size_t dsize)
290 {
291  X_ASSERT(self);
292  X_ASSERT(dst);
293 
294  const size_t size = xfifo_size(self);
295 
296  if ((size <= 0) || (dsize <= 0) || (dst == NULL))
297  return 0;
298 
299  /* 読み込む(読み込める)要素数 */
300  size_t to_read = (size >= dsize) ? dsize : size;
301 
302  /* to_readは減算される可能性があるので保存しておく。 */
303  const size_t read = to_read;
304  volatile size_t rpos = self->first;
305  const size_t until_tail = xfifo_capacity(self) - rpos + 1;
306 
307  if (to_read > until_tail)
308  {
309  memcpy(dst, &self->data[rpos], until_tail);
310  to_read -= until_tail;
311  dst = (char*)dst + until_tail;
312  rpos = 0;
313  }
314  memcpy(dst, &self->data[rpos], to_read);
315  self->assigner(&self->first, XFIFO__ADD_FIRST(read));
316 
317  return read;
318 }
319 
320 
321 #undef XFIFO__ADD_FIRST
322 #undef XFIFO__ADD_LAST
323 #undef XFIFO__IS_POWER_OF_TWO
324 
325 
326 #ifdef __cplusplus
327 }
328 #endif // __cplusplus
329 
330 
336 #endif // xfifo_h_
static void * xfifo_data(const XFifoBuffer *self)
要素を格納するバッファを返します。
Definition: xfifo_buffer.h:206
static size_t xfifo_reserve(const XFifoBuffer *self)
空き要素数を返します。
Definition: xfifo_buffer.h:196
static size_t xfifo_write(XFifoBuffer *self, const void *src, size_t ssize)
FIFO末尾に指定サイズのデータの書き込みを試みます。
Definition: xfifo_buffer.h:247
static size_t xfifo_read(XFifoBuffer *self, void *dst, size_t dsize)
FIFO先頭から指定サイズのデータを読み込みを試みます。
Definition: xfifo_buffer.h:289
static void xfifo_clear(XFifoBuffer *self)
バッファを空にします。
Definition: xfifo_buffer.h:147
static uint8_t xfifo_pop(XFifoBuffer *self)
FIFO先頭から要素を取り出します。
Definition: xfifo_buffer.h:227
static bool xfifo_empty(const XFifoBuffer *self)
格納要素数が0かどうかを返します。
Definition: xfifo_buffer.h:157
static size_t xfifo_size(const XFifoBuffer *self)
格納要素数を返します。
Definition: xfifo_buffer.h:176
static bool xfifo_full(const XFifoBuffer *self)
要素数が上限かどうかを返します。
Definition: xfifo_buffer.h:186
static bool x_is_power_of_two(uint32_t x)
X_IS_POWER_OF_TWO()の関数版です。
Definition: xutils.h:329
static void xfifo_push(XFifoBuffer *self, uint8_t data)
FIFO末尾に要素を追加します。
Definition: xfifo_buffer.h:216
void(* XFifoAtomicAssigner)(size_t *dst, size_t value)
アトミックにsize_t変数に代入を行う関数ポインタ
Definition: xfifo_buffer.h:60
FIFOバイトバッファ管理構造体
Definition: xfifo_buffer.h:65
static void xfifo_init(XFifoBuffer *self, void *buffer, size_t size, XFifoAtomicAssigner assigner)
バッファを初期化します。
Definition: xfifo_buffer.h:126
static size_t xfifo_capacity(const XFifoBuffer *self)
最大格納要素数を返します。
Definition: xfifo_buffer.h:167