docs/Writerside/topics/buffer.h.md

Wed, 26 Mar 2025 12:26:20 +0100

author
Mike Becker <universe@uap-core.de>
date
Wed, 26 Mar 2025 12:26:20 +0100
changeset 1262
7cc81244b28a
parent 1261
6bbc308b7a20
child 1263
f993745c60f0
permissions
-rw-r--r--

document buffer read operations

relates to #451

# Buffer

This buffer implementation can be used to read from or write to memory like you would do with a stream.

This allows the use of `cx_stream_copy()` (see [](streams.h.md)) to copy contents from one buffer to another,
or from a file or network streams to the buffer and vice versa.

More features for convenient use of the buffer can be enabled, like automatic memory management,
automatic resizing of the buffer space, or automatic flushing of contents.

The functions `cxBufferRead()` and `cxBufferWrite()` are `cx_read_func` and `cx_write_func` compatible,
which in turn have a compatible signature to `fread()` and `fwrite()`.
However, due to the different pointer type, the function pointers do not type check out of the box.
For convenience, the macros `cxBufferReadFunc` and `cxBufferWriteFunc` are defined, which perform the necessary cast.

## Example

<warning>
TODO: add example
</warning>

## Create

```C
#include <cx/buffer.h>

int cxBufferInit(CxBuffer *buffer, void *space, size_t capacity,
        const CxAllocator *allocator, int flags);

CxBuffer *cxBufferCreate(void *space,size_t capacity,
        const CxAllocator *allocator, int flags);

// available flags:
#define CX_BUFFER_DEFAULT
#define CX_BUFFER_FREE_CONTENTS
#define CX_BUFFER_AUTO_EXTEND
#define CX_BUFFER_COPY_ON_WRITE
#define CX_BUFFER_COPY_ON_EXTEND
```

<warning>
TODO: document
</warning>

## Destroy

```C
#include <cx/buffer.h>

void cxBufferDestroy(CxBuffer *buffer);

void cxBufferFree(CxBuffer *buffer);
```

The above functions destroy the buffer and deallocate the buffer's memory when the `CX_BUFFER_FREE_CONTENTS` flag is set.

The function `cxBufferDestroy()` is to be used when the buffer was initialized with `cxBufferInit()`,
and the function `cxBufferFree()` is to be used when the buffer was created with `cxBufferCreate()`.
The only difference is, that `cxBufferFree()` additionally deallocates the memory of the `CxBuffer` structure. 

## Write

```C
#include <cx/buffer.h>

size_t cxBufferWrite(const void *ptr, size_t size, size_t nitems,
        CxBuffer *buffer);

size_t cxBufferAppend(const void *ptr, size_t size, size_t nitems,
        CxBuffer *buffer);

int cxBufferPut(CxBuffer *buffer, int c);

size_t cxBufferPutString(CxBuffer *buffer, const char *str);

int cxBufferTerminate(CxBuffer *buffer);

int cxBufferMinimumCapacity(CxBuffer *buffer, size_t capacity);
```

<warning>
TODO: document
</warning>

## Read

```C
#include <cx/buffer.h>

size_t cxBufferRead(void *ptr, size_t size, size_t nitems,
        CxBuffer *buffer);

int cxBufferGet(CxBuffer *buffer);

bool cxBufferEof(const CxBuffer *buffer);
```

The function `cxBufferRead()` reads `nitems` number of items of `size` bytes each from the `buffer`
and stores them into the memory pointed to by `ptr`, which must be sufficiently large to hold the contents.
The function returns the actual bytes read, which might be lower, if the desired number of items is not available.

The function `cxBufferGet()` is a `fgetc()`-like function which returns the next byte in the buffer converted to an `int`.
Similar to `fgetc()` it returns `EOF` when there are no more bytes in the buffer.

When all bytes from the buffer have been read, the function `cxBufferEof()` returns true. 

All read functions advance the position in the buffer by the number of read bytes.

> When you want to read from a buffer that you previously used for writing, do not forget to set the position
> in the buffer to zero, e.g. by calling `cxBufferSeek()`.

## Reset and Clear

```C
#include <cx/buffer.h>

void cxBufferReset(CxBuffer *buffer);

void cxBufferClear(CxBuffer *buffer);
```

The function `cxBufferReset()` sets both size and position of the buffer to zero,
and `cxBufferClear()` additionally uses `memset()` to set every byte in the buffer to zero.

> When clearing the buffer, only the "live" data, i.e. bytes with indices `[0..size)`, are cleared.
> If you which to clear the entire buffer's memory, you would need to set the size to the capacity, first.

> If the `CX_BUFFER_COPY_ON_WRITE` flag is set, `cxBufferClear()` behaves exactly like `cxBufferReset()`,
> because writing to the contents is disallowed.
>{style="note"}

## Random Access

```C
#include <cx/buffer.h>

int cxBufferSeek(CxBuffer *buffer, off_t offset, int whence);
```

The function `cxBufferSeek()` is a `fseek()`-like function that sets the current position in the buffer
relative to the start (when `whence` is `SEEK_SET`), the current position (when `whence` is `SEEK_CUR`),
or end (when `whence` is `SEEK_END`) of the buffer.

If the resulting position is negative, or larger than the size (i.e. the first unused byte),
this function returns non-zero and sets `errno` to `EOVERFLOW`.

> Note that the error behavior of `cxBufferSeek()` is not exactly the same as for POSIX `fseek()`.

## Shift Contents

```C
#include <cx/buffer.h>

int cxBufferShift(CxBuffer *buffer, off_t shift);

int cxBufferShiftRight(CxBuffer *buffer, size_t shift);

int cxBufferShiftLeft(CxBuffer *buffer, size_t shift);
```

The function `cxBufferShift()` moves the contents within the buffer by the specified `shift` offset,
where a negative offset means a shift to the left, and a positive offset means a shift to the right.
It also adjusts the current position within the buffer, and in case of a right shift also the size, by the same offset.

Data that is shift to the left, is always discarded when the new position of a byte would be smaller than zero.
If the new position would be smaller than zero, it is set exactly to zero.

When data is shift to the right, the behavior depends on the `CX_BUFFER_AUTO_EXTEND` flag.
If set, the function extends the buffer's capacity before moving the data.
Otherwise, the function discards all data that would exceed the buffer's capacity, and both the size and the position are equal to the capacity
(which means, `cxBufferEof()` returns `true` after the operation). 

The functions `cxBufferShiftRight()` and `cxBufferShiftLeft()` accept a larger (but in both cases positive) shift offset,
which usually does not make much sense on a 64-bit platform where `off_t` is already large enough to represent any reasonable offset.
You may, however, still use those function to express more explicitly in your code in which direction you want the contents to be shifted.

## Flushing

```C
#include <cx/buffer.h>

typedef struct cx_buffer_flush_config_s {
    size_t threshold;
    size_t blksize;
    size_t blkmax;
    void *target;
    cx_write_func wfunc;
} CxBufferFlushConfig;

int cxBufferEnableFlushing(CxBuffer *buffer,
        CxBufferFlushConfig config);

size_t cxBufferFlush(CxBuffer *buffer);
```

<warning>
TODO: document
</warning>

<seealso>
<category ref="apidoc">
<a href="https://ucx.sourceforge.io/api/buffer_8h.html">buffer.h</a>
</category>
</seealso>

mercurial