## GskBuffer

GskBuffer — a fast, flexible in-memory data buffer

## Synopsis

                        GskBuffer;
                        GskBufferFragment;
    void                gsk_buffer_construct                (GskBuffer *buffer);
    guint               gsk_buffer_read                     (GskBuffer *buffer,
                                                             gpointer data,
                                                             guint max_length);
    guint               gsk_buffer_peek                     (const GskBuffer *buffer,
                                                             gpointer data,
                                                             guint max_length);
    int                 gsk_buffer_discard                  (GskBuffer *buffer,
                                                             guint max_discard);
    char *              gsk_buffer_read_line                (GskBuffer *buffer);
    char *              gsk_buffer_parse_string0            (GskBuffer *buffer);
    int                 gsk_buffer_peek_char                (const GskBuffer *buffer);
    int                 gsk_buffer_read_char                (GskBuffer *buffer);
    void                gsk_buffer_append                   (GskBuffer *buffer,
                                                             gconstpointer data,
                                                             guint length);
    void                gsk_buffer_append_string            (GskBuffer *buffer,
                                                             const char *string);
    void                gsk_buffer_append_char              (GskBuffer *buffer,
                                                             char character);
    void                gsk_buffer_append_string0           (GskBuffer *buffer,
                                                             const char *string);
    void                gsk_buffer_append_foreign           (GskBuffer *buffer,
                                                             gconstpointer data,
                                                             int length,
                                                             GDestroyNotify destroy,
                                                             gpointer destroy_data);
    void                gsk_buffer_printf                   (GskBuffer *buffer,
                                                             const char *format,
                                                             ...);
    void                gsk_buffer_vprintf                  (GskBuffer *buffer,
                                                             const char *format,
                                                             va_list args);
    guint               gsk_buffer_drain                    (GskBuffer *dst,
                                                             GskBuffer *src);
    guint               gsk_buffer_transfer                 (GskBuffer *dst,
                                                             GskBuffer *src,
                                                             guint max_transfer);
    int                 gsk_buffer_writev                   (GskBuffer *read_from,
                                                             int fd);
    int                 gsk_buffer_read_in_fd               (GskBuffer *write_to,
                                                             int read_from);
    int                 gsk_buffer_index_of                 (GskBuffer *buffer,
                                                             char char_to_find);
    int                 gsk_buffer_polystr_index_of         (GskBuffer *buffer,
                                                             char **strings);
    void                gsk_buffer_destruct                 (GskBuffer *to_destroy);
    void                gsk_buffer_cleanup_recycling_bin    ();
                        GskBufferIterator;
    #define             gsk_buffer_iterator_offset          (iterator)
    void                gsk_buffer_iterator_construct       (GskBufferIterator *iterator,
                                                             GskBuffer *to_iterate);
    guint               gsk_buffer_iterator_peek            (GskBufferIterator *iterator,
                                                             gpointer out,
                                                             guint max_length);
    guint               gsk_buffer_iterator_read            (GskBufferIterator *iterator,
                                                             gpointer out,
                                                             guint max_length);
    guint               gsk_buffer_iterator_skip            (GskBufferIterator *iterator,
                                                             guint max_length);
    gboolean            gsk_buffer_iterator_find_char       (GskBufferIterator *iterator,
                                                             char c);
    #define             GSK_BUFFER_STATIC_INIT

## Description

This code manages a binary data buffer. Data is maintained first-in first-out; so `gsk_buffer_append()` writes to the end of the buffer, and `gsk_buffer_read()` reads from the beginning.

## Details

### GskBuffer

    typedef struct {
      guint			size;

      GskBufferFragment    *first_frag;
      GskBufferFragment    *last_frag;
    } GskBuffer;

A buffer is just a list of fragments and a size counter.

guint `size`; | the number of bytes in the buffer total.
GskBufferFragment *`first_frag`; | the first fragment in the buffer (read end)
GskBufferFragment *`last_frag`; | the last fragment in the buffer (write end)

### GskBufferFragment

    typedef struct {
      GskBufferFragment    *next;
      char                 *buf;
      guint                 buf_max_size;	/* allocation size of buf */
      guint                 buf_start;	/* offset in buf of valid data */
      guint                 buf_length;	/* length of valid data in buf */

      gboolean              is_foreign;
      GDestroyNotify        destroy;
      gpointer              destroy_data;
    } GskBufferFragment;

