| 4 |
4 |
| 5 This allows the use of `cx_stream_copy()` (see [](streams.h.md)) to copy contents from one buffer to another, |
5 This allows the use of `cx_stream_copy()` (see [](streams.h.md)) to copy contents from one buffer to another, |
| 6 or from a file or network stream to the buffer and vice versa. |
6 or from a file or network stream to the buffer and vice versa. |
| 7 |
7 |
| 8 More features for convenient use of the buffer can be enabled, like automatic memory management, |
8 More features for convenient use of the buffer can be enabled, like automatic memory management, |
| 9 automatic resizing of the buffer space, or automatic flushing of contents. |
9 or automatic resizing of the buffer space. |
| 10 |
10 |
| 11 The functions `cxBufferRead()` and `cxBufferWrite()` are `cx_read_func` and `cx_write_func` compatible, |
11 The functions `cxBufferRead()` and `cxBufferWrite()` are `cx_read_func` and `cx_write_func` compatible, |
| 12 which in turn have a compatible signature to `fread()` and `fwrite()`. |
12 which in turn have a compatible signature to `fread()` and `fwrite()`. |
| 13 However, due to the different pointer type the function pointers do not type check out of the box. |
13 However, due to the different pointer type the function pointers do not type check out of the box. |
| 14 For convenience, the macros `cxBufferReadFunc` and `cxBufferWriteFunc` are defined, which perform the necessary cast. |
14 For convenience, the macros `cxBufferReadFunc` and `cxBufferWriteFunc` are defined, which perform the necessary cast. |
| 120 ## Capacity Management |
120 ## Capacity Management |
| 121 |
121 |
| 122 ```C |
122 ```C |
| 123 #include <cx/buffer.h> |
123 #include <cx/buffer.h> |
| 124 |
124 |
| |
125 int cxBufferMaximumCapacity(CxBuffer *buffer, size_t capacity); |
| |
126 |
| |
127 int cxBufferMinimumCapacity(CxBuffer *buffer, size_t capacity); |
| |
128 |
| 125 int cxBufferReserve(CxBuffer *buffer, size_t capacity); |
129 int cxBufferReserve(CxBuffer *buffer, size_t capacity); |
| 126 |
130 |
| 127 int cxBufferMinimumCapacity(CxBuffer *buffer, size_t capacity); |
|
| 128 |
|
| 129 void cxBufferShrink(CxBuffer *buffer, size_t reserve); |
131 void cxBufferShrink(CxBuffer *buffer, size_t reserve); |
| 130 ``` |
132 ``` |
| |
133 |
| |
134 The function `cxBufferMaximumCapacity()` specifies an upper limit for auto-growing the buffer's capacity. |
| |
135 If the new threshold is smaller than the current capacity, this function fails and returns non-zero. |
| 131 |
136 |
| 132 The function `cxBufferMinimumCapacity()` guarantees a buffer capacity of _at least_ `capacity`. |
137 The function `cxBufferMinimumCapacity()` guarantees a buffer capacity of _at least_ `capacity`. |
| 133 It will grow the capacity in powers of two until the system's page size is reached. |
138 It will grow the capacity in powers of two until the system's page size is reached. |
| 134 Then, the new capacity will be a multiple of the page size. |
139 Then, the new capacity will be a multiple of the page size. |
| 135 The function returns non-zero if increasing the capacity was attempted unsuccessfully. |
140 The function returns non-zero if increasing the capacity was attempted unsuccessfully; |
| |
141 that includes attempts to specify a minimum capacity that exceeds the maximum capacity. |
| 136 |
142 |
| 137 The function `cxBufferReserve()`, on the other hand, will reallocate the buffer's space to match exactly the requested `capacity` |
143 The function `cxBufferReserve()`, on the other hand, will reallocate the buffer's space to match exactly the requested `capacity` |
| 138 and the contents are truncated if required. |
144 and the contents are truncated if required. |
| 139 |
145 |
| 140 You should use `cxBufferReserve()` when you know precisely the required capacity beforehand |
146 You should use `cxBufferReserve()` when you know precisely the required capacity beforehand |
| 145 If the current capacity is not larger than the size plus the reserve bytes, the function will do nothing. |
151 If the current capacity is not larger than the size plus the reserve bytes, the function will do nothing. |
| 146 |
152 |
| 147 > If the buffer is in a copy-on-write state, `cxBufferMinimumCapacity()` will perform the copy-on-write action |
153 > If the buffer is in a copy-on-write state, `cxBufferMinimumCapacity()` will perform the copy-on-write action |
| 148 > before reallocating the space. |
154 > before reallocating the space. |
| 149 > The function `cxBufferShrink()` on the other hand does _nothing_ when the buffer is in a copy-on-write state, |
155 > The function `cxBufferShrink()` on the other hand does _nothing_ when the buffer is in a copy-on-write state, |
| 150 > because it does not make much sense to copy the memory just to have it in a smaller memory region. |
156 > because it makes little sense to copy the memory just to have it in a smaller memory region. |
| 151 |
157 |
| 152 ## Write |
158 ## Write |
| 153 |
159 |
| 154 ```C |
160 ```C |
| 155 #include <cx/buffer.h> |
161 #include <cx/buffer.h> |
| 170 The primary function for writing to a buffer is `cxBufferWrite()` |
176 The primary function for writing to a buffer is `cxBufferWrite()` |
| 171 which writes up to `nitems` with `size` bytes each from the memory pointed to by `ptr` to the buffer. |
177 which writes up to `nitems` with `size` bytes each from the memory pointed to by `ptr` to the buffer. |
| 172 |
178 |
| 173 When the capacity of the buffer is not sufficient and the `CX_BUFFER_AUTO_EXTEND` is not set in the buffer, |
179 When the capacity of the buffer is not sufficient and the `CX_BUFFER_AUTO_EXTEND` is not set in the buffer, |
| 174 items that do not fit into the buffer are discarded. |
180 items that do not fit into the buffer are discarded. |
| 175 The function always returns the actual number of items successfully written. |
181 The function then returns the actual number of items successfully written. |
| 176 This equals the number of bytes if and only if `size=1`. |
182 This equals the number of bytes if and only if `size=1`. |
| |
183 If `CX_BUFFER_AUTO_EXTEND` is set, the buffer is grown to it's maximum capacity |
| |
184 (see `cxBufferMaximumCapacity()` in [](#capacity-management)). |
| |
185 In case the allocation for auto-extension fails, the function immediately returns zero and does not write any data. |
| 177 |
186 |
| 178 The function `cxBufferPut()` is a `putc()`-like wrapper for `cxBufferWrite()` which writes the character `c`, |
187 The function `cxBufferPut()` is a `putc()`-like wrapper for `cxBufferWrite()` which writes the character `c`, |
| 179 converted to an `unsigned char` to the buffer. |
188 converted to an `unsigned char` to the buffer. |
| 180 Just like `putc()` this function returns the written character on success, and `EOF` on failure, |
189 Just like `putc()` this function returns the written character on success, and `EOF` on failure, |
| 181 but it does _not_ set `errno` on failure. |
190 but it does _not_ set `errno` on failure. |
| 188 On the other hand, `cxBufferTerminate()` writes a zero-byte at the current position, |
197 On the other hand, `cxBufferTerminate()` writes a zero-byte at the current position, |
| 189 effectively creating a zero-terminated string whose size equals the buffer size. |
198 effectively creating a zero-terminated string whose size equals the buffer size. |
| 190 |
199 |
| 191 The function `cxBufferAppend()` writes the data to the end of the buffer (given by its size) regardless of the current position, |
200 The function `cxBufferAppend()` writes the data to the end of the buffer (given by its size) regardless of the current position, |
| 192 and it also does _not_ advance the position. |
201 and it also does _not_ advance the position. |
| 193 If the write operation triggered a [flush](#flushing), however, the position will be shifted left alongside the shifted buffer contents. |
|
| 194 In case the data at which the current position points gets flushed, the new position will be zero. |
|
| 195 |
202 |
| 196 ## Read |
203 ## Read |
| 197 |
204 |
| 198 ```C |
205 ```C |
| 199 #include <cx/buffer.h> |
206 #include <cx/buffer.h> |
| 289 (which means, `cxBufferEof()` returns `true` after the operation). |
296 (which means, `cxBufferEof()` returns `true` after the operation). |
| 290 |
297 |
| 291 The functions `cxBufferShiftRight()` and `cxBufferShiftLeft()` accept a larger (but in both cases positive) shift offset, |
298 The functions `cxBufferShiftRight()` and `cxBufferShiftLeft()` accept a larger (but in both cases positive) shift offset, |
| 292 which usually makes little sense on a 64-bit platform where `off_t` is already large enough to represent any reasonable offset. |
299 which usually makes little sense on a 64-bit platform where `off_t` is already large enough to represent any reasonable offset. |
| 293 You may, however, still use those functions to express more explicitly in your code in which direction you want the contents to be shifted. |
300 You may, however, still use those functions to express more explicitly in your code in which direction you want the contents to be shifted. |
| 294 |
|
| 295 ## Flushing |
|
| 296 |
|
| 297 ```C |
|
| 298 #include <cx/buffer.h> |
|
| 299 |
|
| 300 typedef struct cx_buffer_flush_config_s { |
|
| 301 size_t threshold; |
|
| 302 size_t blksize; |
|
| 303 size_t blkmax; |
|
| 304 void *target; |
|
| 305 cx_write_func wfunc; |
|
| 306 } CxBufferFlushConfig; |
|
| 307 |
|
| 308 int cxBufferEnableFlushing(CxBuffer *buffer, |
|
| 309 CxBufferFlushConfig config); |
|
| 310 |
|
| 311 size_t cxBufferFlush(CxBuffer *buffer); |
|
| 312 ``` |
|
| 313 |
|
| 314 With the function `cxBufferEnableFlushing()` you can configure a flushing strategy for the contents of the buffer. |
|
| 315 |
|
| 316 Flushing, once enabled, may happen in the following cases: |
|
| 317 1. when data is written to the buffer, the capacity is insufficient, and `CX_BUFFER_AUTO_EXTEND` is _not_ enabled |
|
| 318 2. when data is written to the buffer, and the required capacity exceeds the `threshold` configuration |
|
| 319 3. when `cxBufferFlush()` is called explicitly |
|
| 320 |
|
| 321 > By combining the `CX_BUFFER_AUTO_EXTEND` flag and the `threshold` setting, |
|
| 322 > you can create a buffer that initially starts with a small capacity, grows up to a certain threshold, |
|
| 323 > and starts flushing only when that threshold is exceeded. |
|
| 324 |
|
| 325 Flushing happens by invoking the `wfunc` up to `blkmax` times, writing up to `blksize` bytes from the buffer to the `target` with each call. |
|
| 326 The target might not accept all bytes (i.e., the `wfunc` return value indicates that fewer items have been written than requested), |
|
| 327 in which case the remaining data remains in the buffer. |
|
| 328 That means the buffer is effectively [shifted](#shift-contents) left by the number of successfully flushed bytes. |
|
| 329 |
|
| 330 > When you write large amounts of data to a buffer, multiple flush cycles might happen. |
|
| 331 > After the first flush operations are completed, the reclaimed space in the buffer is filled first, but if that |
|
| 332 > is not enough, another flush may be triggered within the same invocation of the write operation. |
|
| 333 > |
|
| 334 > That means as much data is written to the buffer and/or flushed as possible, until neither the flush target nor the buffer accept more data. |
|
| 335 > {style="note"} |
|
| 336 |
|
| 337 > The function `cxBufferFlush()` simply returns zero when flushing was not enabled via `cxBufferEnableFlushing()`. |
|
| 338 |
301 |
| 339 <seealso> |
302 <seealso> |
| 340 <category ref="apidoc"> |
303 <category ref="apidoc"> |
| 341 <a href="https://ucx.sourceforge.io/api/buffer_8h.html">buffer.h</a> |
304 <a href="https://ucx.sourceforge.io/api/buffer_8h.html">buffer.h</a> |
| 342 </category> |
305 </category> |