Managed binary buffers

#include <libcork/ds.h>

This section defines an interface for handling reference-counted binary buffers. The cork_managed_buffer type wraps a buffer with a simple reference count, and takes care of freeing the necessary resources when the reference count drops to zero. There should only be a single cork_managed_buffer instance for any given buffer, regardless of how many threads or functions access that buffer. Each thread or function that uses the buffer does so via a cork_slice instance. This type is meant to be allocated directly on the stack (or in some other managed storage), and keeps a pointer to the managed buffer instance that it slices. As its name implies, a slice can refer to a subset of the buffer.

struct cork_managed_buffer

A “managed buffer”, which wraps a buffer with a simple reference count.

Managed buffer consumers should consider all of the fields of this class private. Managed buffer implementors should fill in this fields when constructing a new cork_managed_buffer instance.

const void *buf

The buffer that this instance manages.

size_t size

The size of buf.

volatile int ref_count

A reference count for the buffer. If this drops to 0, the buffer will be finalized.

struct cork_managed_buffer_iface *iface

The managed buffer implementation for this instance.

struct cork_managed_buffer *cork_managed_buffer_ref(struct cork_managed_buffer *buf)

Atomically increase the reference count of a managed buffer. This function is thread-safe.

void cork_managed_buffer_unref(struct cork_managed_buffer *buf)

Atomically decrease the reference count of a managed buffer. If the reference count falls to 0, the instance is freed. This function is thread-safe.

int cork_managed_buffer_slice(struct cork_slice *dest, struct cork_managed_buffer *buffer, size_t offset, size_t length)
int cork_managed_buffer_slice_offset(struct cork_slice *dest, struct cork_managed_buffer *buffer, size_t offset)

Initialize a new slice that refers to a subset of a managed buffer. The offset and length parameters identify the subset. (For the _slice_offset variant, the length is calculated automatically to include all of the managed buffer content starting from offset.) If these parameters don’t refer to a valid portion of the buffer, we return false, and you must not try to deference the slice’s buf pointer. If the slice is valid, we return true.

Regardless of whether the new slice is valid, you must ensure that you call cork_slice_finish() when you are done with the slice.

Predefined managed buffer implementations

struct cork_managed_buffer *cork_managed_buffer_new_copy(const void *buf, size_t size)

Make a copy of buf, and allocate a new managed buffer to manage this copy. The copy will automatically be freed when the managed buffer’s reference count drops to 0.

void (*cork_managed_buffer_freer)(void *buf, size_t size)

A finalization function for a managed buffer created by cork_managed_buffer_new().

struct cork_managed_buffer *cork_managed_buffer_new(const void *buf, size_t size, cork_managed_buffer_freer free)

Allocate a new managed buffer to manage an existing buffer (buf). The existing buffer is not copied; the new managed buffer instance takes control of it. When the managed buffer’s reference count drops to 0, it will call free to finalize buf.

This is a helper function, and keeps you from having to write a complete custom managed buffer implementation when you don’t need to store any additional state in the managed buffer object.

Note

The free function is not responsible for freeing the cork_managed_buffer instance itself.

Custom managed buffer implementations

struct cork_managed_buffer_iface

The interface of methods that managed buffer implementations must provide.

void (*free)(struct cork_managed_buffer *self)

Free the contents of a managed buffer, and the cork_managed_buffer instance itself.