This structure should rarely be accessed directly, instead you should use the GskBuffer methods. They are exposed for optimization and debugging convenience.

A single contiguous chunk of memory in the buffer. Each GskBufferFragment is managed by a single buffer, but internally fragments are sometimes transferred whole between buffers.

A foreign fragment is one which created with `gsk_buffer_append_foreign()`. It means that gsk will use the destroy method rather than the normal buffer pool, where data and the GskBufferFragment are allocated continguously. The headers of foreign fragments are pooled in a separate pool.

GskBufferFragment *`next`; | next fragment in the buffer.
char *`buf`; | raw data in the buffer
guint `buf_max_size`; | maximum size of buffer, assuming buf_start==0.
guint `buf_start`; | offset in `buf` of first readable data.
guint `buf_length`; | number of bytes currently in the buffer.
gboolean `is_foreign`; | is this fragment foreign?
GDestroyNotify `destroy`; | function to free foreign data.
gpointer `destroy_data`; | data to destroy to free buf, if foreign.

### gsk_buffer_construct ()

    void                gsk_buffer_construct                (GskBuffer *buffer);

Construct an empty buffer out of raw memory. (This is equivalent to filling the buffer with 0s)

`buffer` : | buffer to initialize (as empty).

### gsk_buffer_read ()

    guint               gsk_buffer_read                     (GskBuffer *buffer,
                                                             gpointer data,
                                                             guint max_length);

Removes up to `max_length` data from the beginning of the buffer, and writes it to `data`. The number of bytes actually read is returned.

`buffer` : | the buffer to read data from.
`data` : | buffer to fill with up to `max_length` bytes of data.
`max_length` : | maximum number of bytes to read.
Returns : | number of bytes transferred.

### gsk_buffer_peek ()

    guint               gsk_buffer_peek                     (const GskBuffer *buffer,
                                                             gpointer data,
                                                             guint max_length);

Copies up to `max_length` data from the beginning of the buffer, and writes it to `data`. The number of bytes actually copied is returned.

This function is just like `gsk_buffer_read()` except that the data is not removed from the buffer.

`buffer` : | the buffer to peek data from the front of. This buffer is unchanged by the operation.
`data` : | buffer to fill with up to `max_length` bytes of data.
`max_length` : | maximum number of bytes to peek.
Returns : | number of bytes copied into data.

### gsk_buffer_discard ()

    int                 gsk_buffer_discard                  (GskBuffer *buffer,
                                                             guint max_discard);

Removes up to `max_discard` data from the beginning of the buffer, and returns the number of bytes actually discarded.

`buffer` : | the buffer to discard data from.
`max_discard` : | maximum number of bytes to discard.
Returns : | number of bytes discarded.

### gsk_buffer_read_line ()

    char *              gsk_buffer_read_line                (GskBuffer *buffer);

Parse a newline (\n) terminated line from buffer and return it as a newly allocated string. The newline is changed to a NUL character.

If the buffer does not contain a newline, then NULL is returned.

`buffer` : | buffer to read a line from.
Returns : | a newly allocated NUL-terminated string, or NULL.

### gsk_buffer_parse_string0 ()

    char *              gsk_buffer_parse_string0            (GskBuffer *buffer);

Parse a NUL-terminated line from buffer and return it as a newly allocated string.

If the buffer does not contain a newline, then NULL is returned.

`buffer` : | buffer to read a line from.
Returns : | a newly allocated NUL-terminated string, or NULL.

### gsk_buffer_peek_char ()

    int                 gsk_buffer_peek_char                (const GskBuffer *buffer);

Get the first byte in the buffer as a positive or 0 number. If the buffer is empty, -1 is returned. The buffer is unchanged.

`buffer` : | buffer to peek a single byte from.
Returns : | an unsigned character or -1.

### gsk_buffer_read_char ()

    int                 gsk_buffer_read_char                (GskBuffer *buffer);

Get the first byte in the buffer as a positive or 0 number, and remove the character from the buffer. If the buffer is empty, -1 is returned.

