vec.c 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. /** @file vec.c
  2. * Implementation of variable length vector of arbitrary structures.
  3. */
  4. #include <stdlib.h>
  5. #include <string.h>
  6. #include <assert.h>
  7. #include <ctype.h>
  8. #include <stdio.h>
  9. #include "private.h"
  10. /** @brief Allocates and initalizes new vector.
  11. *
  12. * Callback function matchFn can be used later to find item by user specified
  13. * key. Function can compare key and item's data.
  14. *
  15. * @param [in] item_size Size of single vector's item.
  16. * @param [in] matchFn Callback function to compare user key and item's data.
  17. * @return Allocated and initialized vector or NULL on error.
  18. */
  19. faux_vec_t *faux_vec_new(size_t item_size, faux_vec_kcmp_fn matchFn)
  20. {
  21. faux_vec_t *faux_vec = NULL;
  22. faux_vec = faux_zmalloc(sizeof(*faux_vec));
  23. assert(faux_vec);
  24. if (!faux_vec)
  25. return NULL;
  26. if (0 == item_size)
  27. return NULL;
  28. // Init
  29. faux_vec->data = NULL;
  30. faux_vec->item_size = item_size;
  31. faux_vec->len = 0;
  32. faux_vec->kcmpFn = matchFn;
  33. return faux_vec;
  34. }
  35. /** @brief Frees previously allocated vector object.
  36. *
  37. * @param [in] faux_vec Allocated vector object.
  38. */
  39. void faux_vec_free(faux_vec_t *faux_vec)
  40. {
  41. if (!faux_vec)
  42. return;
  43. faux_free(faux_vec->data);
  44. faux_free(faux_vec);
  45. }
  46. /** @brief Gets vector length in items.
  47. *
  48. * @param [in] faux_vec Allocated vector object.
  49. * @return Number of items.
  50. */
  51. size_t faux_vec_len(const faux_vec_t *faux_vec)
  52. {
  53. assert(faux_vec);
  54. if (!faux_vec)
  55. return 0;
  56. return faux_vec->len;
  57. }
  58. /** @brief Gets size of item.
  59. *
  60. * @param [in] faux_vec Allocated vector object.
  61. * @return Size of item in bytes.
  62. */
  63. size_t faux_vec_item_size(const faux_vec_t *faux_vec)
  64. {
  65. assert(faux_vec);
  66. if (!faux_vec)
  67. return 0;
  68. return faux_vec->item_size;
  69. }
  70. /** @brief Gets item by index.
  71. *
  72. * Gets pointer to item's data.
  73. *
  74. * @param [in] faux_vec Allocated vector object.
  75. * @return Pointer to item or NULL on error.
  76. */
  77. void *faux_vec_item(const faux_vec_t *faux_vec, unsigned int index)
  78. {
  79. assert(faux_vec);
  80. if (!faux_vec)
  81. return NULL;
  82. if ((index + 1) > faux_vec_len(faux_vec))
  83. return NULL;
  84. return (char *)faux_vec->data + index * faux_vec_item_size(faux_vec);
  85. }
  86. /** @brief Gets pointer to whole vector.
  87. *
  88. * @param [in] faux_vec Allocated vector object.
  89. * @return Pointer to vector or NULL on error.
  90. */
  91. void *faux_vec_data(const faux_vec_t *faux_vec)
  92. {
  93. assert(faux_vec);
  94. if (!faux_vec)
  95. return NULL;
  96. return faux_vec->data;
  97. }
  98. /** @brief Adds item to vector and gets pointer to newly created item.
  99. *
  100. * @param [in] faux_vec Allocated vector object.
  101. * @return Newly created item or NULL on error.
  102. */
  103. void *faux_vec_add(faux_vec_t *faux_vec)
  104. {
  105. void *new_vector = NULL;
  106. size_t new_data_len = 0;
  107. void *new_item = NULL;
  108. assert(faux_vec);
  109. if (!faux_vec)
  110. return NULL;
  111. // Allocate space to hold new vector
  112. new_data_len = (faux_vec_len(faux_vec) + 1) * faux_vec_item_size(faux_vec);
  113. new_vector = realloc(faux_vec->data, new_data_len);
  114. assert(new_vector);
  115. if (!new_vector)
  116. return NULL;
  117. faux_vec->len++;
  118. faux_vec->data = new_vector;
  119. // Newly created item (it's last one)
  120. new_item = faux_vec_item(faux_vec, faux_vec_len(faux_vec) - 1);
  121. faux_bzero(new_item, faux_vec_item_size(faux_vec));
  122. return new_item;
  123. }
  124. /** @brief Removes item from vector by index.
  125. *
  126. * Function removes item by index and then fill hole with the following items.
  127. * It saves items sequence and frees vector memory.
  128. *
  129. * @param [in] faux_vec Allocated vector object.
  130. * @param [in] index Index of item to remove.
  131. * @return New number of items within vector after removing or < 0 on error.
  132. */
  133. ssize_t faux_vec_del(faux_vec_t *faux_vec, unsigned int index)
  134. {
  135. void *new_vector = NULL;
  136. size_t new_data_len = 0;
  137. assert(faux_vec);
  138. if (!faux_vec)
  139. return -1;
  140. if ((index + 1) > faux_vec_len(faux_vec))
  141. return -1;
  142. // It's special case when the only one item left within vector. In this
  143. // case we don't need to realloc() but free() the vector.
  144. if (faux_vec_len(faux_vec) == 1) {
  145. free(faux_vec->data);
  146. faux_vec->data = NULL;
  147. faux_vec->len = 0;
  148. return 0;
  149. }
  150. // Move following items to fill the space of deleted item
  151. if (index != (faux_vec_len(faux_vec) - 1)) { // Is it last item?
  152. void *item_to_del = faux_vec_item(faux_vec, index);
  153. void *next_item = faux_vec_item(faux_vec, index + 1);
  154. unsigned int items_to_move =
  155. faux_vec_len(faux_vec) - (index + 1);
  156. memmove(item_to_del, next_item,
  157. items_to_move * faux_vec_item_size(faux_vec));
  158. }
  159. // Re-allocate space to hold new vector
  160. faux_vec->len--;
  161. new_data_len = faux_vec_len(faux_vec) * faux_vec_item_size(faux_vec);
  162. new_vector = realloc(faux_vec->data, new_data_len);
  163. assert(new_vector);
  164. if (!new_vector)
  165. return -1;
  166. faux_vec->data = new_vector;
  167. return faux_vec_len(faux_vec);
  168. }
  169. /** @brief Finds item by user defined key using specified callback function.
  170. *
  171. * It iterates through the vector and try to find item with the specified key
  172. * value. It starts searching with specified item index and returns index of
  173. * found item. So it can be used to iterate all the vector with duplicate keys.
  174. *
  175. * @param [in] faux_vec Allocated vector object.
  176. * @param [in] matchFn Callback function to compare user key and item's data.
  177. * @param [in] userkey User defined key to compare item to.
  178. * @param [in] start_index Item's index to start searching from.
  179. * @return Index of found item or < 0 on error or "not found" case.
  180. */
  181. int faux_vec_find_fn(const faux_vec_t *faux_vec, faux_vec_kcmp_fn matchFn,
  182. const void *userkey, unsigned int start_index)
  183. {
  184. unsigned int i = 0;
  185. assert(faux_vec);
  186. if (!faux_vec)
  187. return -1;
  188. assert(userkey);
  189. if (!userkey)
  190. return -1;
  191. assert(matchFn);
  192. if (!matchFn)
  193. return -1;
  194. for (i = start_index; i < faux_vec_len(faux_vec); i++) {
  195. if (matchFn(userkey, faux_vec_item(faux_vec, i)) == 0)
  196. return i;
  197. }
  198. return -1;
  199. }
  200. /** @brief Finds item by user defined key.
  201. *
  202. * It acts like a faux_vec_find_fn() function but uses callback function
  203. * specified while faux_vec_new() call.
  204. *
  205. * @sa faux_vec_find_fn()
  206. * @sa faux_vec_new()
  207. * @param [in] faux_vec Allocated vector object.
  208. * @param [in] userkey User defined key to compare item to.
  209. * @param [in] start_index Item's index to start searching from.
  210. * @return Index of found item or < 0 on error or "not found" case.
  211. */
  212. int faux_vec_find(const faux_vec_t *faux_vec, const void *userkey,
  213. unsigned int start_index)
  214. {
  215. assert(faux_vec);
  216. if (!faux_vec)
  217. return -1;
  218. assert(faux_vec->kcmpFn);
  219. if (!faux_vec->kcmpFn)
  220. return -1;
  221. return faux_vec_find_fn(faux_vec, faux_vec->kcmpFn,
  222. userkey, start_index);
  223. }
  224. /** @brief Deletes all vector's items.
  225. *
  226. * @param [in] faux_vec Allocated vector object.
  227. */
  228. void faux_vec_del_all(faux_vec_t *faux_vec)
  229. {
  230. if (!faux_vec)
  231. return;
  232. faux_free(faux_vec->data);
  233. faux_vec->data = NULL;
  234. faux_vec->len = 0;
  235. }