#include <libcork/ds.h>
This section defines an interface for safely referring to the contents of a binary buffer, without needing to know where the buffer came from. In addition to accessing the contents of the underlying buffer, slices support three operations:
These operations are represented by the slice interface (cork_slice_iface). To write a new slice implementation, you just need to provide an instance of this interface type.
Note
There’s no generic constructor or initialization function for slices; instead, you’ll create a slice from some other data structure, using a function specific to that data structure. (An example is the cork_buffer_to_slice() function, which initializes a slice from a resizable buffer.)
A specific window into a portion of an underlying binary buffer.
Instances of this class do not need to be (and almost never are) allocated on the heap; you can define an instance directly on the stack, or in some other kind of managed storage.
Note
It is very important that you ensure that cork_slice_finish() is called whenever you are done with a slice — if you don’t, there’s a very good chance that the underlying buffer will never be freed. Yes, yes, it’s unfortunate that C doesn’t have try/finally or RAII, but suck it up and make sure that cork_slice_finish() gets called.
The beginning of the sliced portion of the underlying buffer.
The slice implementation of the underlying buffer. For slice consumers, this field should be considered private. For slice implementors, you should fill in this field with your slice interface.
An opaque pointer used by the slice implementation. For slice consumers, this field should be considered private. For slice implementors, you can use this field to point at the underlying buffer (and/or any additional metadata that you need.)
Clear a slice object. This fills in a slice instance so that it’s “empty”. You should not try to call any of the slice methods on an empty slice, nor should you try to dereference the slice’s buf pointer. An empty slice is equivalent to a NULL pointer.
Return whether a slice is empty.
Initialize a new slice that refers to a subset of an existing slice. The offset and length parameters identify the subset. (For the _copy_offset variant, the length is calculated automatically to include all of the original slice content starting from offset.)
For the _fast variants, we don’t verify that the offset and length parameters refer to a valid subset of the slice. This is your responsibility. For the non-_fast variants, we perform a bounds check for you, and return an error if the requested slice is invalid.
Regardless of whether the new slice is valid, you must ensure that you call cork_slice_finish() on dest when you are done with it.
Update a slice to refer to a subset of its contents. The offset and length parameters identify the subset. (For the _slice_offset variant, the length is calculated automatically to include all of the original slice content starting from offset.)
For the _fast variants, we don’t verify that the offset and length parameters refer to a valid subset of the slice. This is your responsibility. For the non-_fast variants, we perform a bounds check for you, and return an error if the requested slice is invalid.
Finalize a slice, freeing the underlying buffer if necessary.
Compare the contents of two slices for equality. (The contents of the slices are compared, not their pointers; this is the slice equivalent of memcmp, not the == operator.)
The interface of methods that slice implementations must provide.
Called when the slice should be freed. If necessary, you should free the contents of the underlying buffer. (If the buffer contents can be shared, it’s up to you to keep track of when the contents are safe to be freed.)
This function pointer can be NULL if you don’t need to free any underlying buffer.
Create a copy of a slice. You can assume that offset and length refer to a valid subset of self‘s content.
Update self to point at a different subset of the underlying buffer. You can assume that offset and length refer to a valid subset of the buffer. (They will be relative to self‘s existing slice, and not to the original buffer.)
This function pointer can be NULL if you don’t need to do anything special to the underlying buffer; in this case, cork_slice_slice() and cork_slice_slice_offset() will update the slice’s buf and size fields for you.
Several libcork classes can be used to initialize a slice:
In addition, you can initialize a slice to point at a static string using the following function:
Initializes dest to point at the given static buffer. Since the buffer is static, and guaranteed to always exist, the slice’s copy method doesn’t copy the underlying data, it just creates a new pointer to the existing buffer.
Note
You can also use this function to refer to a non-static buffer, but then you take responsibility for ensuring that the underlying buffer exists for at least as long as the slice, and any copies made of the slice.
As with all slices, you must ensure that you call cork_slice_finish() when you’re done with the slice.