`buffer` : | buffer to read a single byte from.
Returns : | an unsigned character or -1.

### gsk_buffer_append ()

    void                gsk_buffer_append                   (GskBuffer *buffer,
                                                             gconstpointer data,
                                                             guint length);

Append data into the buffer.

`buffer` : | the buffer to add data to. Data is put at the end of the buffer.
`data` : | binary data to add to the buffer.
`length` : | length of `data` to add to the buffer.

### gsk_buffer_append_string ()

    void                gsk_buffer_append_string            (GskBuffer *buffer,
                                                             const char *string);

Append a string to the buffer.

`buffer` : | the buffer to add data to. Data is put at the end of the buffer.
`string` : | NUL-terminated string to append to the buffer. The NUL is not appended.

### gsk_buffer_append_char ()

    void                gsk_buffer_append_char              (GskBuffer *buffer,
                                                             char character);

Append a byte to a buffer.

`buffer` : | the buffer to add the byte to.
`character` : | the byte to add to the buffer.

### gsk_buffer_append_string0 ()

    void                gsk_buffer_append_string0           (GskBuffer *buffer,
                                                             const char *string);

Append a NUL-terminated string to the buffer. The NUL is appended.

`buffer` : | the buffer to add data to. Data is put at the end of the buffer.
`string` : | NUL-terminated string to append to the buffer; NUL is appended.

### gsk_buffer_append_foreign ()

    void                gsk_buffer_append_foreign           (GskBuffer *buffer,
                                                             gconstpointer data,
                                                             int length,
                                                             GDestroyNotify destroy,
                                                             gpointer destroy_data);

This function allows data to be placed in a buffer without copying. It is the callers' responsibility to ensure that `data` will remain valid until the destroy method is called. `destroy` may be omitted if `data` is permanent, for example, if appended a static string into a buffer.

`buffer` : | the buffer to append into.
`data` : | the data to append.
`length` : | length of `data`.
`destroy` : | optional method to call when the data is no longer needed.
`destroy_data` : | the argument to the destroy method.

### gsk_buffer_printf ()

    void                gsk_buffer_printf                   (GskBuffer *buffer,
                                                             const char *format,
                                                             ...);

Append printf-style content to a buffer.

`buffer` : | the buffer to append to.
`format` : | printf-style format string describing what to append to buffer.
`...` : | values referenced by `format` string.

### gsk_buffer_vprintf ()

    void                gsk_buffer_vprintf                  (GskBuffer *buffer,
                                                             const char *format,
                                                             va_list args);

Append printf-style content to a buffer, given a va_list.

`buffer` : | the buffer to append to.
`format` : | printf-style format string describing what to append to buffer.
`args` : | values referenced by `format` string.

### gsk_buffer_drain ()

    guint               gsk_buffer_drain                    (GskBuffer *dst,
                                                             GskBuffer *src);

Transfer all data from `src` to `dst`, leaving `src` empty.

`dst` : | buffer to add to.
`src` : | buffer to remove from.
Returns : | the number of bytes transferred.

### gsk_buffer_transfer ()

    guint               gsk_buffer_transfer                 (GskBuffer *dst,
                                                             GskBuffer *src,
                                                             guint max_transfer);

Transfer data out of `src` and into `dst`. Data is removed from `src`. The number of bytes transferred is returned.

`dst` : | place to copy data into.
`src` : | place to read data from.
`max_transfer` : | maximum number of bytes to transfer.
Returns : | the number of bytes transferred.

### gsk_buffer_writev ()

    int                 gsk_buffer_writev                   (GskBuffer *read_from,
                                                             int fd);

Writes as much data as possible to the given file-descriptor using the writev(2) function to deal with multiple fragments efficiently, where available.

`read_from` : | buffer to take data from.
`fd` : | file-descriptor to write data to.
Returns : | the number of bytes transferred, or -1 on a write error (consult errno).

### gsk_buffer_read_in_fd ()

    int                 gsk_buffer_read_in_fd               (GskBuffer *write_to,
                                                             int read_from);

Append data into the buffer directly from the given file-descriptor.

`write_to` : | buffer to append data to.
`read_from` : | file-descriptor to read data from.
Returns : | the number of bytes transferred, or -1 on a read error (consult errno).

