vita-toolchain

git clone https://git.neptards.moe/neptards/vita-toolchain.git
Log | Files | Refs | README | LICENSE

varray.c (5125B)


      1 #include <stdlib.h>
      2 #include <string.h>
      3 
      4 #include "varray.h"
      5 
      6 #define _IDX(index) VARRAY_ELEMENT(va, index)
      7 
      8 varray *varray_new(int element_size, int initial_allocation)
      9 {
     10 	varray *va;
     11 
     12 	va = malloc(sizeof(varray));
     13 	if (va == NULL)
     14 		return NULL;
     15 
     16 	if (varray_init(va, element_size, initial_allocation) == NULL) {
     17 		free(va);
     18 		return NULL;
     19 	}
     20 
     21 	return va;
     22 }
     23 
     24 varray *varray_init(varray *va, int element_size, int initial_allocation)
     25 {
     26 	memset(va, 0, sizeof(varray));
     27 	va->element_size = element_size;
     28 	va->allocation = initial_allocation;
     29 
     30 	if (initial_allocation) {
     31 		va->data = calloc(initial_allocation + 1, element_size);
     32 		if (va->data == NULL) {
     33 			return NULL;
     34 		}
     35 	}
     36 
     37 	return va;
     38 }
     39 
     40 void varray_destroy(varray *va)
     41 {
     42 	int i;
     43 
     44 	if (va->destroy_func != NULL) {
     45 		for (i = 0; i < va->count; i++) {
     46 			va->destroy_func(_IDX(i));
     47 		}
     48 	}
     49 	free(va->data);
     50 	memset(va, 0, sizeof(varray));
     51 }
     52 
     53 void varray_free(varray *va)
     54 {
     55 	if (va == NULL)
     56 		return;
     57 
     58 	varray_destroy(va);
     59 	free(va);
     60 }
     61 
     62 void *varray_extract_array(varray *va)
     63 {
     64 	void *array;
     65 
     66 	if (va->count == 0) {
     67 		varray_destroy(va);
     68 		return NULL;
     69 	}
     70 
     71 	array = realloc(va->data, va->count * va->element_size);
     72 	memset(va, 0, sizeof(varray));
     73 	return array;
     74 }
     75 
     76 int varray_get_index(varray *va, void *element_ptr)
     77 {
     78 	if (va->data == NULL)
     79 		return -1;
     80 
     81 	if (element_ptr < va->data || element_ptr >= _IDX(va->count))
     82 		return -1;
     83 
     84 	if ((element_ptr - va->data) % va->element_size != 0)
     85 		return -1;
     86 
     87 	return (element_ptr - va->data) / va->element_size;
     88 }
     89 
     90 static int grow_array(varray *va)
     91 {
     92 	int new_allocation;
     93 	void *new_data;
     94 
     95 	if (va->allocation == 0)
     96 		new_allocation = 16;
     97 	else
     98 		new_allocation = va->allocation * 2;
     99 
    100 	new_data = realloc(va->data, va->element_size * (new_allocation + 1));
    101 	if (new_data == NULL)
    102 		return 0;
    103 
    104 	va->data = new_data;
    105 	va->allocation = new_allocation;
    106 	return 1;
    107 }
    108 #define GROW_IF_NECESSARY(va, failure_retval) do { \
    109 	if ((va)->count >= (va)->allocation) { \
    110 		if (!grow_array(va)) \
    111 			return (failure_retval); \
    112 	} \
    113 } while (0)
    114 
    115 void *varray_push(varray *va, void *element)
    116 {
    117 	GROW_IF_NECESSARY(va, NULL);
    118 	if (element == NULL) {
    119 		memset(_IDX(va->count), 0, va->element_size);
    120 		if (va->init_func) {
    121 			if (va->init_func(_IDX(va->count)) == NULL)
    122 				return NULL;
    123 		}
    124 	} else {
    125 		memcpy(_IDX(va->count), element, va->element_size);
    126 	}
    127 	va->count++;
    128 
    129 	return _IDX(va->count - 1);
    130 }
    131 
    132 void *varray_insert(varray *va, void *element, int index)
    133 {
    134 	if (index > va->count || index < 0)
    135 		return NULL;
    136 
    137 	GROW_IF_NECESSARY(va, NULL);
    138 	if (index < va->count) {
    139 		memmove(_IDX(index + 1), _IDX(index), va->element_size * (va->count - index));
    140 	}
    141 
    142 	if (element == NULL) {
    143 		memset(_IDX(index), 0, va->element_size);
    144 		if (va->init_func) {
    145 			if (va->init_func(_IDX(index)) == NULL) {
    146 				varray_remove(va, index);
    147 				return NULL;
    148 			}
    149 		}
    150 	} else {
    151 		memcpy(_IDX(index), element, va->element_size);
    152 	}
    153 
    154 	va->count++;
    155 	return _IDX(index);
    156 }
    157 
    158 void *varray_pop(varray *va)
    159 {
    160 	if (va->count == 0)
    161 		return NULL;
    162 
    163 	va->count--;
    164 	return _IDX(va->count);
    165 }
    166 
    167 void *varray_remove(varray *va, int index)
    168 {
    169 	if (index >= va->count || index < 0)
    170 		return NULL;
    171 
    172 	if (index == va->count - 1)
    173 		return varray_pop(va);
    174 
    175 	memcpy(_IDX(va->allocation), _IDX(index), va->element_size);
    176 	memmove(_IDX(index), _IDX(index + 1), va->element_size * (va->count - index));
    177 	va->count--;
    178 
    179 	memcpy(_IDX(va->count), _IDX(va->allocation), va->element_size);
    180 	return _IDX(va->count);
    181 }
    182 
    183 void varray_sort(varray *va)
    184 {
    185 	qsort(va->data, va->count, va->element_size, va->sort_compar);
    186 }
    187 
    188 
    189 void *varray_sorted_search(const varray *va, const void *key)
    190 {
    191 	return bsearch(key, va->data, va->count, va->element_size, va->search_compar ? va->search_compar : va->sort_compar);
    192 }
    193 
    194 static int get_sorted_insert_index(const varray *va, const void *key_or_element, int (*compar)(const void *, const void *))
    195 {
    196 	int low_idx = 0, high_idx = va->count;
    197 
    198 	while (low_idx < high_idx) {
    199 		int test_idx = (low_idx + high_idx) / 2;
    200 		int result = compar(key_or_element, _IDX(test_idx));
    201 
    202 		if (result == 0)
    203 			return test_idx;
    204 		else if (result > 0)
    205 			low_idx = test_idx + 1;
    206 		else
    207 			high_idx = test_idx;
    208 	}
    209 
    210 	return low_idx;
    211 }
    212 
    213 void *varray_sorted_insert_ex(varray *va, void *element, int allow_dup)
    214 {
    215 	int insert_idx = get_sorted_insert_index(va, element, va->sort_compar);
    216 
    217 	if (!allow_dup && insert_idx < va->count && va->search_compar(element, _IDX(insert_idx)) == 0)
    218 		return NULL;
    219 
    220 	return varray_insert(va, element, insert_idx);
    221 }
    222 
    223 void *varray_sorted_insert(varray *va, void *element)
    224 {
    225 	return varray_sorted_insert_ex(va, element, 1);
    226 }
    227 
    228 void *varray_sorted_search_or_insert(varray *va, const void *key, int *found_existing)
    229 {
    230 	int (*compar)(const void *, const void *);
    231 	int insert_idx;
    232 
    233 	compar = va->search_compar ? va->search_compar : va->sort_compar;
    234 
    235 	insert_idx = get_sorted_insert_index(va, key, compar);
    236 
    237 	if (insert_idx < va->count && compar(key, _IDX(insert_idx)) == 0) {
    238 		if (found_existing != NULL)
    239 			*found_existing = 1;
    240 		return _IDX(insert_idx);
    241 	} else {
    242 		if (found_existing != NULL)
    243 			*found_existing = 0;
    244 		return varray_insert(va, NULL, insert_idx);
    245 	}
    246 }