mirror of
https://github.com/Rockbox/rockbox.git
synced 2025-11-09 05:02:33 -05:00
This commit adds new files written exclusively for the 3ds port. Additional comments: 1. Plugins works, but will be enabled in future commits. 2. The port has only been tested on the New 3DS. 3. Not all features of rockbox have been tested so there may be bugs or non-functional features. 4. There is a known issue where a random crash can occur when exiting the app. Change-Id: I122d0bea9aa604e04fca45ba8287cf79e6110769
549 lines
24 KiB
C
549 lines
24 KiB
C
#ifndef CVECTOR_H_
|
|
#define CVECTOR_H_
|
|
/**
|
|
* @copyright Copyright (c) 2015 Evan Teran,
|
|
* License: The MIT License (MIT)
|
|
* @brief cvector heap implemented using C library malloc()
|
|
* @file cvector.h
|
|
*/
|
|
|
|
/* in case C library malloc() needs extra protection,
|
|
* allow these defines to be overridden.
|
|
*/
|
|
/* functions for allocation and deallocation need to correspond to each other, fall back to C library functions if not all are overridden */
|
|
#if !defined(cvector_clib_free) || !defined(cvector_clib_malloc) || !defined(cvector_clib_calloc) || !defined(cvector_clib_realloc)
|
|
#ifdef cvector_clib_free
|
|
#undef cvector_clib_free
|
|
#endif
|
|
#ifdef cvector_clib_malloc
|
|
#undef cvector_clib_malloc
|
|
#endif
|
|
#ifdef cvector_clib_calloc
|
|
#undef cvector_clib_calloc
|
|
#endif
|
|
#ifdef cvector_clib_realloc
|
|
#undef cvector_clib_realloc
|
|
#endif
|
|
#include <stdlib.h>
|
|
#define cvector_clib_free free
|
|
#define cvector_clib_malloc malloc
|
|
#define cvector_clib_calloc calloc
|
|
#define cvector_clib_realloc realloc
|
|
#endif
|
|
/* functions independent of memory allocation */
|
|
#ifndef cvector_clib_assert
|
|
#include <assert.h> /* for assert */
|
|
#define cvector_clib_assert assert
|
|
#endif
|
|
#ifndef cvector_clib_memcpy
|
|
#include <string.h> /* for memcpy */
|
|
#define cvector_clib_memcpy memcpy
|
|
#endif
|
|
#ifndef cvector_clib_memmove
|
|
#include <string.h> /* for memmove */
|
|
#define cvector_clib_memmove memmove
|
|
#endif
|
|
|
|
/* NOTE: Similar to C's qsort and bsearch, you will receive a T*
|
|
* for a vector of Ts. This means that you cannot use `free` directly
|
|
* as a destructor. Instead if you have for example a cvector_vector_type(int *)
|
|
* you will need to supply a function which casts `elem_ptr` to an `int**`
|
|
* and then does a free on what that pointer points to:
|
|
*
|
|
* ex:
|
|
*
|
|
* void free_int(void *p) { free(*(int **)p); }
|
|
*/
|
|
typedef void (*cvector_elem_destructor_t)(void *elem_ptr);
|
|
|
|
typedef struct cvector_metadata_t {
|
|
size_t size;
|
|
size_t capacity;
|
|
cvector_elem_destructor_t elem_destructor;
|
|
} cvector_metadata_t;
|
|
|
|
/**
|
|
* @brief cvector_vector_type - The vector type used in this library
|
|
* @param type The type of vector to act on.
|
|
*/
|
|
#define cvector_vector_type(type) type *
|
|
|
|
/**
|
|
* @brief cvector - Syntactic sugar to retrieve a vector type
|
|
* @param type The type of vector to act on.
|
|
*/
|
|
#define cvector(type) cvector_vector_type(type)
|
|
|
|
/**
|
|
* @brief cvector_iterator - The iterator type used for cvector
|
|
* @param type The type of iterator to act on.
|
|
*/
|
|
#define cvector_iterator(type) cvector_vector_type(type)
|
|
|
|
/**
|
|
* @note you can also safely pass a pointer to a cvector iterator to a function
|
|
* but you have to update the pointer at the end to update the original
|
|
* iterator.
|
|
* example:
|
|
* void function( cvector_vector_type( type ) * p_it )
|
|
* {
|
|
* cvector_vector_type( type ) it = *p_it;
|
|
* it ++;
|
|
*
|
|
* ...
|
|
*
|
|
* *p_it = it;
|
|
* }
|
|
*/
|
|
|
|
/**
|
|
* @brief cvector_vector_type_ptr - helper to make code more "readable"
|
|
* @param type - the vector type pointer
|
|
*/
|
|
#define cvector_ptr_type(type) \
|
|
cvector_vector_type(type) *
|
|
|
|
/**
|
|
* @brief cvector_vector_ptr_get_iterator/set - helpers to make code more "readable"
|
|
* @param it - the vector iterator
|
|
* @param ptr - the vector pointer
|
|
*/
|
|
#define cvector_ptr_get_iterator(ptr) \
|
|
*(ptr)
|
|
|
|
#define cvector_ptr_set(ptr, it) \
|
|
*(ptr) = it
|
|
|
|
/**
|
|
* @brief cvector_vector_container_declare - defined a vector container type
|
|
*/
|
|
#define cvector_vector_container_declare(name, type) \
|
|
struct cvector_vector_container_##name { \
|
|
cvector_vector_type(type) vector; \
|
|
}
|
|
|
|
/**
|
|
* @brief cvector_vector_container - used to pass a cvector wrapped inside a container as a function parameter
|
|
*/
|
|
#define cvector_vector_container(name) \
|
|
struct cvector_vector_container_##name
|
|
|
|
|
|
/**
|
|
* @brief cvector_vec_to_base - For internal use, converts a vector pointer to a metadata pointer
|
|
* @param vec - the vector
|
|
* @return the metadata pointer of the vector
|
|
* @internal
|
|
*/
|
|
#define cvector_vec_to_base(vec) \
|
|
(&((cvector_metadata_t *)(void *)(vec))[-1])
|
|
|
|
/**
|
|
* @brief cvector_base_to_vec - For internal use, converts a metadata pointer to a vector pointer
|
|
* @param ptr - pointer to the metadata
|
|
* @return the vector
|
|
* @internal
|
|
*/
|
|
#define cvector_base_to_vec(ptr) \
|
|
((void *)&((cvector_metadata_t *)(ptr))[1])
|
|
|
|
/**
|
|
* @brief cvector_capacity - gets the current capacity of the vector
|
|
* @param vec - the vector
|
|
* @return the capacity as a size_t
|
|
*/
|
|
#define cvector_capacity(vec) \
|
|
((vec) ? cvector_vec_to_base(vec)->capacity : (size_t)0)
|
|
|
|
/**
|
|
* @brief cvector_size - gets the current size of the vector
|
|
* @param vec - the vector
|
|
* @return the size as a size_t
|
|
*/
|
|
#define cvector_size(vec) \
|
|
((vec) ? cvector_vec_to_base(vec)->size : (size_t)0)
|
|
|
|
/**
|
|
* @brief cvector_elem_destructor - get the element destructor function used
|
|
* to clean up elements
|
|
* @param vec - the vector
|
|
* @return the function pointer as cvector_elem_destructor_t
|
|
*/
|
|
#define cvector_elem_destructor(vec) \
|
|
((vec) ? cvector_vec_to_base(vec)->elem_destructor : NULL)
|
|
|
|
/**
|
|
* @brief cvector_empty - returns non-zero if the vector is empty
|
|
* @param vec - the vector
|
|
* @return non-zero if empty, zero if non-empty
|
|
*/
|
|
#define cvector_empty(vec) \
|
|
(cvector_size(vec) == 0)
|
|
|
|
/**
|
|
* @brief cvector_reserve - Requests that the vector capacity be at least enough
|
|
* to contain n elements. If n is greater than the current vector capacity, the
|
|
* function causes the container to reallocate its storage increasing its
|
|
* capacity to n (or greater).
|
|
* @param vec - the vector
|
|
* @param n - Minimum capacity for the vector.
|
|
* @return void
|
|
*/
|
|
#define cvector_reserve(vec, n) \
|
|
do { \
|
|
size_t cv_reserve_cap__ = cvector_capacity(vec); \
|
|
if (cv_reserve_cap__ < (n)) { \
|
|
cvector_grow((vec), (n)); \
|
|
} \
|
|
} while (0)
|
|
|
|
/**
|
|
* @brief cvector_init - Initialize a vector. The vector must be NULL for this to do anything.
|
|
* @param vec - the vector
|
|
* @param capacity - vector capacity to reserve
|
|
* @param elem_destructor_fn - element destructor function
|
|
* @return void
|
|
*/
|
|
#define cvector_init(vec, capacity, elem_destructor_fn) \
|
|
do { \
|
|
if (!(vec)) { \
|
|
cvector_reserve((vec), capacity); \
|
|
cvector_set_elem_destructor((vec), (elem_destructor_fn)); \
|
|
} \
|
|
} while (0)
|
|
|
|
/**
|
|
* @brief cvector_init_default - Initialize a vector with default value. The vector must be NULL for this to do anything. Does NOT work for struct types.
|
|
* @param vec - the vector
|
|
* @param capacity - vector capacity to reserve
|
|
* @param elem_destructor_fn - element destructor function
|
|
* @return void
|
|
*/
|
|
#define cvector_init_default(vec, capacity, default) \
|
|
do { \
|
|
if (!(vec)) { \
|
|
cvector_reserve((vec), capacity); \
|
|
cvector_set_elem_destructor((vec), (elem_destructor_fn)); \
|
|
} \
|
|
} while (0)
|
|
|
|
/**
|
|
* @brief cvector_erase - removes the element at index i from the vector
|
|
* @param vec - the vector
|
|
* @param i - index of element to remove
|
|
* @return void
|
|
*/
|
|
#define cvector_erase(vec, i) \
|
|
do { \
|
|
if (vec) { \
|
|
const size_t cv_erase_sz__ = cvector_size(vec); \
|
|
if ((i) < cv_erase_sz__) { \
|
|
cvector_elem_destructor_t cv_erase_elem_dtor__ = cvector_elem_destructor(vec); \
|
|
if (cv_erase_elem_dtor__) { \
|
|
cv_erase_elem_dtor__(&(vec)[i]); \
|
|
} \
|
|
cvector_set_size((vec), cv_erase_sz__ - 1); \
|
|
cvector_clib_memmove( \
|
|
(vec) + (i), \
|
|
(vec) + (i) + 1, \
|
|
sizeof(*(vec)) * (cv_erase_sz__ - 1 - (i))); \
|
|
} \
|
|
} \
|
|
} while (0)
|
|
|
|
/**
|
|
* @brief cvector_clear - erase all of the elements in the vector
|
|
* @param vec - the vector
|
|
* @return void
|
|
*/
|
|
#define cvector_clear(vec) \
|
|
do { \
|
|
if (vec) { \
|
|
cvector_elem_destructor_t cv_clear_elem_dtor__ = cvector_elem_destructor(vec); \
|
|
if (cv_clear_elem_dtor__) { \
|
|
size_t cv_clear_i__; \
|
|
for (cv_clear_i__ = 0; cv_clear_i__ < cvector_size(vec); ++cv_clear_i__) { \
|
|
cv_clear_elem_dtor__(&(vec)[cv_clear_i__]); \
|
|
} \
|
|
} \
|
|
cvector_set_size(vec, 0); \
|
|
} \
|
|
} while (0)
|
|
|
|
/**
|
|
* @brief cvector_free - frees all memory associated with the vector
|
|
* @param vec - the vector
|
|
* @return void
|
|
*/
|
|
#define cvector_free(vec) \
|
|
do { \
|
|
if (vec) { \
|
|
void *cv_free_p__ = cvector_vec_to_base(vec); \
|
|
cvector_elem_destructor_t cv_free_elem_dtor__ = cvector_elem_destructor(vec); \
|
|
if (cv_free_elem_dtor__) { \
|
|
size_t cv_free_i__; \
|
|
for (cv_free_i__ = 0; cv_free_i__ < cvector_size(vec); ++cv_free_i__) { \
|
|
cv_free_elem_dtor__(&(vec)[cv_free_i__]); \
|
|
} \
|
|
} \
|
|
cvector_clib_free(cv_free_p__); \
|
|
} \
|
|
} while (0)
|
|
|
|
/**
|
|
* @brief cvector_begin - returns an iterator to first element of the vector
|
|
* @param vec - the vector
|
|
* @return a pointer to the first element (or NULL)
|
|
*/
|
|
#define cvector_begin(vec) \
|
|
(vec)
|
|
|
|
/**
|
|
* @brief cvector_end - returns an iterator to one past the last element of the vector
|
|
* @param vec - the vector
|
|
* @return a pointer to one past the last element (or NULL)
|
|
*/
|
|
#define cvector_end(vec) \
|
|
((vec) ? &((vec)[cvector_size(vec)]) : NULL)
|
|
|
|
/* user request to use linear growth algorithm */
|
|
#ifdef CVECTOR_LINEAR_GROWTH
|
|
|
|
/**
|
|
* @brief cvector_compute_next_grow - returns an the computed size in next vector grow
|
|
* size is increased by 1
|
|
* @param size - current size
|
|
* @return size after next vector grow
|
|
*/
|
|
#define cvector_compute_next_grow(size) \
|
|
((size) + 1)
|
|
|
|
#else
|
|
|
|
/**
|
|
* @brief cvector_compute_next_grow - returns an the computed size in next vector grow
|
|
* size is increased by multiplication of 2
|
|
* @param size - current size
|
|
* @return size after next vector grow
|
|
*/
|
|
#define cvector_compute_next_grow(size) \
|
|
((size) ? ((size) << 1) : 1)
|
|
|
|
#endif /* CVECTOR_LINEAR_GROWTH */
|
|
|
|
/**
|
|
* @brief cvector_push_back - adds an element to the end of the vector
|
|
* @param vec - the vector
|
|
* @param value - the value to add
|
|
* @return void
|
|
*/
|
|
#define cvector_push_back(vec, value) \
|
|
do { \
|
|
size_t cv_push_back_cap__ = cvector_capacity(vec); \
|
|
if (cv_push_back_cap__ <= cvector_size(vec)) { \
|
|
cvector_grow((vec), cvector_compute_next_grow(cv_push_back_cap__)); \
|
|
} \
|
|
(vec)[cvector_size(vec)] = (value); \
|
|
cvector_set_size((vec), cvector_size(vec) + 1); \
|
|
} while (0)
|
|
|
|
/**
|
|
* @brief cvector_insert - insert element at position pos to the vector
|
|
* @param vec - the vector
|
|
* @param pos - position in the vector where the new elements are inserted.
|
|
* @param val - value to be copied (or moved) to the inserted elements.
|
|
* @return void
|
|
*/
|
|
#define cvector_insert(vec, pos, val) \
|
|
do { \
|
|
size_t cv_insert_cap__ = cvector_capacity(vec); \
|
|
if (cv_insert_cap__ <= cvector_size(vec)) { \
|
|
cvector_grow((vec), cvector_compute_next_grow(cv_insert_cap__)); \
|
|
} \
|
|
if ((pos) < cvector_size(vec)) { \
|
|
cvector_clib_memmove( \
|
|
(vec) + (pos) + 1, \
|
|
(vec) + (pos), \
|
|
sizeof(*(vec)) * ((cvector_size(vec)) - (pos))); \
|
|
} \
|
|
(vec)[(pos)] = (val); \
|
|
cvector_set_size((vec), cvector_size(vec) + 1); \
|
|
} while (0)
|
|
|
|
/**
|
|
* @brief cvector_pop_back - removes the last element from the vector
|
|
* @param vec - the vector
|
|
* @return void
|
|
*/
|
|
#define cvector_pop_back(vec) \
|
|
do { \
|
|
cvector_elem_destructor_t cv_pop_back_elem_dtor__ = cvector_elem_destructor(vec); \
|
|
if (cv_pop_back_elem_dtor__) { \
|
|
cv_pop_back_elem_dtor__(&(vec)[cvector_size(vec) - 1]); \
|
|
} \
|
|
cvector_set_size((vec), cvector_size(vec) - 1); \
|
|
} while (0)
|
|
|
|
/**
|
|
* @brief cvector_copy - copy a vector
|
|
* @param from - the original vector
|
|
* @param to - destination to which the function copy to
|
|
* @return void
|
|
*/
|
|
#define cvector_copy(from, to) \
|
|
do { \
|
|
if ((from)) { \
|
|
cvector_grow(to, cvector_size(from)); \
|
|
cvector_set_size(to, cvector_size(from)); \
|
|
cvector_clib_memcpy((to), (from), cvector_size(from) * sizeof(*(from))); \
|
|
} \
|
|
} while (0)
|
|
|
|
/**
|
|
* @brief cvector_swap - exchanges the content of the vector by the content of another vector of the same type
|
|
* @param vec - the original vector
|
|
* @param other - the other vector to swap content with
|
|
* @param type - the type of both vectors
|
|
* @return void
|
|
*/
|
|
#define cvector_swap(vec, other, type) \
|
|
do { \
|
|
if (vec && other) { \
|
|
cvector_vector_type(type) cv_swap__ = vec; \
|
|
vec = other; \
|
|
other = cv_swap__; \
|
|
} \
|
|
} while (0)
|
|
|
|
/**
|
|
* @brief cvector_set_capacity - For internal use, sets the capacity variable of the vector
|
|
* @param vec - the vector
|
|
* @param size - the new capacity to set
|
|
* @return void
|
|
* @internal
|
|
*/
|
|
#define cvector_set_capacity(vec, size) \
|
|
do { \
|
|
if (vec) { \
|
|
cvector_vec_to_base(vec)->capacity = (size); \
|
|
} \
|
|
} while (0)
|
|
|
|
/**
|
|
* @brief cvector_set_size - For internal use, sets the size variable of the vector
|
|
* @param vec - the vector
|
|
* @param _size - the new capacity to set
|
|
* @return void
|
|
* @internal
|
|
*/
|
|
#define cvector_set_size(vec, _size) \
|
|
do { \
|
|
if (vec) { \
|
|
cvector_vec_to_base(vec)->size = (_size); \
|
|
} \
|
|
} while (0)
|
|
|
|
/**
|
|
* @brief cvector_set_elem_destructor - set the element destructor function
|
|
* used to clean up removed elements. The vector must NOT be NULL for this to do anything.
|
|
* @param vec - the vector
|
|
* @param elem_destructor_fn - function pointer of type cvector_elem_destructor_t used to destroy elements
|
|
* @return void
|
|
*/
|
|
#define cvector_set_elem_destructor(vec, elem_destructor_fn) \
|
|
do { \
|
|
if (vec) { \
|
|
cvector_vec_to_base(vec)->elem_destructor = (elem_destructor_fn); \
|
|
} \
|
|
} while (0)
|
|
|
|
/**
|
|
* @brief cvector_grow - For internal use, ensures that the vector is at least `count` elements big
|
|
* @param vec - the vector
|
|
* @param count - the new capacity to set
|
|
* @return void
|
|
* @internal
|
|
*/
|
|
#define cvector_grow(vec, count) \
|
|
do { \
|
|
const size_t cv_grow_sz__ = (count) * sizeof(*(vec)) + sizeof(cvector_metadata_t); \
|
|
if (vec) { \
|
|
void *cv_grow_p1__ = cvector_vec_to_base(vec); \
|
|
void *cv_grow_p2__ = cvector_clib_realloc(cv_grow_p1__, cv_grow_sz__); \
|
|
cvector_clib_assert(cv_grow_p2__); \
|
|
(vec) = cvector_base_to_vec(cv_grow_p2__); \
|
|
} else { \
|
|
void *cv_grow_p__ = cvector_clib_malloc(cv_grow_sz__); \
|
|
cvector_clib_assert(cv_grow_p__); \
|
|
(vec) = cvector_base_to_vec(cv_grow_p__); \
|
|
cvector_set_size((vec), 0); \
|
|
cvector_set_elem_destructor((vec), NULL); \
|
|
} \
|
|
cvector_set_capacity((vec), (count)); \
|
|
} while (0)
|
|
|
|
/**
|
|
* @brief cvector_shrink_to_fit - requests the container to reduce its capacity to fit its size
|
|
* @param vec - the vector
|
|
* @return void
|
|
*/
|
|
#define cvector_shrink_to_fit(vec) \
|
|
do { \
|
|
if (vec) { \
|
|
const size_t cv_shrink_to_fit_sz__ = cvector_size(vec); \
|
|
cvector_grow(vec, cv_shrink_to_fit_sz__); \
|
|
} \
|
|
} while (0)
|
|
|
|
/**
|
|
* @brief cvector_at - returns a reference to the element at position n in the vector.
|
|
* @param vec - the vector
|
|
* @param n - position of an element in the vector.
|
|
* @return the element at the specified position in the vector.
|
|
*/
|
|
#define cvector_at(vec, n) \
|
|
((vec) ? (((int)(n) < 0 || (size_t)(n) >= cvector_size(vec)) ? NULL : &(vec)[n]) : NULL)
|
|
|
|
/**
|
|
* @brief cvector_front - returns a reference to the first element in the vector. Unlike member cvector_begin, which returns an iterator to this same element, this function returns a direct reference.
|
|
* @param vec - the vector
|
|
* @return a reference to the first element in the vector container.
|
|
*/
|
|
#define cvector_front(vec) \
|
|
((vec) ? ((cvector_size(vec) > 0) ? cvector_at(vec, 0) : NULL) : NULL)
|
|
|
|
/**
|
|
* @brief cvector_back - returns a reference to the last element in the vector.Unlike member cvector_end, which returns an iterator just past this element, this function returns a direct reference.
|
|
* @param vec - the vector
|
|
* @return a reference to the last element in the vector.
|
|
*/
|
|
#define cvector_back(vec) \
|
|
((vec) ? ((cvector_size(vec) > 0) ? cvector_at(vec, cvector_size(vec) - 1) : NULL) : NULL)
|
|
|
|
/**
|
|
* @brief cvector_resize - resizes the container to contain count elements.
|
|
* @param vec - the vector
|
|
* @param count - new size of the vector
|
|
* @param value - the value to initialize new elements with
|
|
* @return void
|
|
*/
|
|
#define cvector_resize(vec, count, value) \
|
|
do { \
|
|
if (vec) { \
|
|
size_t cv_resize_count__ = (size_t)(count); \
|
|
size_t cv_resize_sz__ = cvector_vec_to_base(vec)->size; \
|
|
if (cv_resize_count__ > cv_resize_sz__) { \
|
|
cvector_reserve((vec), cv_resize_count__); \
|
|
cvector_set_size((vec), cv_resize_count__); \
|
|
do { \
|
|
(vec)[cv_resize_sz__++] = (value); \
|
|
} while (cv_resize_sz__ < cv_resize_count__); \
|
|
} else { \
|
|
while (cv_resize_count__ < cv_resize_sz__--) { \
|
|
cvector_pop_back(vec); \
|
|
} \
|
|
} \
|
|
} \
|
|
} while (0)
|
|
|
|
#endif /* CVECTOR_H_ */
|