### gsk_buffer_index_of ()

    int                 gsk_buffer_index_of                 (GskBuffer *buffer,
                                                             char char_to_find);

Scans for the first instance of the given character.

`buffer` : | buffer to scan.
`char_to_find` : | a byte to look for.
Returns : | its index in the buffer, or -1 if the character is not in the buffer.

### gsk_buffer_polystr_index_of ()

    int                 gsk_buffer_polystr_index_of         (GskBuffer *buffer,
                                                             char **strings);

Scans for the first instance of any of the strings in the buffer.

`buffer` : | buffer to scan.
`strings` : | NULL-terminated set of string.
Returns : | the index of that instance, or -1 if not found.

### gsk_buffer_destruct ()

    void                gsk_buffer_destruct                 (GskBuffer *to_destroy);

Remove all fragments from a buffer, leaving it empty. The buffer is guaranteed to not to be consuming any resources, but it also is allowed to start using it again.

`to_destroy` : | the buffer to empty.

### gsk_buffer_cleanup_recycling_bin ()

    void                gsk_buffer_cleanup_recycling_bin    ();

Free unused buffer fragments. (Normally some are kept around to reduce strain on the global allocator.)

### GskBufferIterator

    typedef struct {
      GskBufferFragment *fragment;
      guint in_cur;
      guint cur_length;
      const guint8 *cur_data;
      guint offset;
    } GskBufferIterator;

An iterator which can be used to walk through a buffer.

You MUST not modify the buffer that you are editing in any way.

TODO: exceptions to the above may be feasible, but we have to see what the demands are...

GskBufferFragment *`fragment`; | which fragment we are currently in.
guint `in_cur`; | the offset in bytes into `fragment`.
guint `cur_length`; | the length of fragment.
const guint8 *`cur_data`; | the data of fragment.
guint `offset`; | the offset in bytes into the whole buffer.

### gsk_buffer_iterator_offset()

    #define             gsk_buffer_iterator_offset(iterator)

Get the offset in bytes into GskBuffer that we are into the whole buffer.

`iterator` : | the iterator to examine.

### gsk_buffer_iterator_construct ()

    void                gsk_buffer_iterator_construct       (GskBufferIterator *iterator,
                                                             GskBuffer *to_iterate);

Initialize a new GskBufferIterator.

`iterator` : | to initialize.
`to_iterate` : | the buffer to walk through.

### gsk_buffer_iterator_peek ()

    guint               gsk_buffer_iterator_peek            (GskBufferIterator *iterator,
                                                             gpointer out,
                                                             guint max_length);

Peek data from the current position of an iterator. The iterator's position is not changed.

`iterator` : | to peek data from.
`out` : | to copy data into.
`max_length` : | maximum number of bytes to write to `out`.
Returns : | number of bytes peeked into `out`.

### gsk_buffer_iterator_read ()

    guint               gsk_buffer_iterator_read            (GskBufferIterator *iterator,
                                                             gpointer out,
                                                             guint max_length);

Peek data from the current position of an iterator. The iterator's position is updated to be at the end of the data read.

`iterator` : | to read data from.
`out` : | to copy data into.
`max_length` : | maximum number of bytes to write to `out`.
Returns : | number of bytes read into `out`.

### gsk_buffer_iterator_skip ()

    guint               gsk_buffer_iterator_skip            (GskBufferIterator *iterator,
                                                             guint max_length);

Advance an iterator forward in the buffer, returning the number of bytes skipped.

`iterator` : | to advance.
`max_length` : | maximum number of bytes to skip forward.
Returns : | number of bytes skipped forward.

### gsk_buffer_iterator_find_char ()

    gboolean            gsk_buffer_iterator_find_char       (GskBufferIterator *iterator,
                                                             char c);

If it exists, skip forward to the next instance of `c` and return TRUE. Otherwise, do nothing and return FALSE.

`iterator` : | to advance.
`c` : | the character to look for.
Returns : | whether the character was found.

### GSK_BUFFER_STATIC_INIT

    #define             GSK_BUFFER_STATIC_INIT

Macro which can be used to initialize an empty buffer. One can write: GskBuffer buf = GSK_BUFFER_STATIC_INIT;