| |
1 /* |
| |
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. |
| |
3 * |
| |
4 * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved. |
| |
5 * |
| |
6 * Redistribution and use in source and binary forms, with or without |
| |
7 * modification, are permitted provided that the following conditions are met: |
| |
8 * |
| |
9 * 1. Redistributions of source code must retain the above copyright |
| |
10 * notice, this list of conditions and the following disclaimer. |
| |
11 * |
| |
12 * 2. Redistributions in binary form must reproduce the above copyright |
| |
13 * notice, this list of conditions and the following disclaimer in the |
| |
14 * documentation and/or other materials provided with the distribution. |
| |
15 * |
| |
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
| |
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| |
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| |
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE |
| |
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| |
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| |
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| |
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| |
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| |
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
| |
26 * POSSIBILITY OF SUCH DAMAGE. |
| |
27 */ |
| |
28 |
| |
29 /** |
| |
30 * \file buffer.h |
| |
31 * |
| |
32 * \brief Advanced buffer implementation. |
| |
33 * |
| |
34 * Instances of CxBuffer can be used to read from or to write to like one |
| |
35 * would do with a stream. |
| |
36 * |
| |
37 * Some features for convenient use of the buffer |
| |
38 * can be enabled. See the documentation of the macro constants for more |
| |
39 * information. |
| |
40 * |
| |
41 * \author Mike Becker |
| |
42 * \author Olaf Wintermann |
| |
43 * \copyright 2-Clause BSD License |
| |
44 */ |
| |
45 |
| |
46 #ifndef UCX_BUFFER_H |
| |
47 #define UCX_BUFFER_H |
| |
48 |
| |
49 #include "common.h" |
| |
50 #include "allocator.h" |
| |
51 |
| |
52 #ifdef __cplusplus |
| |
53 extern "C" { |
| |
54 #endif |
| |
55 |
| |
56 /** |
| |
57 * No buffer features enabled (all flags cleared). |
| |
58 */ |
| |
59 #define CX_BUFFER_DEFAULT 0x00 |
| |
60 |
| |
61 /** |
| |
62 * If this flag is enabled, the buffer will automatically free its contents when destroyed. |
| |
63 */ |
| |
64 #define CX_BUFFER_FREE_CONTENTS 0x01 |
| |
65 |
| |
66 /** |
| |
67 * If this flag is enabled, the buffer will automatically extends its capacity. |
| |
68 */ |
| |
69 #define CX_BUFFER_AUTO_EXTEND 0x02 |
| |
70 |
| |
71 /** Structure for the UCX buffer data. */ |
| |
72 typedef struct { |
| |
73 /** A pointer to the buffer contents. */ |
| |
74 union { |
| |
75 /** |
| |
76 * Data is interpreted as text. |
| |
77 */ |
| |
78 char *space; |
| |
79 /** |
| |
80 * Data is interpreted as binary. |
| |
81 */ |
| |
82 unsigned char *bytes; |
| |
83 }; |
| |
84 /** The allocator to use for automatic memory management. */ |
| |
85 CxAllocator const *allocator; |
| |
86 /** Current position of the buffer. */ |
| |
87 size_t pos; |
| |
88 /** Current capacity (i.e. maximum size) of the buffer. */ |
| |
89 size_t capacity; |
| |
90 /** Current size of the buffer content. */ |
| |
91 size_t size; |
| |
92 /** |
| |
93 * The buffer may not extend beyond this threshold before starting to flush. |
| |
94 * Default is \c SIZE_MAX (flushing disabled when auto extension is enabled). |
| |
95 */ |
| |
96 size_t flush_threshold; |
| |
97 /** |
| |
98 * The block size for the elements to flush. |
| |
99 * Default is 4096 bytes. |
| |
100 */ |
| |
101 size_t flush_blksize; |
| |
102 /** |
| |
103 * The maximum number of blocks to flush in one cycle. |
| |
104 * Zero disables flushing entirely (this is the default). |
| |
105 * Set this to \c SIZE_MAX to flush the entire buffer. |
| |
106 * |
| |
107 * @attention if the maximum number of blocks multiplied with the block size |
| |
108 * is smaller than the expected contents written to this buffer within one write |
| |
109 * operation, multiple flush cycles are performed after that write. |
| |
110 * That means the total number of blocks flushed after one write to this buffer may |
| |
111 * be larger than \c flush_blkmax. |
| |
112 */ |
| |
113 size_t flush_blkmax; |
| |
114 |
| |
115 /** |
| |
116 * The write function used for flushing. |
| |
117 * If NULL, the flushed content gets discarded. |
| |
118 */ |
| |
119 cx_write_func flush_func; |
| |
120 |
| |
121 /** |
| |
122 * The target for \c flush_func. |
| |
123 */ |
| |
124 void *flush_target; |
| |
125 |
| |
126 /** |
| |
127 * Flag register for buffer features. |
| |
128 * @see #CX_BUFFER_DEFAULT |
| |
129 * @see #CX_BUFFER_FREE_CONTENTS |
| |
130 * @see #CX_BUFFER_AUTO_EXTEND |
| |
131 */ |
| |
132 int flags; |
| |
133 } cx_buffer_s; |
| |
134 |
| |
135 /** |
| |
136 * UCX buffer. |
| |
137 */ |
| |
138 typedef cx_buffer_s CxBuffer; |
| |
139 |
| |
140 /** |
| |
141 * Initializes a fresh buffer. |
| |
142 * |
| |
143 * \note You may provide \c NULL as argument for \p space. |
| |
144 * Then this function will allocate the space and enforce |
| |
145 * the #CX_BUFFER_FREE_CONTENTS flag. |
| |
146 * |
| |
147 * @param buffer the buffer to initialize |
| |
148 * @param space pointer to the memory area, or \c NULL to allocate |
| |
149 * new memory |
| |
150 * @param capacity the capacity of the buffer |
| |
151 * @param allocator the allocator this buffer shall use for automatic |
| |
152 * memory management. If \c NULL, the default heap allocator will be used. |
| |
153 * @param flags buffer features (see cx_buffer_s.flags) |
| |
154 * @return zero on success, non-zero if a required allocation failed |
| |
155 */ |
| |
156 __attribute__((__nonnull__(1))) |
| |
157 int cxBufferInit( |
| |
158 CxBuffer *buffer, |
| |
159 void *space, |
| |
160 size_t capacity, |
| |
161 CxAllocator const *allocator, |
| |
162 int flags |
| |
163 ); |
| |
164 |
| |
165 /** |
| |
166 * Allocates and initializes a fresh buffer. |
| |
167 * |
| |
168 * \note You may provide \c NULL as argument for \p space. |
| |
169 * Then this function will allocate the space and enforce |
| |
170 * the #CX_BUFFER_FREE_CONTENTS flag. |
| |
171 * |
| |
172 * @param space pointer to the memory area, or \c NULL to allocate |
| |
173 * new memory |
| |
174 * @param capacity the capacity of the buffer |
| |
175 * @param allocator the allocator to use for allocating the structure and the automatic |
| |
176 * memory management within the buffer. If \c NULL, the default heap allocator will be used. |
| |
177 * @param flags buffer features (see cx_buffer_s.flags) |
| |
178 * @return a pointer to the buffer on success, \c NULL if a required allocation failed |
| |
179 */ |
| |
180 CxBuffer *cxBufferCreate( |
| |
181 void *space, |
| |
182 size_t capacity, |
| |
183 CxAllocator const *allocator, |
| |
184 int flags |
| |
185 ); |
| |
186 |
| |
187 /** |
| |
188 * Destroys the buffer contents. |
| |
189 * |
| |
190 * Has no effect if the #CX_BUFFER_FREE_CONTENTS feature is not enabled. |
| |
191 * If you want to free the memory of the entire buffer, use cxBufferFree(). |
| |
192 * |
| |
193 * @param buffer the buffer which contents shall be destroyed |
| |
194 * @see cxBufferInit() |
| |
195 */ |
| |
196 __attribute__((__nonnull__)) |
| |
197 void cxBufferDestroy(CxBuffer *buffer); |
| |
198 |
| |
199 /** |
| |
200 * Deallocates the buffer. |
| |
201 * |
| |
202 * If the #CX_BUFFER_FREE_CONTENTS feature is enabled, this function also destroys |
| |
203 * the contents. If you \em only want to destroy the contents, use cxBufferDestroy(). |
| |
204 * |
| |
205 * @param buffer the buffer to deallocate |
| |
206 * @see cxBufferCreate() |
| |
207 */ |
| |
208 __attribute__((__nonnull__)) |
| |
209 void cxBufferFree(CxBuffer *buffer); |
| |
210 |
| |
211 /** |
| |
212 * Shifts the contents of the buffer by the given offset. |
| |
213 * |
| |
214 * If the offset is positive, the contents are shifted to the right. |
| |
215 * If auto extension is enabled, the buffer grows, if necessary. |
| |
216 * In case the auto extension fails, this function returns a non-zero value and |
| |
217 * no contents are changed. |
| |
218 * If auto extension is disabled, the contents that do not fit into the buffer |
| |
219 * are discarded. |
| |
220 * |
| |
221 * If the offset is negative, the contents are shifted to the left where the |
| |
222 * first \p shift bytes are discarded. |
| |
223 * The new size of the buffer is the old size minus the absolute shift value. |
| |
224 * If this value is larger than the buffer size, the buffer is emptied (but |
| |
225 * not cleared, see the security note below). |
| |
226 * |
| |
227 * The buffer position gets shifted alongside with the content but is kept |
| |
228 * within the boundaries of the buffer. |
| |
229 * |
| |
230 * \note For situations where \c off_t is not large enough, there are specialized cxBufferShiftLeft() and |
| |
231 * cxBufferShiftRight() functions using a \c size_t as parameter type. |
| |
232 * |
| |
233 * \attention |
| |
234 * Security Note: The shifting operation does \em not erase the previously occupied memory cells. |
| |
235 * But you can easily do that manually, e.g. by calling |
| |
236 * <code>memset(buffer->bytes, 0, shift)</code> for a right shift or |
| |
237 * <code>memset(buffer->bytes + buffer->size, 0, buffer->capacity - buffer->size)</code> |
| |
238 * for a left shift. |
| |
239 * |
| |
240 * @param buffer the buffer |
| |
241 * @param shift the shift offset (negative means left shift) |
| |
242 * @return 0 on success, non-zero if a required auto-extension fails |
| |
243 */ |
| |
244 __attribute__((__nonnull__)) |
| |
245 int cxBufferShift( |
| |
246 CxBuffer *buffer, |
| |
247 off_t shift |
| |
248 ); |
| |
249 |
| |
250 /** |
| |
251 * Shifts the buffer to the right. |
| |
252 * See cxBufferShift() for details. |
| |
253 * |
| |
254 * @param buffer the buffer |
| |
255 * @param shift the shift offset |
| |
256 * @return 0 on success, non-zero if a required auto-extension fails |
| |
257 * @see cxBufferShift() |
| |
258 */ |
| |
259 __attribute__((__nonnull__)) |
| |
260 int cxBufferShiftRight( |
| |
261 CxBuffer *buffer, |
| |
262 size_t shift |
| |
263 ); |
| |
264 |
| |
265 /** |
| |
266 * Shifts the buffer to the left. |
| |
267 * See cxBufferShift() for details. |
| |
268 * |
| |
269 * \note Since a left shift cannot fail due to memory allocation problems, this |
| |
270 * function always returns zero. |
| |
271 * |
| |
272 * @param buffer the buffer |
| |
273 * @param shift the positive shift offset |
| |
274 * @return always zero |
| |
275 * @see cxBufferShift() |
| |
276 */ |
| |
277 __attribute__((__nonnull__)) |
| |
278 int cxBufferShiftLeft( |
| |
279 CxBuffer *buffer, |
| |
280 size_t shift |
| |
281 ); |
| |
282 |
| |
283 |
| |
284 /** |
| |
285 * Moves the position of the buffer. |
| |
286 * |
| |
287 * The new position is relative to the \p whence argument. |
| |
288 * |
| |
289 * \li \c SEEK_SET marks the start of the buffer. |
| |
290 * \li \c SEEK_CUR marks the current position. |
| |
291 * \li \c SEEK_END marks the end of the buffer. |
| |
292 * |
| |
293 * With an offset of zero, this function sets the buffer position to zero |
| |
294 * (\c SEEK_SET), the buffer size (\c SEEK_END) or leaves the buffer position |
| |
295 * unchanged (\c SEEK_CUR). |
| |
296 * |
| |
297 * @param buffer the buffer |
| |
298 * @param offset position offset relative to \p whence |
| |
299 * @param whence one of \c SEEK_SET, \c SEEK_CUR or \c SEEK_END |
| |
300 * @return 0 on success, non-zero if the position is invalid |
| |
301 * |
| |
302 */ |
| |
303 __attribute__((__nonnull__)) |
| |
304 int cxBufferSeek( |
| |
305 CxBuffer *buffer, |
| |
306 off_t offset, |
| |
307 int whence |
| |
308 ); |
| |
309 |
| |
310 /** |
| |
311 * Clears the buffer by resetting the position and deleting the data. |
| |
312 * |
| |
313 * The data is deleted by zeroing it with a call to memset(). |
| |
314 * If you do not need that, you can use the faster cxBufferReset(). |
| |
315 * |
| |
316 * @param buffer the buffer to be cleared |
| |
317 * @see cxBufferReset() |
| |
318 */ |
| |
319 __attribute__((__nonnull__)) |
| |
320 void cxBufferClear(CxBuffer *buffer); |
| |
321 |
| |
322 /** |
| |
323 * Resets the buffer by resetting the position and size to zero. |
| |
324 * |
| |
325 * The data in the buffer is not deleted. If you need a safe |
| |
326 * reset of the buffer, use cxBufferClear(). |
| |
327 * |
| |
328 * @param buffer the buffer to be cleared |
| |
329 * @see cxBufferClear() |
| |
330 */ |
| |
331 __attribute__((__nonnull__)) |
| |
332 void cxBufferReset(CxBuffer *buffer); |
| |
333 |
| |
334 /** |
| |
335 * Tests, if the buffer position has exceeded the buffer size. |
| |
336 * |
| |
337 * @param buffer the buffer to test |
| |
338 * @return non-zero, if the current buffer position has exceeded the last |
| |
339 * byte of the buffer's contents. |
| |
340 */ |
| |
341 __attribute__((__nonnull__)) |
| |
342 int cxBufferEof(CxBuffer const *buffer); |
| |
343 |
| |
344 |
| |
345 /** |
| |
346 * Ensures that the buffer has a minimum capacity. |
| |
347 * |
| |
348 * If the current capacity is not sufficient, the buffer will be extended. |
| |
349 * |
| |
350 * @param buffer the buffer |
| |
351 * @param capacity the minimum required capacity for this buffer |
| |
352 * @return 0 on success or a non-zero value on failure |
| |
353 */ |
| |
354 __attribute__((__nonnull__)) |
| |
355 int cxBufferMinimumCapacity( |
| |
356 CxBuffer *buffer, |
| |
357 size_t capacity |
| |
358 ); |
| |
359 |
| |
360 /** |
| |
361 * Writes data to a CxBuffer. |
| |
362 * |
| |
363 * If flushing is enabled and the buffer needs to flush, the data is flushed to |
| |
364 * the target until the target signals that it cannot take more data by |
| |
365 * returning zero via the respective write function. In that case, the remaining |
| |
366 * data in this buffer is shifted to the beginning of this buffer so that the |
| |
367 * newly available space can be used to append as much data as possible. This |
| |
368 * function only stops writing more elements, when the flush target and this |
| |
369 * buffer are both incapable of taking more data or all data has been written. |
| |
370 * The number returned by this function is the total number of elements that |
| |
371 * could be written during the process. It does not necessarily mean that those |
| |
372 * elements are still in this buffer, because some of them could have also be |
| |
373 * flushed already. |
| |
374 * |
| |
375 * If automatic flushing is not enabled, the position of the buffer is increased |
| |
376 * by the number of bytes written. |
| |
377 * |
| |
378 * \note The signature is compatible with the fwrite() family of functions. |
| |
379 * |
| |
380 * @param ptr a pointer to the memory area containing the bytes to be written |
| |
381 * @param size the length of one element |
| |
382 * @param nitems the element count |
| |
383 * @param buffer the CxBuffer to write to |
| |
384 * @return the total count of elements written |
| |
385 */ |
| |
386 __attribute__((__nonnull__)) |
| |
387 size_t cxBufferWrite( |
| |
388 void const *ptr, |
| |
389 size_t size, |
| |
390 size_t nitems, |
| |
391 CxBuffer *buffer |
| |
392 ); |
| |
393 |
| |
394 /** |
| |
395 * Reads data from a CxBuffer. |
| |
396 * |
| |
397 * The position of the buffer is increased by the number of bytes read. |
| |
398 * |
| |
399 * \note The signature is compatible with the fread() family of functions. |
| |
400 * |
| |
401 * @param ptr a pointer to the memory area where to store the read data |
| |
402 * @param size the length of one element |
| |
403 * @param nitems the element count |
| |
404 * @param buffer the CxBuffer to read from |
| |
405 * @return the total number of elements read |
| |
406 */ |
| |
407 __attribute__((__nonnull__)) |
| |
408 size_t cxBufferRead( |
| |
409 void *ptr, |
| |
410 size_t size, |
| |
411 size_t nitems, |
| |
412 CxBuffer *buffer |
| |
413 ); |
| |
414 |
| |
415 /** |
| |
416 * Writes a character to a buffer. |
| |
417 * |
| |
418 * The least significant byte of the argument is written to the buffer. If the |
| |
419 * end of the buffer is reached and #CX_BUFFER_AUTO_EXTEND feature is enabled, |
| |
420 * the buffer capacity is extended by cxBufferMinimumCapacity(). If the feature is |
| |
421 * disabled or buffer extension fails, \c EOF is returned. |
| |
422 * |
| |
423 * On successful write, the position of the buffer is increased. |
| |
424 * |
| |
425 * @param buffer the buffer to write to |
| |
426 * @param c the character to write |
| |
427 * @return the byte that has bean written or \c EOF when the end of the stream is |
| |
428 * reached and automatic extension is not enabled or not possible |
| |
429 */ |
| |
430 __attribute__((__nonnull__)) |
| |
431 int cxBufferPut( |
| |
432 CxBuffer *buffer, |
| |
433 int c |
| |
434 ); |
| |
435 |
| |
436 /** |
| |
437 * Writes a string to a buffer. |
| |
438 * |
| |
439 * @param buffer the buffer |
| |
440 * @param str the zero-terminated string |
| |
441 * @return the number of bytes written |
| |
442 */ |
| |
443 __attribute__((__nonnull__)) |
| |
444 size_t cxBufferPutString( |
| |
445 CxBuffer *buffer, |
| |
446 const char *str |
| |
447 ); |
| |
448 |
| |
449 /** |
| |
450 * Gets a character from a buffer. |
| |
451 * |
| |
452 * The current position of the buffer is increased after a successful read. |
| |
453 * |
| |
454 * @param buffer the buffer to read from |
| |
455 * @return the character or \c EOF, if the end of the buffer is reached |
| |
456 */ |
| |
457 __attribute__((__nonnull__)) |
| |
458 int cxBufferGet(CxBuffer *buffer); |
| |
459 |
| |
460 #ifdef __cplusplus |
| |
461 } |
| |
462 #endif |
| |
463 |
| |
464 #endif // UCX_BUFFER_H |