ucx/cx/buffer.h

changeset 115
e57ca2747782
parent 113
dde28a806552
equal deleted inserted replaced
114:3da24640513a 115:e57ca2747782
46 #ifndef UCX_BUFFER_H 46 #ifndef UCX_BUFFER_H
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 #include "string.h"
51 52
52 #ifdef __cplusplus 53 #ifdef __cplusplus
53 extern "C" { 54 extern "C" {
54 #endif 55 #endif
55 56
87 * buffers automatically admit the auto-extend flag when initialized with copy-on-extend enabled. 88 * buffers automatically admit the auto-extend flag when initialized with copy-on-extend enabled.
88 */ 89 */
89 #define CX_BUFFER_COPY_ON_EXTEND 0x08 90 #define CX_BUFFER_COPY_ON_EXTEND 0x08
90 91
91 /** 92 /**
93 * If this flag is enabled, the buffer will never free its contents regardless of #CX_BUFFER_FREE_CONTENTS.
94 *
95 * This is useful, for example, when you want to keep a pointer to the data after destroying the buffer.
96 */
97 #define CX_BUFFER_DO_NOT_FREE 0x10
98
99 /**
92 * Function pointer for cxBufferWrite that is compatible with cx_write_func. 100 * Function pointer for cxBufferWrite that is compatible with cx_write_func.
93 * @see cx_write_func 101 * @see cx_write_func
94 */ 102 */
95 #define cxBufferWriteFunc ((cx_write_func) cxBufferWrite) 103 #define cxBufferWriteFunc ((cx_write_func) cxBufferWrite)
96 /** 104 /**
97 * Function pointer for cxBufferRead that is compatible with cx_read_func. 105 * Function pointer for cxBufferRead that is compatible with cx_read_func.
98 * @see cx_read_func 106 * @see cx_read_func
99 */ 107 */
100 #define cxBufferReadFunc ((cx_read_func) cxBufferRead) 108 #define cxBufferReadFunc ((cx_read_func) cxBufferRead)
101 109
102 /**
103 * Configuration for automatic flushing.
104 */
105 struct cx_buffer_flush_config_s {
106 /**
107 * The buffer may not extend beyond this threshold before starting to flush.
108 *
109 * Only used when the buffer uses #CX_BUFFER_AUTO_EXTEND.
110 * The threshold will be the maximum capacity the buffer is extended to
111 * before flushing.
112 */
113 size_t threshold;
114 /**
115 * The block size for the elements to flush.
116 */
117 size_t blksize;
118 /**
119 * The maximum number of blocks to flush in one cycle.
120 *
121 * @attention while it is guaranteed that cxBufferFlush() will not flush
122 * more blocks, this is not necessarily the case for cxBufferWrite().
123 * After performing a flush cycle, cxBufferWrite() will retry the write
124 * operation and potentially trigger another flush cycle, until the
125 * flush target accepts no more data.
126 */
127 size_t blkmax;
128
129 /**
130 * The target for the write function.
131 */
132 void *target;
133
134 /**
135 * The write-function used for flushing.
136 * If NULL, the flushed content gets discarded.
137 */
138 cx_write_func wfunc;
139 };
140
141 /**
142 * Type alias for the flush configuration struct.
143 *
144 * @code
145 * struct cx_buffer_flush_config_s {
146 * size_t threshold;
147 * size_t blksize;
148 * size_t blkmax;
149 * void *target;
150 * cx_write_func wfunc;
151 * };
152 * @endcode
153 */
154 typedef struct cx_buffer_flush_config_s CxBufferFlushConfig;
155 110
156 /** Structure for the UCX buffer data. */ 111 /** Structure for the UCX buffer data. */
157 struct cx_buffer_s { 112 struct cx_buffer_s {
158 /** A pointer to the buffer contents. */ 113 /** A pointer to the buffer contents. */
159 union { 114 union {
166 */ 121 */
167 unsigned char *bytes; 122 unsigned char *bytes;
168 }; 123 };
169 /** The allocator to use for automatic memory management. */ 124 /** The allocator to use for automatic memory management. */
170 const CxAllocator *allocator; 125 const CxAllocator *allocator;
171 /**
172 * Optional flush configuration
173 *
174 * @see cxBufferEnableFlushing()
175 */
176 CxBufferFlushConfig *flush;
177 /** Current position of the buffer. */ 126 /** Current position of the buffer. */
178 size_t pos; 127 size_t pos;
179 /** Current capacity (i.e. maximum size) of the buffer. */ 128 /** Current capacity (i.e. maximum size) of the buffer. */
180 size_t capacity; 129 size_t capacity;
130 /** Maximum capacity that this buffer may grow to. */
131 size_t max_capacity;
181 /** Current size of the buffer content. */ 132 /** Current size of the buffer content. */
182 size_t size; 133 size_t size;
183 /** 134 /**
184 * Flag register for buffer features. 135 * Flag register for buffer features.
185 * @see #CX_BUFFER_DEFAULT 136 * @see #CX_BUFFER_DEFAULT
229 cx_attr_nonnull_arg(1) 180 cx_attr_nonnull_arg(1)
230 CX_EXPORT int cxBufferInit(CxBuffer *buffer, void *space, size_t capacity, 181 CX_EXPORT int cxBufferInit(CxBuffer *buffer, void *space, size_t capacity,
231 const CxAllocator *allocator, int flags); 182 const CxAllocator *allocator, int flags);
232 183
233 /** 184 /**
234 * Configures the buffer for flushing.
235 *
236 * Flushing can happen automatically when data is written
237 * to the buffer (see cxBufferWrite()) or manually when
238 * cxBufferFlush() is called.
239 *
240 * @param buffer the buffer
241 * @param config the flush configuration
242 * @retval zero success
243 * @retval non-zero failure
244 * @see cxBufferFlush()
245 * @see cxBufferWrite()
246 */
247 cx_attr_nonnull
248 CX_EXPORT int cxBufferEnableFlushing(CxBuffer *buffer, CxBufferFlushConfig config);
249
250 /**
251 * Destroys the buffer contents. 185 * Destroys the buffer contents.
252 * 186 *
253 * Has no effect if the #CX_BUFFER_FREE_CONTENTS feature is not enabled. 187 * Has no effect if the #CX_BUFFER_FREE_CONTENTS feature is not enabled.
254 * If you want to free the memory of the entire buffer, use cxBufferFree(). 188 * If you want to free the memory of the entire buffer, use cxBufferFree().
255 * 189 *
386 */ 320 */
387 cx_attr_nonnull 321 cx_attr_nonnull
388 CX_EXPORT int cxBufferSeek(CxBuffer *buffer, off_t offset, int whence); 322 CX_EXPORT int cxBufferSeek(CxBuffer *buffer, off_t offset, int whence);
389 323
390 /** 324 /**
325 * Discards items from the end of the buffer.
326 *
327 * When the current position points to a byte that gets discarded,
328 * the position is set to the buffer size.
329 *
330 * @param buffer the buffer
331 * @param size the size of one item
332 * @param nitems the number of items to discard
333 * @return the actual number of discarded items
334 */
335 cx_attr_nonnull
336 CX_EXPORT size_t cxBufferPop(CxBuffer *buffer, size_t size, size_t nitems);
337
338 /**
391 * Clears the buffer by resetting the position and deleting the data. 339 * Clears the buffer by resetting the position and deleting the data.
392 * 340 *
393 * The data is deleted by zeroing it with a call to memset(). 341 * The data is deleted by zeroing it with a call to memset().
394 * If you do not need that, you can use the faster cxBufferReset(). 342 * If you do not need that, you can use the faster cxBufferReset().
395 * 343 *
423 * @retval false otherwise 371 * @retval false otherwise
424 */ 372 */
425 cx_attr_nonnull cx_attr_nodiscard 373 cx_attr_nonnull cx_attr_nodiscard
426 CX_EXPORT bool cxBufferEof(const CxBuffer *buffer); 374 CX_EXPORT bool cxBufferEof(const CxBuffer *buffer);
427 375
376 /**
377 * Ensures that the buffer has the required capacity.
378 *
379 * If the current capacity is not sufficient, the buffer will be extended.
380 * If the current capacity is larger, the buffer is shrunk and superfluous
381 * content is discarded.
382 *
383 * This function will reserve no more bytes than requested, in contrast to
384 * cxBufferMinimumCapacity(), which may reserve more bytes to improve the
385 * number of future necessary reallocations.
386 *
387 * @param buffer the buffer
388 * @param capacity the required capacity for this buffer
389 * @retval zero on success
390 * @retval non-zero on allocation failure
391 * @see cxBufferShrink()
392 * @see cxBufferMinimumCapacity()
393 */
394 cx_attr_nonnull
395 CX_EXPORT int cxBufferReserve(CxBuffer *buffer, size_t capacity);
396
397 /**
398 * Limits the buffer's capacity.
399 *
400 * If the current capacity is already larger, this function fails and returns
401 * non-zero.
402 *
403 * The capacity limit will affect auto-extension features, as well as future
404 * calls to cxBufferMinimumCapacity() and cxBufferReserve().
405 *
406 * @param buffer the buffer
407 * @param capacity the maximum allowed capacity for this buffer
408 * @retval zero the limit is applied
409 * @retval non-zero the new limit is smaller than the current capacity
410 * @see cxBufferReserve()
411 * @see cxBufferMinimumCapacity()
412 */
413 cx_attr_nonnull
414 CX_EXPORT int cxBufferMaximumCapacity(CxBuffer *buffer, size_t capacity);
428 415
429 /** 416 /**
430 * Ensures that the buffer has a minimum capacity. 417 * Ensures that the buffer has a minimum capacity.
431 * 418 *
432 * If the current capacity is not sufficient, the buffer will be extended. 419 * If the current capacity is not sufficient, the buffer will be generously
420 * extended.
433 * 421 *
434 * The new capacity will be a power of two until the system's page size is reached. 422 * The new capacity will be a power of two until the system's page size is reached.
435 * Then, the new capacity will be a multiple of the page size. 423 * Then, the new capacity will be a multiple of the page size.
436 * 424 *
437 * @param buffer the buffer 425 * @param buffer the buffer
438 * @param capacity the minimum required capacity for this buffer 426 * @param capacity the minimum required capacity for this buffer
439 * @retval zero the capacity was already sufficient or successfully increased 427 * @retval zero the capacity was already sufficient or successfully increased
440 * @retval non-zero on allocation failure 428 * @retval non-zero on allocation failure
429 * @see cxBufferMaximumCapacity()
430 * @see cxBufferReserve()
441 * @see cxBufferShrink() 431 * @see cxBufferShrink()
442 */ 432 */
443 cx_attr_nonnull 433 cx_attr_nonnull
444 CX_EXPORT int cxBufferMinimumCapacity(CxBuffer *buffer, size_t capacity); 434 CX_EXPORT int cxBufferMinimumCapacity(CxBuffer *buffer, size_t capacity);
445 435
455 * If the #CX_BUFFER_COPY_ON_WRITE or #CX_BUFFER_COPY_ON_EXTEND flag is set, 445 * If the #CX_BUFFER_COPY_ON_WRITE or #CX_BUFFER_COPY_ON_EXTEND flag is set,
456 * this function does nothing. 446 * this function does nothing.
457 * 447 *
458 * @param buffer the buffer 448 * @param buffer the buffer
459 * @param reserve the number of bytes that shall remain reserved 449 * @param reserve the number of bytes that shall remain reserved
450 * @see cxBufferReserve()
460 * @see cxBufferMinimumCapacity() 451 * @see cxBufferMinimumCapacity()
461 */ 452 */
462 cx_attr_nonnull 453 cx_attr_nonnull
463 CX_EXPORT void cxBufferShrink(CxBuffer *buffer, size_t reserve); 454 CX_EXPORT void cxBufferShrink(CxBuffer *buffer, size_t reserve);
464 455
465 /** 456 /**
466 * Writes data to a CxBuffer. 457 * Writes data to a CxBuffer.
467 * 458 *
468 * If automatic flushing is not enabled, the data is simply written into the 459 * If auto-extension is enabled, the buffer's capacity is automatically
469 * buffer at the current position, and the position of the buffer is increased 460 * increased when it is not large enough to hold all data.
470 * by the number of bytes written. 461 * By default, the capacity grows indefinitely, unless limited with
471 * 462 * cxBufferMaximumCapacity().
472 * If flushing is enabled and the buffer needs to flush, the data is flushed to 463 * When auto-extension fails, this function writes no data and returns zero.
473 * the target until the target signals that it cannot take more data by 464 *
474 * returning zero via the respective write function. In that case, the remaining 465 * The position of the buffer is moved alongside the written data.
475 * data in this buffer is shifted to the beginning of this buffer so that the
476 * newly available space can be used to append as much data as possible.
477 *
478 * This function only stops writing more elements when the flush target and this
479 * buffer are both incapable of taking more data or all data has been written.
480 *
481 * If, after flushing, the number of items that shall be written still exceeds
482 * the capacity or flush threshold, this function tries to write all items directly
483 * to the flush target, if possible.
484 *
485 * The number returned by this function is the number of elements from
486 * @c ptr that could be written to either the flush target or the buffer.
487 * That means it does @em not include the number of items that were already in
488 * the buffer and were also flushed during the process.
489 *
490 * @attention
491 * When @p size is larger than one and the contents of the buffer are not aligned
492 * with @p size, flushing stops after all complete items have been flushed, leaving
493 * the misaligned part in the buffer.
494 * Afterward, this function only writes as many items as possible to the buffer.
495 * 466 *
496 * @note The signature is compatible with the fwrite() family of functions. 467 * @note The signature is compatible with the fwrite() family of functions.
497 * 468 *
498 * @param ptr a pointer to the memory area containing the bytes to be written 469 * @param ptr a pointer to the memory area containing the bytes to be written
499 * @param size the length of one element 470 * @param size the length of one element
529 cx_attr_nonnull 500 cx_attr_nonnull
530 CX_EXPORT size_t cxBufferAppend(const void *ptr, size_t size, 501 CX_EXPORT size_t cxBufferAppend(const void *ptr, size_t size,
531 size_t nitems, CxBuffer *buffer); 502 size_t nitems, CxBuffer *buffer);
532 503
533 /** 504 /**
534 * Performs a single flush-run on the specified buffer.
535 *
536 * Does nothing when the position in the buffer is zero.
537 * Otherwise, the data until the current position minus
538 * one is considered for flushing.
539 * Note carefully that flushing will never exceed the
540 * current @em position, even when the size of the
541 * buffer is larger than the current position.
542 *
543 * One flush run will try to flush @c blkmax many
544 * blocks of size @c blksize until either the @p buffer
545 * has no more data to flush or the write function
546 * used for flushing returns zero.
547 *
548 * The buffer is shifted left for that many bytes
549 * the flush operation has successfully flushed.
550 *
551 * @par Example 1
552 * Assume you have a buffer with size 340 and you are
553 * at position 200. The flush configuration is
554 * @c blkmax=4 and @c blksize=64 .
555 * Assume that the entire flush operation is successful.
556 * All 200 bytes on the left-hand-side from the current
557 * position are written.
558 * That means the size of the buffer is now 140 and the
559 * position is zero.
560 *
561 * @par Example 2
562 * Same as Example 1, but now the @c blkmax is 1.
563 * The size of the buffer is now 276, and the position is 136.
564 *
565 * @par Example 3
566 * Same as Example 1, but now assume the flush target
567 * only accepts 100 bytes before returning zero.
568 * That means the flush operation manages to flush
569 * one complete block and one partial block, ending
570 * up with a buffer with size 240 and position 100.
571 *
572 * @remark Just returns zero when flushing was not enabled with
573 * cxBufferEnableFlushing().
574 *
575 * @remark When the buffer uses copy-on-write, the memory
576 * is copied first, before attempting any flush.
577 * This is, however, considered an erroneous use of the
578 * buffer because it makes little sense to put
579 * readonly data into an UCX buffer for flushing instead
580 * of writing it directly to the target.
581 *
582 * @param buffer the buffer
583 * @return the number of successfully flushed bytes
584 * @see cxBufferEnableFlushing()
585 */
586 cx_attr_nonnull
587 CX_EXPORT size_t cxBufferFlush(CxBuffer *buffer);
588
589 /**
590 * Reads data from a CxBuffer. 505 * Reads data from a CxBuffer.
591 * 506 *
592 * The position of the buffer is increased by the number of bytes read. 507 * The position of the buffer is increased by the number of bytes read.
593 * 508 *
594 * @note The signature is compatible with the fread() family of functions. 509 * @note The signature is compatible with the fread() family of functions.
608 /** 523 /**
609 * Writes a character to a buffer. 524 * Writes a character to a buffer.
610 * 525 *
611 * The least significant byte of the argument is written to the buffer. If the 526 * The least significant byte of the argument is written to the buffer. If the
612 * end of the buffer is reached and #CX_BUFFER_AUTO_EXTEND feature is enabled, 527 * end of the buffer is reached and #CX_BUFFER_AUTO_EXTEND feature is enabled,
613 * the buffer capacity is extended by cxBufferMinimumCapacity(). If the feature 528 * the buffer capacity is extended, unless a limit set by
614 * is disabled or the buffer extension fails, @c EOF is returned. 529 * cxBufferMaximumCapacity() is reached.
530 * If the feature is disabled or the buffer extension fails, @c EOF is returned.
615 * 531 *
616 * On successful writing, the position of the buffer is increased. 532 * On successful writing, the position of the buffer is increased.
617 * 533 *
618 * If you just want to write a null-terminator at the current position, you 534 * If you just want to write a null-terminator at the current position, you
619 * should use cxBufferTerminate() instead. 535 * should use cxBufferTerminate() instead.
620 * 536 *
621 * @param buffer the buffer to write to 537 * @param buffer the buffer to write to
622 * @param c the character to write 538 * @param c the character to write
623 * @return the byte that has been written or @c EOF when the end of the stream is 539 * @return the byte that has been written or @c EOF when the end of the
624 * reached, and automatic extension is not enabled or not possible 540 * stream is reached, and automatic extension is not enabled or not possible
625 * @see cxBufferTerminate() 541 * @see cxBufferTerminate()
626 */ 542 */
627 cx_attr_nonnull 543 cx_attr_nonnull
628 CX_EXPORT int cxBufferPut(CxBuffer *buffer, int c); 544 CX_EXPORT int cxBufferPut(CxBuffer *buffer, int c);
629 545
630 /** 546 /**
631 * Writes a terminating zero to a buffer at the current position. 547 * Writes a terminating zero to a buffer at the current position.
632 * 548 *
633 * If successful, sets the size to the current position and advances the position by one. 549 * If successful, also sets the size to the current position and shrinks the buffer.
634 * 550 *
635 * The purpose of this function is to have the written data ready to be used as 551 * The purpose of this function is to have the written data ready to be used as
636 * a C string with the buffer's size being the length of that string. 552 * a C string with the buffer's size being the length of that string.
637 * 553 *
638 * @param buffer the buffer to write to 554 * @param buffer the buffer to write to
639 * @return zero, if the terminator could be written, non-zero otherwise 555 * @return zero, if the terminator could be written, non-zero otherwise
556 * @see cxBufferShrink()
640 */ 557 */
641 cx_attr_nonnull 558 cx_attr_nonnull
642 CX_EXPORT int cxBufferTerminate(CxBuffer *buffer); 559 CX_EXPORT int cxBufferTerminate(CxBuffer *buffer);
643 560
644 /** 561 /**
645 * Writes a string to a buffer. 562 * Internal function - do not use.
646 * 563 *
647 * This is a convenience function for <code>cxBufferWrite(str, 1, strlen(str), buffer)</code>. 564 * @param buffer the buffer
648 * 565 * @param str the string
649 * @param buffer the buffer
650 * @param str the zero-terminated string
651 * @return the number of bytes written 566 * @return the number of bytes written
652 */ 567 * @see cxBufferPutString()
653 cx_attr_nonnull cx_attr_cstr_arg(2) 568 */
654 CX_EXPORT size_t cxBufferPutString(CxBuffer *buffer, const char *str); 569 cx_attr_nonnull
570 CX_EXPORT size_t cx_buffer_put_string(CxBuffer *buffer, cxstring str);
571
572 /**
573 * Writes a string to a buffer with cxBufferWrite().
574 *
575 * @param buffer (@c CxBuffer*) the buffer
576 * @param str (any string) the zero-terminated string
577 * @return (@c size_t) the number of bytes written
578 * @see cxBufferWrite()
579 * @see cx_strcast()
580 */
581 #define cxBufferPutString(buffer, str) cx_buffer_put_string(buffer, cx_strcast(str))
582
583 /**
584 * Internal function - do not use.
585 *
586 * @param buffer the buffer
587 * @param str the string
588 * @return the number of bytes written
589 * @see cxBufferPutString()
590 */
591 cx_attr_nonnull
592 CX_EXPORT size_t cx_buffer_append_string(CxBuffer *buffer, cxstring str);
593
594 /**
595 * Appends a string to a buffer with cxBufferAppend().
596 *
597 * @param buffer (@c CxBuffer*) the buffer
598 * @param str (any string) the zero-terminated string
599 * @return (@c size_t) the number of bytes written
600 * @see cxBufferAppend()
601 * @see cx_strcast()
602 */
603 #define cxBufferAppendString(buffer, str) cx_buffer_append_string(buffer, cx_strcast(str))
655 604
656 /** 605 /**
657 * Gets a character from a buffer. 606 * Gets a character from a buffer.
658 * 607 *
659 * The current position of the buffer is increased after a successful read. 608 * The current position of the buffer is increased after a successful read.

mercurial