🔨 Creating a vector
In this section we'll discuss creation of the vector.
Based on Example file.
⚙️ Default options
#define vector_create(...)
Vector constructor.
Vector control structure type.
⚙️ Custom options
.element_size = sizeof(float),
.initial_cap = 100
);
- Note
- Extension and Custom allocator options will be discussed later.
⚙️ No macro wrapper
You can avoid macro wrapper with default values if you know what you are doing.
Just create opts on stack
and pass by reference into a vector_create_ function directly:
size_t element_size
Size of the underling element type.
vector_t * vector_create_(const vector_opts_t *const opts)
Vector contructor.
⿻ Clone an existing vector
With vector_clone you are able to produce exact copy of an existing vector.
vector_t * vector_clone(const vector_t *const vector)
Duplicates a vector.
❗Error handling
Check that vector
value is NULL
, then resolve allocation error. If you got none resolution choises, perform gracefull program termination. See following example, print error and exit abnormally.
if (!vector)
{
perror("vector_create");
abort();
}
🧨 Deallocating a vector
Prevent memory leaks by deallocation resources, when they not needed anymore!
void vector_destroy(vector_t *const vector)
Deallocates vector.
- Attention
- Always remember to deallocate
vector
created with vector_create or vector_clone !
⬆️ Extending a vector
In this section we'll discuss an extension points of the vector
⚙️ Allocate extended header
It is possible to reserve space to store derived class data
in a memory allocated by underlying vector.
Define a structure ext_t
that will be peallocated right after vector_t and allocator region if present:
typedef struct
{
size_t meta;
}
ext_t;
Create vector specifying vector_opts_t::ext_header_size to reserve space for ext_t
.
.ext_header_size = sizeof(ext_t),
.element_size = sizeof(long)
);
Initialize extended header:
*header = (ext_t) {0};
void * vector_get_ext_header(const vector_t *const vector)
Provides a location where user can put a header for the derived class.
❗Customize resize error
Resize function takes additional parameter error
indicating an error code that is going to be returned from resize when allocation error occures. This allows derived classes to provide custom error code that is not in vector_status_t and/or if they need different error codes depending on context they call resize from.
- See also
- vector_resize
⚙️ Override default allocator
Define a structure of the allocator region:
ALIGNED
macro serves as constructor for temporary reference to an alloc_t
.
#define ALIGNED(bytes) &(alloc_t){.alignment = bytes}
#if defined _WIN32 || defined __CYGWIN__
#define aligned_alloc(alignment, size) _aligned_malloc(size, alignment)
#endif
typedef struct alloc
{
size_t alignment;
size_t last_size;
}
alloc_t;
Create vector by providing alloc_opts_t :
.element_size = sizeof(int),
.size = sizeof(alloc_t),
.data = ALIGNED(MAX_ALIGNMENT),
),
);
#define alloc_opts(...)
Use this macro to define allocator opts in vector_opts_t.
Implement vector_alloc, vector_realloc, and vector_free functions
Functions can be implemented in external translation unit and then linked:
void *
vector_alloc(
const size_t alloc_size,
void *
const param)
{
assert(param);
alloc_t* alloc = (alloc_t*)param;
return aligned_alloc(alloc->alignment, alloc_size);
void * vector_alloc(const size_t alloc_size, void *const param)
Allocates memory chunk of alloc_size.
}
void *
vector_realloc(
void *
const ptr,
size_t alloc_size,
void *
const param)
{
assert(ptr);
assert(alloc_size > 0);
assert(param);
alloc_t *alloc = (alloc_t*)param;
if (alloc_size == alloc->last_size)
{
return ptr;
void * vector_realloc(void *const ptr, size_t alloc_size, void *const param)
Reallocates already allocated memory chunk in order to change allocation size.
}
{
(void) param;
free(ptr);
}
void vector_free(void *const ptr, void *const param)
Free allocation that was previously allocated.