added vector_take_at() (and take_back()) which removes like pop() without destructor calling, and copies into supplied pointer - ownership transfer
This commit is contained in:
@@ -30,6 +30,9 @@ Guarantees:
|
|||||||
On a vector with an element destructor this is rejected with -1 instead,
|
On a vector with an element destructor this is rejected with -1 instead,
|
||||||
as a byte-wise copy would leave two slots owning the same memory. To
|
as a byte-wise copy would leave two slots owning the same memory. To
|
||||||
duplicate an owning element, copy what it owns yourself and push that.
|
duplicate an owning element, copy what it owns yourself and push that.
|
||||||
|
- vector_take_at() and vector_take_back() transfer ownership of the element to the
|
||||||
|
caller, and do not call the destructor on it. It is the caller's responsibility
|
||||||
|
to free whatever the element owns.
|
||||||
|
|
||||||
Element destructors:
|
Element destructors:
|
||||||
A vector may be given an element destructor with vector_set_destructor(). It is
|
A vector may be given an element destructor with vector_set_destructor(). It is
|
||||||
@@ -37,6 +40,10 @@ called for every element that leaves the vector, i.e. by vector_pop_back(),
|
|||||||
vector_pop_at(), vector_set() (on the element being overwritten), vector_clear()
|
vector_pop_at(), vector_set() (on the element being overwritten), vector_clear()
|
||||||
and vector_destroy().
|
and vector_destroy().
|
||||||
|
|
||||||
|
The destructor is NOT called by vector_take_back() or vector_take_at(), as these
|
||||||
|
functions transfer ownership of the element to the caller. It is the caller's
|
||||||
|
responsibility to free whatever the element owns.
|
||||||
|
|
||||||
The destructor receives a pointer to the element's slot inside the vector's data
|
The destructor receives a pointer to the element's slot inside the vector's data
|
||||||
array - NOT a pointer that was returned by malloc(). It must free whatever the
|
array - NOT a pointer that was returned by malloc(). It must free whatever the
|
||||||
element owns, and must never free the pointer it was handed, as that memory
|
element owns, and must never free the pointer it was handed, as that memory
|
||||||
@@ -103,6 +110,8 @@ static inline int vector_prune(vector_t* vec);
|
|||||||
static inline int vector_push_back(vector_t* vec, const void* element);
|
static inline int vector_push_back(vector_t* vec, const void* element);
|
||||||
static inline int vector_pop_back(vector_t* vec);
|
static inline int vector_pop_back(vector_t* vec);
|
||||||
static inline int vector_pop_at(vector_t* vec, size_t index);
|
static inline int vector_pop_at(vector_t* vec, size_t index);
|
||||||
|
static inline int vector_take_at(vector_t* vec, size_t index, void* out);
|
||||||
|
static inline int vector_take_back(vector_t* vec, void* out);
|
||||||
static inline int vector_insert(vector_t* vec, size_t index, const void* element);
|
static inline int vector_insert(vector_t* vec, size_t index, const void* element);
|
||||||
static inline int vector_clear(vector_t* vec);
|
static inline int vector_clear(vector_t* vec);
|
||||||
static inline int vector_set(vector_t* vec, size_t index, const void* element);
|
static inline int vector_set(vector_t* vec, size_t index, const void* element);
|
||||||
@@ -329,7 +338,7 @@ static inline int vector_push_back(vector_t* vec, const void* element) {
|
|||||||
@brief Removes the last element from the vector.
|
@brief Removes the last element from the vector.
|
||||||
@param vec A pointer to the vector from which the element will be removed.
|
@param vec A pointer to the vector from which the element will be removed.
|
||||||
@return 0 on success, -1 if the vector is NULL or empty.
|
@return 0 on success, -1 if the vector is NULL or empty.
|
||||||
@attention After calling this function, the vector's size will be reduced by one. The memory occupied by the removed element will not be freed automatically unless a destructor is set.
|
@attention After calling this function, the vector's size will be reduced by one. The memory occupied by the removed element will not be freed automatically unless a destructor is set (in which case, the destructor will be called on the element being removed if it is set). Use vector_take_back() to retrieve the last element, remove it from the vector, and NOT call the destructor on it (hands ownership to the caller).
|
||||||
*/
|
*/
|
||||||
static inline int vector_pop_back(vector_t* vec) {
|
static inline int vector_pop_back(vector_t* vec) {
|
||||||
if (!vec || vec->size == 0) {
|
if (!vec || vec->size == 0) {
|
||||||
@@ -350,7 +359,7 @@ static inline int vector_pop_back(vector_t* vec) {
|
|||||||
@param vec A pointer to the vector from which the element will be removed.
|
@param vec A pointer to the vector from which the element will be removed.
|
||||||
@param index The index of the element to be removed.
|
@param index The index of the element to be removed.
|
||||||
@return 0 on success, -1 if the vector is NULL or the index is out of bounds.
|
@return 0 on success, -1 if the vector is NULL or the index is out of bounds.
|
||||||
@attention After calling this function, the vector's size will be reduced by one. The memory occupied by the removed element will not be freed automatically unless a destructor is set.
|
@attention After calling this function, the vector's size will be reduced by one. The memory occupied by the removed element will not be freed automatically unless a destructor is set (in which case, the destructor will be called on the element being removed if it is set). Use vector_take_at() to retrieve the element at the specified index, remove it from the vector, and NOT call the destructor on it (hands ownership to the caller).
|
||||||
*/
|
*/
|
||||||
static inline int vector_pop_at(vector_t* vec, size_t index) {
|
static inline int vector_pop_at(vector_t* vec, size_t index) {
|
||||||
if (!vec || index >= vec->size) {
|
if (!vec || index >= vec->size) {
|
||||||
@@ -371,6 +380,53 @@ static inline int vector_pop_at(vector_t* vec, size_t index) {
|
|||||||
return 0; // Success
|
return 0; // Success
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
@brief Removes the element at the specified index and transfers ownership of it to the caller.
|
||||||
|
@param vec A pointer to the vector from which the element will be taken.
|
||||||
|
@param index The index of the element to take.
|
||||||
|
@param out A pointer to a buffer of at least vector_element_size(vec) bytes, which the element is copied into.
|
||||||
|
@return 0 on success, -1 if the vector is NULL, out is NULL, out points into the vector's own data, or the index is out of bounds.
|
||||||
|
@attention The element destructor is deliberately NOT called. Whatever the element owns becomes the caller's responsibility to free.
|
||||||
|
@attention out must not point into the vector's own data array. Doing so would leave two slots owning the same memory and is rejected with -1.
|
||||||
|
*/
|
||||||
|
static inline int vector_take_at(vector_t* vec, size_t index, void* out) {
|
||||||
|
if (!vec || index >= vec->size || !out) {
|
||||||
|
return -1; // Invalid vector, index out of bounds, or output pointer is NULL
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vector_is_aliased(vec, out)) {
|
||||||
|
return -1; // Refuse to take an element into a pointer that lives inside the vector
|
||||||
|
}
|
||||||
|
|
||||||
|
void* slot = (char*)vec->data + (index * vec->element_size);
|
||||||
|
memcpy(out, slot, vec->element_size); // Copy the element to the output pointer
|
||||||
|
|
||||||
|
// Move elements after the index one position to the left
|
||||||
|
if (index + 1 < vec->size) {
|
||||||
|
memmove(slot,
|
||||||
|
(char*)vec->data + ((index + 1) * vec->element_size),
|
||||||
|
(vec->size - index - 1) * vec->element_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec->size--;
|
||||||
|
return 0; // Success
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
@brief Removes the last element from the vector and transfers ownership of it to the caller.
|
||||||
|
@param vec A pointer to the vector from which the element will be taken.
|
||||||
|
@param out A pointer to a buffer of at least vector_element_size(vec) bytes, which the element is copied into.
|
||||||
|
@return 0 on success, -1 if the vector is NULL, empty, if out aliases the vector's data, or out is NULL.
|
||||||
|
@attention The element destructor is deliberately NOT called. Whatever the element owns becomes the caller's responsibility to free.
|
||||||
|
*/
|
||||||
|
static inline int vector_take_back(vector_t* vec, void* out) {
|
||||||
|
if (!vec || vec->size == 0 || !out) {
|
||||||
|
return -1; // Invalid vector, empty vector, or output pointer is NULL
|
||||||
|
}
|
||||||
|
|
||||||
|
return vector_take_at(vec, vec->size - 1, out); // Take the last element
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@brief Inserts an element at the specified index in the vector.
|
@brief Inserts an element at the specified index in the vector.
|
||||||
@param vec A pointer to the vector into which the element will be inserted.
|
@param vec A pointer to the vector into which the element will be inserted.
|
||||||
|
|||||||
Reference in New Issue
Block a user