25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
26 * POSSIBILITY OF SUCH DAMAGE. |
26 * POSSIBILITY OF SUCH DAMAGE. |
27 */ |
27 */ |
28 |
28 |
29 /** |
29 /** |
30 * \file buffer.h |
30 * @file buffer.h |
31 * |
31 * |
32 * \brief Advanced buffer implementation. |
32 * @brief Advanced buffer implementation. |
33 * |
33 * |
34 * Instances of CxBuffer can be used to read from or to write to like one |
34 * Instances of CxBuffer can be used to read from or to write to like one |
35 * would do with a stream. |
35 * would do with a stream. |
36 * |
36 * |
37 * Some features for convenient use of the buffer |
37 * Some features for convenient use of the buffer |
38 * can be enabled. See the documentation of the macro constants for more |
38 * can be enabled. See the documentation of the macro constants for more |
39 * information. |
39 * information. |
40 * |
40 * |
41 * \author Mike Becker |
41 * @author Mike Becker |
42 * \author Olaf Wintermann |
42 * @author Olaf Wintermann |
43 * \copyright 2-Clause BSD License |
43 * @copyright 2-Clause BSD License |
44 */ |
44 */ |
45 |
45 |
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 |
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 |
70 |
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 |
|
90 |
|
91 /** |
|
92 * Configuration for automatic flushing. |
|
93 */ |
|
94 struct cx_buffer_flush_config_s { |
|
95 /** |
|
96 * The buffer may not extend beyond this threshold before starting to flush. |
|
97 * |
|
98 * Only used when the buffer uses #CX_BUFFER_AUTO_EXTEND. |
|
99 * The threshold will be the maximum capacity the buffer is extended to |
|
100 * before flushing. |
|
101 */ |
|
102 size_t threshold; |
|
103 /** |
|
104 * The block size for the elements to flush. |
|
105 */ |
|
106 size_t blksize; |
|
107 /** |
|
108 * The maximum number of blocks to flush in one cycle. |
|
109 * |
|
110 * @attention while it is guaranteed that cxBufferFlush() will not flush |
|
111 * more blocks, this is not necessarily the case for cxBufferWrite(). |
|
112 * After performing a flush cycle, cxBufferWrite() will retry the write |
|
113 * operation and potentially trigger another flush cycle, until the |
|
114 * flush target accepts no more data. |
|
115 */ |
|
116 size_t blkmax; |
|
117 |
|
118 /** |
|
119 * The target for write function. |
|
120 */ |
|
121 void *target; |
|
122 |
|
123 /** |
|
124 * The write-function used for flushing. |
|
125 * If NULL, the flushed content gets discarded. |
|
126 */ |
|
127 cx_write_func wfunc; |
|
128 }; |
|
129 |
|
130 /** |
|
131 * Type alais for the flush configuration struct. |
|
132 * |
|
133 * @code |
|
134 * struct cx_buffer_flush_config_s { |
|
135 * size_t threshold; |
|
136 * size_t blksize; |
|
137 * size_t blkmax; |
|
138 * void *target; |
|
139 * cx_write_func wfunc; |
|
140 * }; |
|
141 * @endcode |
|
142 */ |
|
143 typedef struct cx_buffer_flush_config_s CxBufferFlushConfig; |
|
144 |
71 /** Structure for the UCX buffer data. */ |
145 /** Structure for the UCX buffer data. */ |
72 typedef struct { |
146 struct cx_buffer_s { |
73 /** A pointer to the buffer contents. */ |
147 /** A pointer to the buffer contents. */ |
74 union { |
148 union { |
75 /** |
149 /** |
76 * Data is interpreted as text. |
150 * Data is interpreted as text. |
77 */ |
151 */ |
81 */ |
155 */ |
82 unsigned char *bytes; |
156 unsigned char *bytes; |
83 }; |
157 }; |
84 /** The allocator to use for automatic memory management. */ |
158 /** The allocator to use for automatic memory management. */ |
85 const CxAllocator *allocator; |
159 const CxAllocator *allocator; |
|
160 /** |
|
161 * Optional flush configuration |
|
162 * |
|
163 * @see cxBufferEnableFlushing() |
|
164 */ |
|
165 CxBufferFlushConfig* flush; |
86 /** Current position of the buffer. */ |
166 /** Current position of the buffer. */ |
87 size_t pos; |
167 size_t pos; |
88 /** Current capacity (i.e. maximum size) of the buffer. */ |
168 /** Current capacity (i.e. maximum size) of the buffer. */ |
89 size_t capacity; |
169 size_t capacity; |
90 /** Current size of the buffer content. */ |
170 /** Current size of the buffer content. */ |
91 size_t size; |
171 size_t size; |
92 /** |
172 /** |
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. |
173 * Flag register for buffer features. |
128 * @see #CX_BUFFER_DEFAULT |
174 * @see #CX_BUFFER_DEFAULT |
129 * @see #CX_BUFFER_FREE_CONTENTS |
175 * @see #CX_BUFFER_FREE_CONTENTS |
130 * @see #CX_BUFFER_AUTO_EXTEND |
176 * @see #CX_BUFFER_AUTO_EXTEND |
|
177 * @see #CX_BUFFER_COPY_ON_WRITE |
131 */ |
178 */ |
132 int flags; |
179 int flags; |
133 } cx_buffer_s; |
180 }; |
134 |
181 |
135 /** |
182 /** |
136 * UCX buffer. |
183 * UCX buffer. |
137 */ |
184 */ |
138 typedef cx_buffer_s CxBuffer; |
185 typedef struct cx_buffer_s CxBuffer; |
139 |
186 |
140 /** |
187 /** |
141 * Initializes a fresh buffer. |
188 * Initializes a fresh buffer. |
142 * |
189 * |
143 * \note You may provide \c NULL as argument for \p space. |
190 * You may also provide a read-only @p space, in which case |
|
191 * you will need to cast the pointer, and you should set the |
|
192 * #CX_BUFFER_COPY_ON_WRITE flag. |
|
193 * |
|
194 * You need to set the size manually after initialization, if |
|
195 * you provide @p space which already contains data. |
|
196 * |
|
197 * When you specify stack memory as @p space and decide to use |
|
198 * the auto-extension feature, you @em must use the |
|
199 * #CX_BUFFER_COPY_ON_EXTEND flag, instead of the |
|
200 * #CX_BUFFER_AUTO_EXTEND flag. |
|
201 * |
|
202 * @note You may provide @c NULL as argument for @p space. |
144 * Then this function will allocate the space and enforce |
203 * Then this function will allocate the space and enforce |
145 * the #CX_BUFFER_FREE_CONTENTS flag. |
204 * the #CX_BUFFER_FREE_CONTENTS flag. In that case, specifying |
|
205 * copy-on-write should be avoided, because the allocated |
|
206 * space will be leaking after the copy-on-write operation. |
146 * |
207 * |
147 * @param buffer the buffer to initialize |
208 * @param buffer the buffer to initialize |
148 * @param space pointer to the memory area, or \c NULL to allocate |
209 * @param space pointer to the memory area, or @c NULL to allocate |
149 * new memory |
210 * new memory |
150 * @param capacity the capacity of the buffer |
211 * @param capacity the capacity of the buffer |
151 * @param allocator the allocator this buffer shall use for automatic |
212 * @param allocator the allocator this buffer shall use for automatic |
152 * memory management. If \c NULL, the default heap allocator will be used. |
213 * memory management |
|
214 * (if @c NULL, a default stdlib allocator will be used) |
153 * @param flags buffer features (see cx_buffer_s.flags) |
215 * @param flags buffer features (see cx_buffer_s.flags) |
154 * @return zero on success, non-zero if a required allocation failed |
216 * @return zero on success, non-zero if a required allocation failed |
155 */ |
217 */ |
156 __attribute__((__nonnull__(1))) |
218 cx_attr_nonnull_arg(1) |
157 int cxBufferInit( |
219 int cxBufferInit( |
158 CxBuffer *buffer, |
220 CxBuffer *buffer, |
159 void *space, |
221 void *space, |
160 size_t capacity, |
222 size_t capacity, |
161 const CxAllocator *allocator, |
223 const CxAllocator *allocator, |
162 int flags |
224 int flags |
163 ); |
225 ); |
164 |
226 |
165 /** |
227 /** |
|
228 * Configures the buffer for flushing. |
|
229 * |
|
230 * Flushing can happen automatically when data is written |
|
231 * to the buffer (see cxBufferWrite()) or manually when |
|
232 * cxBufferFlush() is called. |
|
233 * |
|
234 * @param buffer the buffer |
|
235 * @param config the flush configuration |
|
236 * @retval zero success |
|
237 * @retval non-zero failure |
|
238 * @see cxBufferFlush() |
|
239 * @see cxBufferWrite() |
|
240 */ |
|
241 cx_attr_nonnull |
|
242 int cxBufferEnableFlushing( |
|
243 CxBuffer *buffer, |
|
244 CxBufferFlushConfig config |
|
245 ); |
|
246 |
|
247 /** |
|
248 * Destroys the buffer contents. |
|
249 * |
|
250 * Has no effect if the #CX_BUFFER_FREE_CONTENTS feature is not enabled. |
|
251 * If you want to free the memory of the entire buffer, use cxBufferFree(). |
|
252 * |
|
253 * @param buffer the buffer which contents shall be destroyed |
|
254 * @see cxBufferInit() |
|
255 */ |
|
256 cx_attr_nonnull |
|
257 void cxBufferDestroy(CxBuffer *buffer); |
|
258 |
|
259 /** |
|
260 * Deallocates the buffer. |
|
261 * |
|
262 * If the #CX_BUFFER_FREE_CONTENTS feature is enabled, this function also destroys |
|
263 * the contents. If you @em only want to destroy the contents, use cxBufferDestroy(). |
|
264 * |
|
265 * @remark As with all free() functions, this accepts @c NULL arguments in which |
|
266 * case it does nothing. |
|
267 * |
|
268 * @param buffer the buffer to deallocate |
|
269 * @see cxBufferCreate() |
|
270 */ |
|
271 void cxBufferFree(CxBuffer *buffer); |
|
272 |
|
273 /** |
166 * Allocates and initializes a fresh buffer. |
274 * Allocates and initializes a fresh buffer. |
167 * |
275 * |
168 * \note You may provide \c NULL as argument for \p space. |
276 * You may also provide a read-only @p space, in which case |
|
277 * you will need to cast the pointer, and you should set the |
|
278 * #CX_BUFFER_COPY_ON_WRITE flag. |
|
279 * When you specify stack memory as @p space and decide to use |
|
280 * the auto-extension feature, you @em must use the |
|
281 * #CX_BUFFER_COPY_ON_EXTEND flag, instead of the |
|
282 * #CX_BUFFER_AUTO_EXTEND flag. |
|
283 * |
|
284 * @note You may provide @c NULL as argument for @p space. |
169 * Then this function will allocate the space and enforce |
285 * Then this function will allocate the space and enforce |
170 * the #CX_BUFFER_FREE_CONTENTS flag. |
286 * the #CX_BUFFER_FREE_CONTENTS flag. |
171 * |
287 * |
172 * @param space pointer to the memory area, or \c NULL to allocate |
288 * @param space pointer to the memory area, or @c NULL to allocate |
173 * new memory |
289 * new memory |
174 * @param capacity the capacity of the buffer |
290 * @param capacity the capacity of the buffer |
175 * @param allocator the allocator to use for allocating the structure and the automatic |
291 * @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. |
292 * memory management within the buffer |
|
293 * (if @c NULL, a default stdlib allocator will be used) |
177 * @param flags buffer features (see cx_buffer_s.flags) |
294 * @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 |
295 * @return a pointer to the buffer on success, @c NULL if a required allocation failed |
179 */ |
296 */ |
|
297 cx_attr_malloc |
|
298 cx_attr_dealloc(cxBufferFree, 1) |
|
299 cx_attr_nodiscard |
180 CxBuffer *cxBufferCreate( |
300 CxBuffer *cxBufferCreate( |
181 void *space, |
301 void *space, |
182 size_t capacity, |
302 size_t capacity, |
183 const CxAllocator *allocator, |
303 const CxAllocator *allocator, |
184 int flags |
304 int flags |
185 ); |
305 ); |
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 |
306 |
211 /** |
307 /** |
212 * Shifts the contents of the buffer by the given offset. |
308 * Shifts the contents of the buffer by the given offset. |
213 * |
309 * |
214 * If the offset is positive, the contents are shifted to the right. |
310 * If the offset is positive, the contents are shifted to the right. |
217 * no contents are changed. |
313 * no contents are changed. |
218 * If auto extension is disabled, the contents that do not fit into the buffer |
314 * If auto extension is disabled, the contents that do not fit into the buffer |
219 * are discarded. |
315 * are discarded. |
220 * |
316 * |
221 * If the offset is negative, the contents are shifted to the left where the |
317 * If the offset is negative, the contents are shifted to the left where the |
222 * first \p shift bytes are discarded. |
318 * first @p shift bytes are discarded. |
223 * The new size of the buffer is the old size minus the absolute shift value. |
319 * 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 |
320 * If this value is larger than the buffer size, the buffer is emptied (but |
225 * not cleared, see the security note below). |
321 * not cleared, see the security note below). |
226 * |
322 * |
227 * The buffer position gets shifted alongside with the content but is kept |
323 * The buffer position gets shifted alongside with the content but is kept |
228 * within the boundaries of the buffer. |
324 * within the boundaries of the buffer. |
229 * |
325 * |
230 * \note For situations where \c off_t is not large enough, there are specialized cxBufferShiftLeft() and |
326 * @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. |
327 * cxBufferShiftRight() functions using a @c size_t as parameter type. |
232 * |
328 * |
233 * \attention |
329 * @attention |
234 * Security Note: The shifting operation does \em not erase the previously occupied memory cells. |
330 * 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 |
331 * But you can easily do that manually, e.g. by calling |
236 * <code>memset(buffer->bytes, 0, shift)</code> for a right shift or |
332 * <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> |
333 * <code>memset(buffer->bytes + buffer->size, 0, buffer->capacity - buffer->size)</code> |
238 * for a left shift. |
334 * for a left shift. |
239 * |
335 * |
240 * @param buffer the buffer |
336 * @param buffer the buffer |
241 * @param shift the shift offset (negative means left shift) |
337 * @param shift the shift offset (negative means left shift) |
242 * @return 0 on success, non-zero if a required auto-extension fails |
338 * @retval zero success |
243 */ |
339 * @retval non-zero if a required auto-extension or copy-on-write fails |
244 __attribute__((__nonnull__)) |
340 * @see cxBufferShiftLeft() |
|
341 * @see cxBufferShiftRight() |
|
342 */ |
|
343 cx_attr_nonnull |
245 int cxBufferShift( |
344 int cxBufferShift( |
246 CxBuffer *buffer, |
345 CxBuffer *buffer, |
247 off_t shift |
346 off_t shift |
248 ); |
347 ); |
249 |
348 |
251 * Shifts the buffer to the right. |
350 * Shifts the buffer to the right. |
252 * See cxBufferShift() for details. |
351 * See cxBufferShift() for details. |
253 * |
352 * |
254 * @param buffer the buffer |
353 * @param buffer the buffer |
255 * @param shift the shift offset |
354 * @param shift the shift offset |
256 * @return 0 on success, non-zero if a required auto-extension fails |
355 * @retval zero success |
|
356 * @retval non-zero if a required auto-extension or copy-on-write fails |
257 * @see cxBufferShift() |
357 * @see cxBufferShift() |
258 */ |
358 */ |
259 __attribute__((__nonnull__)) |
359 cx_attr_nonnull |
260 int cxBufferShiftRight( |
360 int cxBufferShiftRight( |
261 CxBuffer *buffer, |
361 CxBuffer *buffer, |
262 size_t shift |
362 size_t shift |
263 ); |
363 ); |
264 |
364 |
265 /** |
365 /** |
266 * Shifts the buffer to the left. |
366 * Shifts the buffer to the left. |
267 * See cxBufferShift() for details. |
367 * See cxBufferShift() for details. |
268 * |
368 * |
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 |
369 * @param buffer the buffer |
273 * @param shift the positive shift offset |
370 * @param shift the positive shift offset |
274 * @return always zero |
371 * @retval zero success |
|
372 * @retval non-zero if the buffer uses copy-on-write and the allocation fails |
275 * @see cxBufferShift() |
373 * @see cxBufferShift() |
276 */ |
374 */ |
277 __attribute__((__nonnull__)) |
375 cx_attr_nonnull |
278 int cxBufferShiftLeft( |
376 int cxBufferShiftLeft( |
279 CxBuffer *buffer, |
377 CxBuffer *buffer, |
280 size_t shift |
378 size_t shift |
281 ); |
379 ); |
282 |
380 |
283 |
381 |
284 /** |
382 /** |
285 * Moves the position of the buffer. |
383 * Moves the position of the buffer. |
286 * |
384 * |
287 * The new position is relative to the \p whence argument. |
385 * The new position is relative to the @p whence argument. |
288 * |
386 * |
289 * \li \c SEEK_SET marks the start of the buffer. |
387 * @li @c SEEK_SET marks the start of the buffer. |
290 * \li \c SEEK_CUR marks the current position. |
388 * @li @c SEEK_CUR marks the current position. |
291 * \li \c SEEK_END marks the end of the buffer. |
389 * @li @c SEEK_END marks the end of the buffer. |
292 * |
390 * |
293 * With an offset of zero, this function sets the buffer position to zero |
391 * 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 |
392 * (@c SEEK_SET), the buffer size (@c SEEK_END) or leaves the buffer position |
295 * unchanged (\c SEEK_CUR). |
393 * unchanged (@c SEEK_CUR). |
296 * |
394 * |
297 * @param buffer the buffer |
395 * @param buffer the buffer |
298 * @param offset position offset relative to \p whence |
396 * @param offset position offset relative to @p whence |
299 * @param whence one of \c SEEK_SET, \c SEEK_CUR or \c SEEK_END |
397 * @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 |
398 * @retval zero success |
301 * |
399 * @retval non-zero if the position is invalid |
302 */ |
400 * |
303 __attribute__((__nonnull__)) |
401 */ |
|
402 cx_attr_nonnull |
304 int cxBufferSeek( |
403 int cxBufferSeek( |
305 CxBuffer *buffer, |
404 CxBuffer *buffer, |
306 off_t offset, |
405 off_t offset, |
307 int whence |
406 int whence |
308 ); |
407 ); |
326 * reset of the buffer, use cxBufferClear(). |
428 * reset of the buffer, use cxBufferClear(). |
327 * |
429 * |
328 * @param buffer the buffer to be cleared |
430 * @param buffer the buffer to be cleared |
329 * @see cxBufferClear() |
431 * @see cxBufferClear() |
330 */ |
432 */ |
331 __attribute__((__nonnull__)) |
433 cx_attr_nonnull |
332 void cxBufferReset(CxBuffer *buffer); |
434 void cxBufferReset(CxBuffer *buffer); |
333 |
435 |
334 /** |
436 /** |
335 * Tests, if the buffer position has exceeded the buffer size. |
437 * Tests, if the buffer position has exceeded the buffer size. |
336 * |
438 * |
337 * @param buffer the buffer to test |
439 * @param buffer the buffer to test |
338 * @return non-zero, if the current buffer position has exceeded the last |
440 * @retval true if the current buffer position has exceeded the last |
339 * byte of the buffer's contents. |
441 * byte of the buffer's contents |
340 */ |
442 * @retval false otherwise |
341 __attribute__((__nonnull__)) |
443 */ |
342 int cxBufferEof(const CxBuffer *buffer); |
444 cx_attr_nonnull |
|
445 cx_attr_nodiscard |
|
446 bool cxBufferEof(const CxBuffer *buffer); |
343 |
447 |
344 |
448 |
345 /** |
449 /** |
346 * Ensures that the buffer has a minimum capacity. |
450 * Ensures that the buffer has a minimum capacity. |
347 * |
451 * |
348 * If the current capacity is not sufficient, the buffer will be extended. |
452 * If the current capacity is not sufficient, the buffer will be extended. |
349 * |
453 * |
350 * @param buffer the buffer |
454 * @param buffer the buffer |
351 * @param capacity the minimum required capacity for this buffer |
455 * @param capacity the minimum required capacity for this buffer |
352 * @return 0 on success or a non-zero value on failure |
456 * @retval zero the capacity was already sufficient or successfully increased |
353 */ |
457 * @retval non-zero on allocation failure |
354 __attribute__((__nonnull__)) |
458 */ |
|
459 cx_attr_nonnull |
355 int cxBufferMinimumCapacity( |
460 int cxBufferMinimumCapacity( |
356 CxBuffer *buffer, |
461 CxBuffer *buffer, |
357 size_t capacity |
462 size_t capacity |
358 ); |
463 ); |
359 |
464 |
360 /** |
465 /** |
361 * Writes data to a CxBuffer. |
466 * Writes data to a CxBuffer. |
|
467 * |
|
468 * If automatic flushing is not enabled, the data is simply written into the |
|
469 * buffer at the current position and the position of the buffer is increased |
|
470 * by the number of bytes written. |
362 * |
471 * |
363 * If flushing is enabled and the buffer needs to flush, the data is flushed to |
472 * 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 |
473 * 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 |
474 * 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 |
475 * 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 |
476 * 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 |
477 * 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. |
478 * 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 |
479 * If number of items that shall be written is larger than the buffer can hold, |
371 * could be written during the process. It does not necessarily mean that those |
480 * the first items from @c ptr are directly relayed to the flush target, if |
372 * elements are still in this buffer, because some of them could have also be |
481 * possible. |
373 * flushed already. |
482 * The number returned by this function is only the number of elements from |
374 * |
483 * @c ptr that could be written to either the flush target or the buffer. |
375 * If automatic flushing is not enabled, the position of the buffer is increased |
484 * |
376 * by the number of bytes written. |
485 * @note The signature is compatible with the fwrite() family of functions. |
377 * |
|
378 * \note The signature is compatible with the fwrite() family of functions. |
|
379 * |
486 * |
380 * @param ptr a pointer to the memory area containing the bytes to be written |
487 * @param ptr a pointer to the memory area containing the bytes to be written |
381 * @param size the length of one element |
488 * @param size the length of one element |
382 * @param nitems the element count |
489 * @param nitems the element count |
383 * @param buffer the CxBuffer to write to |
490 * @param buffer the CxBuffer to write to |
384 * @return the total count of elements written |
491 * @return the total count of elements written |
385 */ |
492 * @see cxBufferAppend() |
386 __attribute__((__nonnull__)) |
493 * @see cxBufferRead() |
|
494 */ |
|
495 cx_attr_nonnull |
387 size_t cxBufferWrite( |
496 size_t cxBufferWrite( |
388 const void *ptr, |
497 const void *ptr, |
389 size_t size, |
498 size_t size, |
390 size_t nitems, |
499 size_t nitems, |
391 CxBuffer *buffer |
500 CxBuffer *buffer |
392 ); |
501 ); |
393 |
502 |
394 /** |
503 /** |
|
504 * Appends data to a CxBuffer. |
|
505 * |
|
506 * The data is always appended to current data within the buffer, |
|
507 * regardless of the current position. |
|
508 * This is especially useful when the buffer is primarily meant for reading |
|
509 * while additional data is added to the buffer occasionally. |
|
510 * Consequently, the position of the buffer is unchanged after this operation. |
|
511 * |
|
512 * @note The signature is compatible with the fwrite() family of functions. |
|
513 * |
|
514 * @param ptr a pointer to the memory area containing the bytes to be written |
|
515 * @param size the length of one element |
|
516 * @param nitems the element count |
|
517 * @param buffer the CxBuffer to write to |
|
518 * @return the total count of elements written |
|
519 * @see cxBufferWrite() |
|
520 * @see cxBufferRead() |
|
521 */ |
|
522 cx_attr_nonnull |
|
523 size_t cxBufferAppend( |
|
524 const void *ptr, |
|
525 size_t size, |
|
526 size_t nitems, |
|
527 CxBuffer *buffer |
|
528 ); |
|
529 |
|
530 /** |
|
531 * Performs a single flush-run on the specified buffer. |
|
532 * |
|
533 * Does nothing when the position in the buffer is zero. |
|
534 * Otherwise, the data until the current position minus |
|
535 * one is considered for flushing. |
|
536 * Note carefully that flushing will never exceed the |
|
537 * current @em position, even when the size of the |
|
538 * buffer is larger than the current position. |
|
539 * |
|
540 * One flush run will try to flush @c blkmax many |
|
541 * blocks of size @c blksize until either the @p buffer |
|
542 * has no more data to flush or the write function |
|
543 * used for flushing returns zero. |
|
544 * |
|
545 * The buffer is shifted left for that many bytes |
|
546 * the flush operation has successfully flushed. |
|
547 * |
|
548 * @par Example 1 |
|
549 * Assume you have a buffer with size 340 and you are |
|
550 * at position 200. The flush configuration is |
|
551 * @c blkmax=4 and @c blksize=64 . |
|
552 * Assume that the entire flush operation is successful. |
|
553 * All 200 bytes on the left hand-side from the current |
|
554 * position are written. |
|
555 * That means, the size of the buffer is now 140 and the |
|
556 * position is zero. |
|
557 * |
|
558 * @par Example 2 |
|
559 * Same as Example 1, but now the @c blkmax is 1. |
|
560 * The size of the buffer is now 276 and the position is 136. |
|
561 * |
|
562 * @par Example 3 |
|
563 * Same as Example 1, but now assume the flush target |
|
564 * only accepts 100 bytes before returning zero. |
|
565 * That means, the flush operations manages to flush |
|
566 * one complete block and one partial block, ending |
|
567 * up with a buffer with size 240 and position 100. |
|
568 * |
|
569 * @remark Just returns zero when flushing was not enabled with |
|
570 * cxBufferEnableFlushing(). |
|
571 * |
|
572 * @remark When the buffer uses copy-on-write, the memory |
|
573 * is copied first, before attempting any flush. |
|
574 * This is, however, considered an erroneous use of the |
|
575 * buffer, because it does not make much sense to put |
|
576 * readonly data into an UCX buffer for flushing, instead |
|
577 * of writing it directly to the target. |
|
578 * |
|
579 * @param buffer the buffer |
|
580 * @return the number of successfully flushed bytes |
|
581 * @see cxBufferEnableFlushing() |
|
582 */ |
|
583 cx_attr_nonnull |
|
584 size_t cxBufferFlush(CxBuffer *buffer); |
|
585 |
|
586 /** |
395 * Reads data from a CxBuffer. |
587 * Reads data from a CxBuffer. |
396 * |
588 * |
397 * The position of the buffer is increased by the number of bytes read. |
589 * The position of the buffer is increased by the number of bytes read. |
398 * |
590 * |
399 * \note The signature is compatible with the fread() family of functions. |
591 * @note The signature is compatible with the fread() family of functions. |
400 * |
592 * |
401 * @param ptr a pointer to the memory area where to store the read data |
593 * @param ptr a pointer to the memory area where to store the read data |
402 * @param size the length of one element |
594 * @param size the length of one element |
403 * @param nitems the element count |
595 * @param nitems the element count |
404 * @param buffer the CxBuffer to read from |
596 * @param buffer the CxBuffer to read from |
405 * @return the total number of elements read |
597 * @return the total number of elements read |
406 */ |
598 * @see cxBufferWrite() |
407 __attribute__((__nonnull__)) |
599 * @see cxBufferAppend() |
|
600 */ |
|
601 cx_attr_nonnull |
408 size_t cxBufferRead( |
602 size_t cxBufferRead( |
409 void *ptr, |
603 void *ptr, |
410 size_t size, |
604 size_t size, |
411 size_t nitems, |
605 size_t nitems, |
412 CxBuffer *buffer |
606 CxBuffer *buffer |
415 /** |
609 /** |
416 * Writes a character to a buffer. |
610 * Writes a character to a buffer. |
417 * |
611 * |
418 * The least significant byte of the argument is written to the buffer. If the |
612 * 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, |
613 * 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 |
614 * the buffer capacity is extended by cxBufferMinimumCapacity(). If the feature |
421 * disabled or buffer extension fails, \c EOF is returned. |
615 * is disabled or buffer extension fails, @c EOF is returned. |
422 * |
616 * |
423 * On successful write, the position of the buffer is increased. |
617 * On successful write, the position of the buffer is increased. |
|
618 * |
|
619 * If you just want to write a null-terminator at the current position, you |
|
620 * should use cxBufferTerminate() instead. |
424 * |
621 * |
425 * @param buffer the buffer to write to |
622 * @param buffer the buffer to write to |
426 * @param c the character to write |
623 * @param c the character to write |
427 * @return the byte that has bean written or \c EOF when the end of the stream is |
624 * @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 |
625 * reached and automatic extension is not enabled or not possible |
429 */ |
626 * @see cxBufferTerminate() |
430 __attribute__((__nonnull__)) |
627 */ |
|
628 cx_attr_nonnull |
431 int cxBufferPut( |
629 int cxBufferPut( |
432 CxBuffer *buffer, |
630 CxBuffer *buffer, |
433 int c |
631 int c |
434 ); |
632 ); |
435 |
633 |
436 /** |
634 /** |
|
635 * Writes a terminating zero to a buffer at the current position. |
|
636 * |
|
637 * On successful write, @em neither the position @em nor the size of the buffer is |
|
638 * increased. |
|
639 * |
|
640 * The purpose of this function is to have the written data ready to be used as |
|
641 * a C string. |
|
642 * |
|
643 * @param buffer the buffer to write to |
|
644 * @return zero, if the terminator could be written, non-zero otherwise |
|
645 */ |
|
646 cx_attr_nonnull |
|
647 int cxBufferTerminate(CxBuffer *buffer); |
|
648 |
|
649 /** |
437 * Writes a string to a buffer. |
650 * Writes a string to a buffer. |
|
651 * |
|
652 * This is a convenience function for <code>cxBufferWrite(str, 1, strlen(str), buffer)</code>. |
438 * |
653 * |
439 * @param buffer the buffer |
654 * @param buffer the buffer |
440 * @param str the zero-terminated string |
655 * @param str the zero-terminated string |
441 * @return the number of bytes written |
656 * @return the number of bytes written |
442 */ |
657 */ |
443 __attribute__((__nonnull__)) |
658 cx_attr_nonnull |
|
659 cx_attr_cstr_arg(2) |
444 size_t cxBufferPutString( |
660 size_t cxBufferPutString( |
445 CxBuffer *buffer, |
661 CxBuffer *buffer, |
446 const char *str |
662 const char *str |
447 ); |
663 ); |
448 |
664 |