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