| 47 #define UCX_BUFFER_H |
47 #define UCX_BUFFER_H |
| 48 |
48 |
| 49 #include "common.h" |
49 #include "common.h" |
| 50 #include "allocator.h" |
50 #include "allocator.h" |
| 51 |
51 |
| 52 #ifdef __cplusplus |
52 #ifdef __cplusplus |
| 53 extern "C" { |
53 extern "C" { |
| 54 #endif |
54 #endif |
| 55 |
55 |
| 56 /** |
56 /** |
| 57 * No buffer features enabled (all flags cleared). |
57 * No buffer features enabled (all flags cleared). |
| 58 */ |
58 */ |
| 59 #define CX_BUFFER_DEFAULT 0x00 |
59 #define CX_BUFFER_DEFAULT 0x00 |
| 60 |
60 |
| 61 /** |
61 /** |
| 62 * If this flag is enabled, the buffer will automatically free its contents when destroyed. |
62 * If this flag is enabled, the buffer will automatically free its contents when destroyed. |
| |
63 * |
| |
64 * Do NOT set this flag together with #CX_BUFFER_COPY_ON_WRITE. It will be automatically |
| |
65 * set when the copy-on-write operations is performed. |
| 63 */ |
66 */ |
| 64 #define CX_BUFFER_FREE_CONTENTS 0x01 |
67 #define CX_BUFFER_FREE_CONTENTS 0x01 |
| 65 |
68 |
| 66 /** |
69 /** |
| 67 * If this flag is enabled, the buffer will automatically extends its capacity. |
70 * If this flag is enabled, the buffer will automatically extend its capacity. |
| 68 */ |
71 */ |
| 69 #define CX_BUFFER_AUTO_EXTEND 0x02 |
72 #define CX_BUFFER_AUTO_EXTEND 0x02 |
| |
73 |
| |
74 /** |
| |
75 * If this flag is enabled, the buffer will allocate new memory when written to. |
| |
76 * |
| |
77 * The current contents of the buffer will be copied to the new memory and the flag |
| |
78 * will be cleared while the #CX_BUFFER_FREE_CONTENTS flag will be set automatically. |
| |
79 */ |
| |
80 #define CX_BUFFER_COPY_ON_WRITE 0x04 |
| |
81 |
| |
82 /** |
| |
83 * If this flag is enabled, the buffer will copy its contents to a new memory area on reallocation. |
| |
84 * |
| |
85 * After performing the copy, the flag is automatically cleared. |
| |
86 * This flag has no effect on buffers which do not have #CX_BUFFER_AUTO_EXTEND set, which is why |
| |
87 * buffers automatically admit the auto-extend flag when initialized with copy-on-extend enabled. |
| |
88 */ |
| |
89 #define CX_BUFFER_COPY_ON_EXTEND 0x08 |
| 70 |
90 |
| 71 /** Structure for the UCX buffer data. */ |
91 /** Structure for the UCX buffer data. */ |
| 72 typedef struct { |
92 typedef struct { |
| 73 /** A pointer to the buffer contents. */ |
93 /** A pointer to the buffer contents. */ |
| 74 union { |
94 union { |
| 138 typedef cx_buffer_s CxBuffer; |
159 typedef cx_buffer_s CxBuffer; |
| 139 |
160 |
| 140 /** |
161 /** |
| 141 * Initializes a fresh buffer. |
162 * Initializes a fresh buffer. |
| 142 * |
163 * |
| |
164 * You may also provide a read-only \p space, in which case |
| |
165 * you will need to cast the pointer, and you should set the |
| |
166 * #CX_BUFFER_COPY_ON_WRITE flag. |
| |
167 * |
| |
168 * You need to set the size manually after initialization, if |
| |
169 * you provide \p space which already contains data. |
| |
170 * |
| |
171 * When you specify stack memory as \p space and decide to use |
| |
172 * the auto-extension feature, you \em must use the |
| |
173 * #CX_BUFFER_COPY_ON_EXTEND flag, instead of the |
| |
174 * #CX_BUFFER_AUTO_EXTEND flag. |
| |
175 * |
| 143 * \note You may provide \c NULL as argument for \p space. |
176 * \note You may provide \c NULL as argument for \p space. |
| 144 * Then this function will allocate the space and enforce |
177 * Then this function will allocate the space and enforce |
| 145 * the #CX_BUFFER_FREE_CONTENTS flag. |
178 * the #CX_BUFFER_FREE_CONTENTS flag. In that case, specifying |
| |
179 * copy-on-write should be avoided, because the allocated |
| |
180 * space will be leaking after the copy-on-write operation. |
| 146 * |
181 * |
| 147 * @param buffer the buffer to initialize |
182 * @param buffer the buffer to initialize |
| 148 * @param space pointer to the memory area, or \c NULL to allocate |
183 * @param space pointer to the memory area, or \c NULL to allocate |
| 149 * new memory |
184 * new memory |
| 150 * @param capacity the capacity of the buffer |
185 * @param capacity the capacity of the buffer |
| 151 * @param allocator the allocator this buffer shall use for automatic |
186 * @param allocator the allocator this buffer shall use for automatic |
| 152 * memory management. If \c NULL, the default heap allocator will be used. |
187 * memory management |
| |
188 * (if \c NULL, a default stdlib allocator will be used) |
| 153 * @param flags buffer features (see cx_buffer_s.flags) |
189 * @param flags buffer features (see cx_buffer_s.flags) |
| 154 * @return zero on success, non-zero if a required allocation failed |
190 * @return zero on success, non-zero if a required allocation failed |
| 155 */ |
191 */ |
| 156 __attribute__((__nonnull__(1))) |
192 cx_attr_nonnull_arg(1) |
| 157 int cxBufferInit( |
193 int cxBufferInit( |
| 158 CxBuffer *buffer, |
194 CxBuffer *buffer, |
| 159 void *space, |
195 void *space, |
| 160 size_t capacity, |
196 size_t capacity, |
| 161 CxAllocator const *allocator, |
197 const CxAllocator *allocator, |
| 162 int flags |
198 int flags |
| 163 ); |
199 ); |
| 164 |
200 |
| 165 /** |
201 /** |
| |
202 * Destroys the buffer contents. |
| |
203 * |
| |
204 * Has no effect if the #CX_BUFFER_FREE_CONTENTS feature is not enabled. |
| |
205 * If you want to free the memory of the entire buffer, use cxBufferFree(). |
| |
206 * |
| |
207 * @param buffer the buffer which contents shall be destroyed |
| |
208 * @see cxBufferInit() |
| |
209 */ |
| |
210 cx_attr_nonnull |
| |
211 void cxBufferDestroy(CxBuffer *buffer); |
| |
212 |
| |
213 /** |
| |
214 * Deallocates the buffer. |
| |
215 * |
| |
216 * If the #CX_BUFFER_FREE_CONTENTS feature is enabled, this function also destroys |
| |
217 * the contents. If you \em only want to destroy the contents, use cxBufferDestroy(). |
| |
218 * |
| |
219 * \remark As with all free() functions, this accepts \c NULL arguments in which |
| |
220 * case it does nothing. |
| |
221 * |
| |
222 * @param buffer the buffer to deallocate |
| |
223 * @see cxBufferCreate() |
| |
224 */ |
| |
225 void cxBufferFree(CxBuffer *buffer); |
| |
226 |
| |
227 /** |
| 166 * Allocates and initializes a fresh buffer. |
228 * Allocates and initializes a fresh buffer. |
| |
229 * |
| |
230 * You may also provide a read-only \p space, in which case |
| |
231 * you will need to cast the pointer, and you should set the |
| |
232 * #CX_BUFFER_COPY_ON_WRITE flag. |
| |
233 * When you specify stack memory as \p space and decide to use |
| |
234 * the auto-extension feature, you \em must use the |
| |
235 * #CX_BUFFER_COPY_ON_EXTEND flag, instead of the |
| |
236 * #CX_BUFFER_AUTO_EXTEND flag. |
| 167 * |
237 * |
| 168 * \note You may provide \c NULL as argument for \p space. |
238 * \note You may provide \c NULL as argument for \p space. |
| 169 * Then this function will allocate the space and enforce |
239 * Then this function will allocate the space and enforce |
| 170 * the #CX_BUFFER_FREE_CONTENTS flag. |
240 * the #CX_BUFFER_FREE_CONTENTS flag. |
| 171 * |
241 * |
| 172 * @param space pointer to the memory area, or \c NULL to allocate |
242 * @param space pointer to the memory area, or \c NULL to allocate |
| 173 * new memory |
243 * new memory |
| 174 * @param capacity the capacity of the buffer |
244 * @param capacity the capacity of the buffer |
| 175 * @param allocator the allocator to use for allocating the structure and the automatic |
245 * @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. |
246 * memory management within the buffer |
| |
247 * (if \c NULL, a default stdlib allocator will be used) |
| 177 * @param flags buffer features (see cx_buffer_s.flags) |
248 * @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 |
249 * @return a pointer to the buffer on success, \c NULL if a required allocation failed |
| 179 */ |
250 */ |
| |
251 cx_attr_malloc |
| |
252 cx_attr_dealloc(cxBufferFree, 1) |
| |
253 cx_attr_nodiscard |
| 180 CxBuffer *cxBufferCreate( |
254 CxBuffer *cxBufferCreate( |
| 181 void *space, |
255 void *space, |
| 182 size_t capacity, |
256 size_t capacity, |
| 183 CxAllocator const *allocator, |
257 const CxAllocator *allocator, |
| 184 int flags |
258 int flags |
| 185 ); |
259 ); |
| 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 |
260 |
| 211 /** |
261 /** |
| 212 * Shifts the contents of the buffer by the given offset. |
262 * Shifts the contents of the buffer by the given offset. |
| 213 * |
263 * |
| 214 * If the offset is positive, the contents are shifted to the right. |
264 * If the offset is positive, the contents are shifted to the right. |
| 251 * Shifts the buffer to the right. |
301 * Shifts the buffer to the right. |
| 252 * See cxBufferShift() for details. |
302 * See cxBufferShift() for details. |
| 253 * |
303 * |
| 254 * @param buffer the buffer |
304 * @param buffer the buffer |
| 255 * @param shift the shift offset |
305 * @param shift the shift offset |
| 256 * @return 0 on success, non-zero if a required auto-extension fails |
306 * @return 0 on success, non-zero if a required auto-extension or copy-on-write fails |
| 257 * @see cxBufferShift() |
307 * @see cxBufferShift() |
| 258 */ |
308 */ |
| 259 __attribute__((__nonnull__)) |
309 cx_attr_nonnull |
| 260 int cxBufferShiftRight( |
310 int cxBufferShiftRight( |
| 261 CxBuffer *buffer, |
311 CxBuffer *buffer, |
| 262 size_t shift |
312 size_t shift |
| 263 ); |
313 ); |
| 264 |
314 |
| 265 /** |
315 /** |
| 266 * Shifts the buffer to the left. |
316 * Shifts the buffer to the left. |
| 267 * See cxBufferShift() for details. |
317 * See cxBufferShift() for details. |
| 268 * |
318 * |
| 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 |
319 * @param buffer the buffer |
| 273 * @param shift the positive shift offset |
320 * @param shift the positive shift offset |
| 274 * @return always zero |
321 * @return usually zero, except the buffer uses copy-on-write and the allocation fails |
| 275 * @see cxBufferShift() |
322 * @see cxBufferShift() |
| 276 */ |
323 */ |
| 277 __attribute__((__nonnull__)) |
324 cx_attr_nonnull |
| 278 int cxBufferShiftLeft( |
325 int cxBufferShiftLeft( |
| 279 CxBuffer *buffer, |
326 CxBuffer *buffer, |
| 280 size_t shift |
327 size_t shift |
| 281 ); |
328 ); |
| 282 |
329 |
| 381 * @param size the length of one element |
432 * @param size the length of one element |
| 382 * @param nitems the element count |
433 * @param nitems the element count |
| 383 * @param buffer the CxBuffer to write to |
434 * @param buffer the CxBuffer to write to |
| 384 * @return the total count of elements written |
435 * @return the total count of elements written |
| 385 */ |
436 */ |
| 386 __attribute__((__nonnull__)) |
437 cx_attr_nonnull |
| 387 size_t cxBufferWrite( |
438 size_t cxBufferWrite( |
| 388 void const *ptr, |
439 const void *ptr, |
| |
440 size_t size, |
| |
441 size_t nitems, |
| |
442 CxBuffer *buffer |
| |
443 ); |
| |
444 |
| |
445 /** |
| |
446 * Appends data to a CxBuffer. |
| |
447 * |
| |
448 * The data is always appended to current data within the buffer, |
| |
449 * regardless of the current position. |
| |
450 * This is especially useful when the buffer is primarily meant for reading |
| |
451 * while additional data is added to the buffer occasionally. |
| |
452 * Consequently, the position of the buffer is unchanged after this operation. |
| |
453 * |
| |
454 * \note The signature is compatible with the fwrite() family of functions. |
| |
455 * |
| |
456 * @param ptr a pointer to the memory area containing the bytes to be written |
| |
457 * @param size the length of one element |
| |
458 * @param nitems the element count |
| |
459 * @param buffer the CxBuffer to write to |
| |
460 * @return the total count of elements written |
| |
461 * @see cxBufferWrite() |
| |
462 */ |
| |
463 cx_attr_nonnull |
| |
464 size_t cxBufferAppend( |
| |
465 const void *ptr, |
| 389 size_t size, |
466 size_t size, |
| 390 size_t nitems, |
467 size_t nitems, |
| 391 CxBuffer *buffer |
468 CxBuffer *buffer |
| 392 ); |
469 ); |
| 393 |
470 |
| 415 /** |
492 /** |
| 416 * Writes a character to a buffer. |
493 * Writes a character to a buffer. |
| 417 * |
494 * |
| 418 * The least significant byte of the argument is written to the buffer. If the |
495 * 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, |
496 * 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 |
497 * the buffer capacity is extended by cxBufferMinimumCapacity(). If the feature |
| 421 * disabled or buffer extension fails, \c EOF is returned. |
498 * is disabled or buffer extension fails, \c EOF is returned. |
| 422 * |
499 * |
| 423 * On successful write, the position of the buffer is increased. |
500 * On successful write, the position of the buffer is increased. |
| 424 * |
501 * |
| 425 * @param buffer the buffer to write to |
502 * @param buffer the buffer to write to |
| 426 * @param c the character to write |
503 * @param c the character to write |
| 427 * @return the byte that has bean written or \c EOF when the end of the stream is |
504 * @return the byte that has been written or \c EOF when the end of the stream is |
| 428 * reached and automatic extension is not enabled or not possible |
505 * reached and automatic extension is not enabled or not possible |
| 429 */ |
506 */ |
| 430 __attribute__((__nonnull__)) |
507 cx_attr_nonnull |
| 431 int cxBufferPut( |
508 int cxBufferPut( |
| 432 CxBuffer *buffer, |
509 CxBuffer *buffer, |
| 433 int c |
510 int c |
| 434 ); |
511 ); |
| |
512 |
| |
513 /** |
| |
514 * Writes a terminating zero to a buffer. |
| |
515 * |
| |
516 * On successful write, \em neither the position \em nor the size of the buffer is |
| |
517 * increased. |
| |
518 * |
| |
519 * The purpose of this function is to have the written data ready to be used as |
| |
520 * a C string. |
| |
521 * |
| |
522 * @param buffer the buffer to write to |
| |
523 * @return zero, if the terminator could be written, non-zero otherwise |
| |
524 */ |
| |
525 cx_attr_nonnull |
| |
526 int cxBufferTerminate(CxBuffer *buffer); |
| 435 |
527 |
| 436 /** |
528 /** |
| 437 * Writes a string to a buffer. |
529 * Writes a string to a buffer. |
| 438 * |
530 * |
| 439 * @param buffer the buffer |
531 * @param buffer the buffer |
| 440 * @param str the zero-terminated string |
532 * @param str the zero-terminated string |
| 441 * @return the number of bytes written |
533 * @return the number of bytes written |
| 442 */ |
534 */ |
| 443 __attribute__((__nonnull__)) |
535 cx_attr_nonnull |
| |
536 cx_attr_cstr_arg(2) |
| 444 size_t cxBufferPutString( |
537 size_t cxBufferPutString( |
| 445 CxBuffer *buffer, |
538 CxBuffer *buffer, |
| 446 const char *str |
539 const char *str |
| 447 ); |
540 ); |
| 448 |
541 |