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)	((iterator)->offset)

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		{ 0, NULL, NULL }

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