Research portable Memory game | Исследовать портируемую игру Память
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.

384 lines
13KB

  1. utarray: dynamic array macros for C
  2. ===================================
  3. Troy D. Hanson <tdh@tkhanson.net>
  4. v2.3.0, February 2021
  5. Here's a link back to the https://github.com/troydhanson/uthash[GitHub project page].
  6. Introduction
  7. ------------
  8. A set of general-purpose dynamic array macros for C structures are included with
  9. uthash in `utarray.h`. To use these macros in your own C program, just
  10. copy `utarray.h` into your source directory and use it in your programs.
  11. #include "utarray.h"
  12. The dynamic array supports basic operations such as push, pop, and erase on the
  13. array elements. These array elements can be any simple datatype or structure.
  14. The array <<operations,operations>> are based loosely on the C++ STL vector methods.
  15. Internally the dynamic array contains a contiguous memory region into which
  16. the elements are copied. This buffer is grown as needed using `realloc` to
  17. accommodate all the data that is pushed into it.
  18. Download
  19. ~~~~~~~~
  20. To download the `utarray.h` header file,
  21. follow the links on https://github.com/troydhanson/uthash to clone uthash or get a zip file,
  22. then look in the src/ sub-directory.
  23. BSD licensed
  24. ~~~~~~~~~~~~
  25. This software is made available under the
  26. link:license.html[revised BSD license].
  27. It is free and open source.
  28. Platforms
  29. ~~~~~~~~~
  30. The 'utarray' macros have been tested on:
  31. * Linux,
  32. * Mac OS X,
  33. * Windows, using Visual Studio 2008 and Visual Studio 2010
  34. Usage
  35. -----
  36. Declaration
  37. ~~~~~~~~~~~
  38. The array itself has the data type `UT_array`, regardless of the type of
  39. elements to be stored in it. It is declared like,
  40. UT_array *nums;
  41. New and free
  42. ~~~~~~~~~~~~
  43. The next step is to create the array using `utarray_new`. Later when you're
  44. done with the array, `utarray_free` will free it and all its elements.
  45. Push, pop, etc
  46. ~~~~~~~~~~~~~~
  47. The central features of the utarray involve putting elements into it, taking
  48. them out, and iterating over them. There are several <<operations,operations>>
  49. to pick from that deal with either single elements or ranges of elements at a
  50. time. In the examples below we will use only the push operation to insert
  51. elements.
  52. Elements
  53. --------
  54. Support for dynamic arrays of integers or strings is especially easy. These are
  55. best shown by example:
  56. Integers
  57. ~~~~~~~~
  58. This example makes a utarray of integers, pushes 0-9 into it, then prints it.
  59. Lastly it frees it.
  60. .Integer elements
  61. -------------------------------------------------------------------------------
  62. #include <stdio.h>
  63. #include "utarray.h"
  64. int main() {
  65. UT_array *nums;
  66. int i, *p;
  67. utarray_new(nums,&ut_int_icd);
  68. for(i=0; i < 10; i++) utarray_push_back(nums,&i);
  69. for(p=(int*)utarray_front(nums);
  70. p!=NULL;
  71. p=(int*)utarray_next(nums,p)) {
  72. printf("%d\n",*p);
  73. }
  74. utarray_free(nums);
  75. return 0;
  76. }
  77. -------------------------------------------------------------------------------
  78. The second argument to `utarray_push_back` is always a 'pointer' to the type
  79. (so a literal cannot be used). So for integers, it is an `int*`.
  80. Strings
  81. ~~~~~~~
  82. In this example we make a utarray of strings, push two strings into it, print
  83. it and free it.
  84. .String elements
  85. -------------------------------------------------------------------------------
  86. #include <stdio.h>
  87. #include "utarray.h"
  88. int main() {
  89. UT_array *strs;
  90. char *s, **p;
  91. utarray_new(strs,&ut_str_icd);
  92. s = "hello"; utarray_push_back(strs, &s);
  93. s = "world"; utarray_push_back(strs, &s);
  94. p = NULL;
  95. while ( (p=(char**)utarray_next(strs,p))) {
  96. printf("%s\n",*p);
  97. }
  98. utarray_free(strs);
  99. return 0;
  100. }
  101. -------------------------------------------------------------------------------
  102. In this example, since the element is a `char*`, we pass a pointer to it
  103. (`char**`) as the second argument to `utarray_push_back`. Note that "push" makes
  104. a copy of the source string and pushes that copy into the array.
  105. About UT_icd
  106. ~~~~~~~~~~~~
  107. Arrays be made of any type of element, not just integers and strings. The
  108. elements can be basic types or structures. Unless you're dealing with integers
  109. and strings (which use pre-defined `ut_int_icd` and `ut_str_icd`), you'll need
  110. to define a `UT_icd` helper structure. This structure contains everything that
  111. utarray needs to initialize, copy or destruct elements.
  112. typedef struct {
  113. size_t sz;
  114. init_f *init;
  115. ctor_f *copy;
  116. dtor_f *dtor;
  117. } UT_icd;
  118. The three function pointers `init`, `copy`, and `dtor` have these prototypes:
  119. typedef void (ctor_f)(void *dst, const void *src);
  120. typedef void (dtor_f)(void *elt);
  121. typedef void (init_f)(void *elt);
  122. The `sz` is just the size of the element being stored in the array.
  123. The `init` function will be invoked whenever utarray needs to initialize an
  124. empty element. This only happens as a byproduct of `utarray_resize` or
  125. `utarray_extend_back`. If `init` is `NULL`, it defaults to zero filling the
  126. new element using memset.
  127. The `copy` function is used whenever an element is copied into the array.
  128. It is invoked during `utarray_push_back`, `utarray_insert`, `utarray_inserta`,
  129. or `utarray_concat`. If `copy` is `NULL`, it defaults to a bitwise copy using
  130. memcpy.
  131. The `dtor` function is used to clean up an element that is being removed from
  132. the array. It may be invoked due to `utarray_resize`, `utarray_pop_back`,
  133. `utarray_erase`, `utarray_clear`, `utarray_done` or `utarray_free`. If the
  134. elements need no cleanup upon destruction, `dtor` may be `NULL`.
  135. Scalar types
  136. ~~~~~~~~~~~~
  137. The next example uses `UT_icd` with all its defaults to make a utarray of
  138. `long` elements. This example pushes two longs, prints them, and frees the
  139. array.
  140. .long elements
  141. -------------------------------------------------------------------------------
  142. #include <stdio.h>
  143. #include "utarray.h"
  144. UT_icd long_icd = {sizeof(long), NULL, NULL, NULL };
  145. int main() {
  146. UT_array *nums;
  147. long l, *p;
  148. utarray_new(nums, &long_icd);
  149. l=1; utarray_push_back(nums, &l);
  150. l=2; utarray_push_back(nums, &l);
  151. p=NULL;
  152. while( (p=(long*)utarray_next(nums,p))) printf("%ld\n", *p);
  153. utarray_free(nums);
  154. return 0;
  155. }
  156. -------------------------------------------------------------------------------
  157. Structures
  158. ~~~~~~~~~~
  159. Structures can be used as utarray elements. If the structure requires no
  160. special effort to initialize, copy or destruct, we can use `UT_icd` with all
  161. its defaults. This example shows a structure that consists of two integers. Here
  162. we push two values, print them and free the array.
  163. .Structure (simple)
  164. -------------------------------------------------------------------------------
  165. #include <stdio.h>
  166. #include "utarray.h"
  167. typedef struct {
  168. int a;
  169. int b;
  170. } intpair_t;
  171. UT_icd intpair_icd = {sizeof(intpair_t), NULL, NULL, NULL};
  172. int main() {
  173. UT_array *pairs;
  174. intpair_t ip, *p;
  175. utarray_new(pairs,&intpair_icd);
  176. ip.a=1; ip.b=2; utarray_push_back(pairs, &ip);
  177. ip.a=10; ip.b=20; utarray_push_back(pairs, &ip);
  178. for(p=(intpair_t*)utarray_front(pairs);
  179. p!=NULL;
  180. p=(intpair_t*)utarray_next(pairs,p)) {
  181. printf("%d %d\n", p->a, p->b);
  182. }
  183. utarray_free(pairs);
  184. return 0;
  185. }
  186. -------------------------------------------------------------------------------
  187. The real utility of `UT_icd` is apparent when the elements of the utarray are
  188. structures that require special work to initialize, copy or destruct.
  189. For example, when a structure contains pointers to related memory areas that
  190. need to be copied when the structure is copied (and freed when the structure is
  191. freed), we can use custom `init`, `copy`, and `dtor` members in the `UT_icd`.
  192. Here we take an example of a structure that contains an integer and a string.
  193. When this element is copied (such as when an element is pushed into the array),
  194. we want to "deep copy" the `s` pointer (so the original element and the new
  195. element point to their own copies of `s`). When an element is destructed, we
  196. want to "deep free" its copy of `s`. Lastly, this example is written to work
  197. even if `s` has the value `NULL`.
  198. .Structure (complex)
  199. -------------------------------------------------------------------------------
  200. #include <stdio.h>
  201. #include <stdlib.h>
  202. #include "utarray.h"
  203. typedef struct {
  204. int a;
  205. char *s;
  206. } intchar_t;
  207. void intchar_copy(void *_dst, const void *_src) {
  208. intchar_t *dst = (intchar_t*)_dst, *src = (intchar_t*)_src;
  209. dst->a = src->a;
  210. dst->s = src->s ? strdup(src->s) : NULL;
  211. }
  212. void intchar_dtor(void *_elt) {
  213. intchar_t *elt = (intchar_t*)_elt;
  214. if (elt->s) free(elt->s);
  215. }
  216. UT_icd intchar_icd = {sizeof(intchar_t), NULL, intchar_copy, intchar_dtor};
  217. int main() {
  218. UT_array *intchars;
  219. intchar_t ic, *p;
  220. utarray_new(intchars, &intchar_icd);
  221. ic.a=1; ic.s="hello"; utarray_push_back(intchars, &ic);
  222. ic.a=2; ic.s="world"; utarray_push_back(intchars, &ic);
  223. p=NULL;
  224. while( (p=(intchar_t*)utarray_next(intchars,p))) {
  225. printf("%d %s\n", p->a, (p->s ? p->s : "null"));
  226. }
  227. utarray_free(intchars);
  228. return 0;
  229. }
  230. -------------------------------------------------------------------------------
  231. [[operations]]
  232. Reference
  233. ---------
  234. This table lists all the utarray operations. These are loosely based on the C++
  235. vector class.
  236. Operations
  237. ~~~~~~~~~~
  238. [width="100%",cols="50<m,40<",grid="none",options="none"]
  239. |===============================================================================
  240. | utarray_new(UT_array *a, UT_icd *icd)| allocate a new array
  241. | utarray_free(UT_array *a) | free an allocated array
  242. | utarray_init(UT_array *a,UT_icd *icd)| init an array (non-alloc)
  243. | utarray_done(UT_array *a) | dispose of an array (non-allocd)
  244. | utarray_reserve(UT_array *a,int n) | ensure space available for 'n' more elements
  245. | utarray_push_back(UT_array *a,void *p) | push element p onto a
  246. | utarray_pop_back(UT_array *a) | pop last element from a
  247. | utarray_extend_back(UT_array *a) | push empty element onto a
  248. | utarray_len(UT_array *a) | get length of a
  249. | utarray_eltptr(UT_array *a,int j) | get pointer of element from index
  250. | utarray_eltidx(UT_array *a,void *e) | get index of element from pointer
  251. | utarray_insert(UT_array *a,void *p, int j) | insert element p to index j
  252. | utarray_inserta(UT_array *a,UT_array *w, int j) | insert array w into array a at index j
  253. | utarray_resize(UT_array *dst,int num) | extend or shrink array to num elements
  254. | utarray_concat(UT_array *dst,UT_array *src) | copy src to end of dst array
  255. | utarray_erase(UT_array *a,int pos,int len) | remove len elements from a[pos]..a[pos+len-1]
  256. | utarray_clear(UT_array *a) | clear all elements from a, setting its length to zero
  257. | utarray_sort(UT_array *a,cmpfcn *cmp) | sort elements of a using comparison function
  258. | utarray_find(UT_array *a,void *v, cmpfcn *cmp) | find element v in utarray (must be sorted)
  259. | utarray_front(UT_array *a) | get first element of a
  260. | utarray_next(UT_array *a,void *e) | get element of a following e (front if e is NULL)
  261. | utarray_prev(UT_array *a,void *e) | get element of a before e (back if e is NULL)
  262. | utarray_back(UT_array *a) | get last element of a
  263. |===============================================================================
  264. Notes
  265. ~~~~~
  266. 1. `utarray_new` and `utarray_free` are used to allocate a new array and free it,
  267. while `utarray_init` and `utarray_done` can be used if the UT_array is already
  268. allocated and just needs to be initialized or have its internal resources
  269. freed.
  270. 2. `utarray_reserve` takes the "delta" of elements to reserve, not the total
  271. desired capacity of the array. This differs from the C++ STL "reserve" notion.
  272. 3. `utarray_sort` expects a comparison function having the usual `strcmp`-like
  273. convention where it accepts two elements (a and b) and returns a negative
  274. value if a precedes b, 0 if a and b sort equally, and positive if b precedes a.
  275. This is an example of a comparison function:
  276. int intsort(const void *a, const void *b) {
  277. int _a = *(const int *)a;
  278. int _b = *(const int *)b;
  279. return (_a < _b) ? -1 : (_a > _b);
  280. }
  281. 4. `utarray_find` uses a binary search to locate an element having a certain value
  282. according to the given comparison function. The utarray must be first sorted
  283. using the same comparison function. An example of using `utarray_find` with
  284. a utarray of strings is included in `tests/test61.c`.
  285. 5. A 'pointer' to a particular element (obtained using `utarray_eltptr` or
  286. `utarray_front`, `utarray_next`, `utarray_prev`, `utarray_back`) becomes invalid whenever
  287. another element is inserted into the utarray. This is because the internal
  288. memory management may need to `realloc` the element storage to a new address.
  289. For this reason, it's usually better to refer to an element by its integer
  290. 'index' in code whose duration may include element insertion.
  291. 6. To override the default out-of-memory handling behavior (which calls `exit(-1)`),
  292. override the `utarray_oom()` macro before including `utarray.h`.
  293. For example,
  294. #define utarray_oom() do { longjmp(error_handling_location); } while (0)
  295. ...
  296. #include "utarray.h"
  297. // vim: set nowrap syntax=asciidoc: