You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

378 lines
10 KiB

10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
  1. /* -*- coding: utf-8 -*-
  2. * ----------------------------------------------------------------------
  3. * Copyright © 2011-2013, RedJack, LLC.
  4. * All rights reserved.
  5. *
  6. * Please see the COPYING file in this distribution for license details.
  7. * ----------------------------------------------------------------------
  8. */
  9. #include <assert.h>
  10. #include <stdlib.h>
  11. #include <string.h>
  12. #include "libcork/core/types.h"
  13. #include "libcork/ds/array.h"
  14. #include "libcork/helpers/errors.h"
  15. #ifndef CORK_ARRAY_DEBUG
  16. #define CORK_ARRAY_DEBUG 0
  17. #endif
  18. #if CORK_ARRAY_DEBUG
  19. #include <stdio.h>
  20. #define DEBUG(...) \
  21. do { \
  22. fprintf(stderr, __VA_ARGS__); \
  23. fprintf(stderr, "\n"); \
  24. } while (0)
  25. #else
  26. #define DEBUG(...) /* nothing */
  27. #endif
  28. /*-----------------------------------------------------------------------
  29. * Resizable arrays
  30. */
  31. struct cork_array_priv {
  32. size_t allocated_count;
  33. size_t allocated_size;
  34. size_t element_size;
  35. size_t initialized_count;
  36. void *user_data;
  37. cork_free_f free_user_data;
  38. cork_init_f init;
  39. cork_done_f done;
  40. cork_init_f reuse;
  41. cork_done_f remove;
  42. };
  43. void
  44. cork_raw_array_init(struct cork_raw_array *array, size_t element_size)
  45. {
  46. array->items = NULL;
  47. array->size = 0;
  48. array->priv = cork_new(struct cork_array_priv);
  49. array->priv->allocated_count = 0;
  50. array->priv->allocated_size = 0;
  51. array->priv->element_size = element_size;
  52. array->priv->initialized_count = 0;
  53. array->priv->user_data = NULL;
  54. array->priv->free_user_data = NULL;
  55. array->priv->init = NULL;
  56. array->priv->done = NULL;
  57. array->priv->reuse = NULL;
  58. array->priv->remove = NULL;
  59. }
  60. void
  61. cork_raw_array_done(struct cork_raw_array *array)
  62. {
  63. if (array->priv->done != NULL) {
  64. size_t i;
  65. char *element = array->items;
  66. for (i = 0; i < array->priv->initialized_count; i++) {
  67. array->priv->done(array->priv->user_data, element);
  68. element += array->priv->element_size;
  69. }
  70. }
  71. if (array->items != NULL) {
  72. cork_free(array->items, array->priv->allocated_size);
  73. }
  74. cork_free_user_data(array->priv);
  75. cork_delete(struct cork_array_priv, array->priv);
  76. }
  77. void
  78. cork_raw_array_set_callback_data(struct cork_raw_array *array,
  79. void *user_data, cork_free_f free_user_data)
  80. {
  81. array->priv->user_data = user_data;
  82. array->priv->free_user_data = free_user_data;
  83. }
  84. void
  85. cork_raw_array_set_init(struct cork_raw_array *array, cork_init_f init)
  86. {
  87. array->priv->init = init;
  88. }
  89. void
  90. cork_raw_array_set_done(struct cork_raw_array *array, cork_done_f done)
  91. {
  92. array->priv->done = done;
  93. }
  94. void
  95. cork_raw_array_set_reuse(struct cork_raw_array *array, cork_init_f reuse)
  96. {
  97. array->priv->reuse = reuse;
  98. }
  99. void
  100. cork_raw_array_set_remove(struct cork_raw_array *array, cork_done_f remove)
  101. {
  102. array->priv->remove = remove;
  103. }
  104. size_t
  105. cork_raw_array_element_size(const struct cork_raw_array *array)
  106. {
  107. return array->priv->element_size;
  108. }
  109. void
  110. cork_raw_array_clear(struct cork_raw_array *array)
  111. {
  112. if (array->priv->remove != NULL) {
  113. size_t i;
  114. char *element = array->items;
  115. for (i = 0; i < array->priv->initialized_count; i++) {
  116. array->priv->remove(array->priv->user_data, element);
  117. element += array->priv->element_size;
  118. }
  119. }
  120. array->size = 0;
  121. }
  122. void *
  123. cork_raw_array_elements(const struct cork_raw_array *array)
  124. {
  125. return array->items;
  126. }
  127. void *
  128. cork_raw_array_at(const struct cork_raw_array *array, size_t index)
  129. {
  130. return ((char *) array->items) + (array->priv->element_size * index);
  131. }
  132. size_t
  133. cork_raw_array_size(const struct cork_raw_array *array)
  134. {
  135. return array->size;
  136. }
  137. bool
  138. cork_raw_array_is_empty(const struct cork_raw_array *array)
  139. {
  140. return (array->size == 0);
  141. }
  142. void
  143. cork_raw_array_ensure_size(struct cork_raw_array *array, size_t desired_count)
  144. {
  145. size_t desired_size;
  146. DEBUG("--- Array %p: Ensure %zu %zu-byte elements",
  147. array, desired_count, array->priv->element_size);
  148. desired_size = desired_count * array->priv->element_size;
  149. if (desired_size > array->priv->allocated_size) {
  150. size_t new_count = array->priv->allocated_count * 2;
  151. size_t new_size = array->priv->allocated_size * 2;
  152. if (desired_size > new_size) {
  153. new_count = desired_count;
  154. new_size = desired_size;
  155. }
  156. DEBUG("--- Array %p: Reallocating %zu->%zu bytes",
  157. array, array->priv->allocated_size, new_size);
  158. array->items =
  159. cork_realloc(array->items, array->priv->allocated_size, new_size);
  160. array->priv->allocated_count = new_count;
  161. array->priv->allocated_size = new_size;
  162. }
  163. }
  164. void *
  165. cork_raw_array_append(struct cork_raw_array *array)
  166. {
  167. size_t index;
  168. void *element;
  169. index = array->size++;
  170. cork_raw_array_ensure_size(array, array->size);
  171. element = cork_raw_array_at(array, index);
  172. /* Call the init or reset callback, depending on whether this entry has been
  173. * initialized before. */
  174. /* Since we can currently only add elements by appending them one at a time,
  175. * then this entry is either already initialized, or is the first
  176. * uninitialized entry. */
  177. assert(index <= array->priv->initialized_count);
  178. if (index == array->priv->initialized_count) {
  179. /* This element has not been initialized yet. */
  180. array->priv->initialized_count++;
  181. if (array->priv->init != NULL) {
  182. array->priv->init(array->priv->user_data, element);
  183. }
  184. } else {
  185. /* This element has already been initialized. */
  186. if (array->priv->reuse != NULL) {
  187. array->priv->reuse(array->priv->user_data, element);
  188. }
  189. }
  190. return element;
  191. }
  192. int
  193. cork_raw_array_copy(struct cork_raw_array *dest,
  194. const struct cork_raw_array *src,
  195. cork_copy_f copy, void *user_data)
  196. {
  197. size_t i;
  198. size_t reuse_count;
  199. char *dest_element;
  200. DEBUG("--- Copying %zu elements (%zu bytes) from %p to %p",
  201. src->size, src->size * dest->priv->element_size, src, dest);
  202. assert(dest->priv->element_size == src->priv->element_size);
  203. cork_array_clear(dest);
  204. cork_array_ensure_size(dest, src->size);
  205. /* Initialize enough elements to hold the contents of src */
  206. reuse_count = dest->priv->initialized_count;
  207. if (src->size < reuse_count) {
  208. reuse_count = src->size;
  209. }
  210. dest_element = dest->items;
  211. if (dest->priv->reuse != NULL) {
  212. DEBUG(" Calling reuse on elements 0-%zu", reuse_count);
  213. for (i = 0; i < reuse_count; i++) {
  214. dest->priv->reuse(dest->priv->user_data, dest_element);
  215. dest_element += dest->priv->element_size;
  216. }
  217. } else {
  218. dest_element += reuse_count * dest->priv->element_size;
  219. }
  220. if (dest->priv->init != NULL) {
  221. DEBUG(" Calling init on elements %zu-%zu", reuse_count, src->size);
  222. for (i = reuse_count; i < src->size; i++) {
  223. dest->priv->init(dest->priv->user_data, dest_element);
  224. dest_element += dest->priv->element_size;
  225. }
  226. }
  227. if (src->size > dest->priv->initialized_count) {
  228. dest->priv->initialized_count = src->size;
  229. }
  230. /* If the caller provided a copy function, let it copy each element in turn.
  231. * Otherwise, bulk copy everything using memcpy. */
  232. if (copy == NULL) {
  233. memcpy(dest->items, src->items, src->size * dest->priv->element_size);
  234. } else {
  235. const char *src_element = src->items;
  236. dest_element = dest->items;
  237. for (i = 0; i < src->size; i++) {
  238. rii_check(copy(user_data, dest_element, src_element));
  239. dest_element += dest->priv->element_size;
  240. src_element += dest->priv->element_size;
  241. }
  242. }
  243. dest->size = src->size;
  244. return 0;
  245. }
  246. /*-----------------------------------------------------------------------
  247. * Pointer arrays
  248. */
  249. struct cork_pointer_array {
  250. cork_free_f free;
  251. };
  252. static void
  253. pointer__init(void *user_data, void *vvalue)
  254. {
  255. void **value = vvalue;
  256. *value = NULL;
  257. }
  258. static void
  259. pointer__done(void *user_data, void *vvalue)
  260. {
  261. struct cork_pointer_array *ptr_array = user_data;
  262. void **value = vvalue;
  263. if (*value != NULL) {
  264. ptr_array->free(*value);
  265. }
  266. }
  267. static void
  268. pointer__remove(void *user_data, void *vvalue)
  269. {
  270. struct cork_pointer_array *ptr_array = user_data;
  271. void **value = vvalue;
  272. if (*value != NULL) {
  273. ptr_array->free(*value);
  274. }
  275. *value = NULL;
  276. }
  277. static void
  278. pointer__free(void *user_data)
  279. {
  280. struct cork_pointer_array *ptr_array = user_data;
  281. cork_delete(struct cork_pointer_array, ptr_array);
  282. }
  283. void
  284. cork_raw_pointer_array_init(struct cork_raw_array *array, cork_free_f free_ptr)
  285. {
  286. struct cork_pointer_array *ptr_array = cork_new(struct cork_pointer_array);
  287. ptr_array->free = free_ptr;
  288. cork_raw_array_init(array, sizeof(void *));
  289. cork_array_set_callback_data(array, ptr_array, pointer__free);
  290. cork_array_set_init(array, pointer__init);
  291. cork_array_set_done(array, pointer__done);
  292. cork_array_set_remove(array, pointer__remove);
  293. }
  294. /*-----------------------------------------------------------------------
  295. * String arrays
  296. */
  297. void
  298. cork_string_array_init(struct cork_string_array *array)
  299. {
  300. cork_raw_pointer_array_init
  301. ((struct cork_raw_array *) array, (cork_free_f) cork_strfree);
  302. }
  303. void
  304. cork_string_array_append(struct cork_string_array *array, const char *str)
  305. {
  306. const char *copy = cork_strdup(str);
  307. cork_array_append(array, copy);
  308. }
  309. static int
  310. string__copy(void *user_data, void *vdest, const void *vsrc)
  311. {
  312. const char **dest = vdest;
  313. const char **src = (const char **) vsrc;
  314. *dest = cork_strdup(*src);
  315. return 0;
  316. }
  317. void
  318. cork_string_array_copy(struct cork_string_array *dest,
  319. const struct cork_string_array *src)
  320. {
  321. CORK_ATTR_UNUSED int rc;
  322. rc = cork_array_copy(dest, src, string__copy, NULL);
  323. /* cork_array_copy can only fail if the copy callback fails, and ours
  324. * doesn't! */
  325. assert(rc == 0);
  326. }