tarray.h 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  1. #include <stdlib.h>
  2. #include "tbegin.h"
  3. /*
  4. * TARRAY is template for a dynamic array of size elements.
  5. * For simplicity, it is is exactly sized, that is,
  6. * it does not allocate any extra elements but the amount requested.
  7. * In other words it's capacity is equal to it's size.
  8. */
  9. #ifdef TEMPLATE_OK
  10. #ifndef TEMPLATE_IMPLEMENT
  11. struct TEMPLATE_STRUCT;
  12. typedef struct TEMPLATE_STRUCT TEMPLATE_NAME;
  13. #define TEMPLATE_COMPARATOR TJOIN(TEMPLATE_STRUCT, Compare)
  14. typedef int TEMPLATE_COMPARATOR (const void * self, const void * other);
  15. /* Gets the array's size. Returns 0 if self is NULL. */
  16. int TEMPLATE_FUNC(size)(TEMPLATE_NAME * self);
  17. /* Frees the contents of an array. Has the same effect as emptying the array.
  18. Does not call a destructor on any elements contained! */
  19. TEMPLATE_NAME * TEMPLATE_FUNC(done)(TEMPLATE_NAME * self);
  20. /* Frees an array. Returns NULL. */
  21. TEMPLATE_NAME * TEMPLATE_FUNC(free)(TEMPLATE_NAME * self);
  22. /* Allocates a new unusable array. */
  23. TEMPLATE_NAME * TEMPLATE_FUNC(alloc)();
  24. /* Initializes an empty array with size elements. */
  25. TEMPLATE_NAME * TEMPLATE_FUNC(init)(TEMPLATE_NAME * self, int size);
  26. /* Changes the size of the dynamic array. Newsize must be >= 1. */
  27. TEMPLATE_NAME * TEMPLATE_FUNC(size_)(TEMPLATE_NAME * self, int newsize);
  28. /* Allocates a new array with size elements. */
  29. TEMPLATE_NAME * TEMPLATE_FUNC(new)(int size);
  30. /* Sets the amount of elements of the the array, but ony if
  31. * amount bigger than the bigger than the current size.
  32. * Returns NULL if the array was not grown, otherwise returns self.
  33. */
  34. TEMPLATE_NAME * TEMPLATE_FUNC(grow)(TEMPLATE_NAME * self, int amount);
  35. /* Returns a pointer to the index-th element of the array.
  36. Does no bounds checking! */
  37. TEMPLATE_T * TEMPLATE_FUNC(getptr_unsafe)(TEMPLATE_NAME * self, int index);
  38. /* Returns the index-th element of the array. Does no bounds checking! */
  39. TEMPLATE_T TEMPLATE_FUNC(getraw_unsafe)(TEMPLATE_NAME * self, int index);
  40. /* Puts the element value at the index'th position
  41. * in the array. Does no bounds checking. Returns self;
  42. */
  43. TEMPLATE_NAME * TEMPLATE_FUNC(putraw_unsafe)
  44. (TEMPLATE_NAME * self, int index, TEMPLATE_T value);
  45. /* Returns the index-th element of the array.
  46. Does bounds checking and returns zero if out of bounds */
  47. TEMPLATE_T TEMPLATE_FUNC(getraw)(TEMPLATE_NAME * self,
  48. size_t index, TEMPLATE_T zero);
  49. /* Returns the index-th element of the array in get.
  50. Does bounds checking and returns FALSE if out of bounds or
  51. if get is not set. Returns TRUE and stores the result in get if all is OK. */
  52. int TEMPLATE_FUNC(get)(TEMPLATE_NAME * self,
  53. int index, TEMPLATE_T * get);
  54. /* Returns a pointer to the index-th element of the array.
  55. Does bounds checking and return NULL if out of bounds */
  56. TEMPLATE_T * TEMPLATE_FUNC(getptr)(TEMPLATE_NAME * self, int index);
  57. /* Copies the TEMPLATE_FUNC(elementsize)(self) of bytes from the data
  58. * in value to the location pointed to by index.
  59. * Does bounds checking and return NULL if out of bounds.
  60. * Returns self if all was OK.
  61. */
  62. TEMPLATE_NAME * TEMPLATE_FUNC(put)(TEMPLATE_NAME * self,
  63. int index, TEMPLATE_T value);
  64. /* Stores contents of a pointer at the index of the array.
  65. * Does bounds checking.
  66. */
  67. TEMPLATE_NAME * TEMPLATE_FUNC(putptr)(TEMPLATE_NAME * self, int index,
  68. TEMPLATE_T * ptr);
  69. #else
  70. /* Implementation */
  71. struct TEMPLATE_STRUCT {
  72. TEMPLATE_T * data;
  73. int size;
  74. };
  75. /* Gets the array's size. Returns 0 if self is NULL. */
  76. int TEMPLATE_FUNC(size)(TEMPLATE_NAME * self) {
  77. if(!self) return 0;
  78. return self->size;
  79. }
  80. /* Frees the contents of an array. Has the same effect as emptying the array.
  81. Does not call a destructor on any elements contained! */
  82. TEMPLATE_NAME * TEMPLATE_FUNC(done)(TEMPLATE_NAME * self) {
  83. if(!self) return NULL;
  84. TEMPLATE_FREE(self->data);
  85. self->data = NULL;
  86. self->size = 0;
  87. return self;
  88. }
  89. /* Frees an array. Returns NULL. */
  90. TEMPLATE_NAME * TEMPLATE_FUNC(free)(TEMPLATE_NAME * self) {
  91. TEMPLATE_FUNC(done)(self);
  92. TEMPLATE_FREE(self);
  93. return NULL;
  94. }
  95. /* Allocates a new unusable array. */
  96. TEMPLATE_NAME * TEMPLATE_FUNC(alloc)() {
  97. return TEMPLATE_ALLOC(sizeof(TEMPLATE_NAME));
  98. }
  99. /* Initializes an empty array with size elements. */
  100. TEMPLATE_NAME * TEMPLATE_FUNC(init)(TEMPLATE_NAME * self, int size) {
  101. if(!self) return NULL;
  102. if(size < 0) return NULL;
  103. self->size = size;
  104. self->data = TEMPLATE_ALLOC(sizeof(TEMPLATE_T) * size);
  105. return self;
  106. }
  107. /* Changes the size of the dynamic array. Newsize must be >= 1. */
  108. TEMPLATE_NAME * TEMPLATE_FUNC(size_)(TEMPLATE_NAME * self, int newsize) {
  109. TEMPLATE_T * newd = NULL;
  110. if(!self) return NULL;
  111. int index, stop;
  112. // Don't allow a newsize of 0, since that will make realloc call
  113. // free on self->data, which we don't want.
  114. if(newsize < 1) return NULL;
  115. newd = TEMPLATE_ALLOC(newsize * sizeof(TEMPLATE_T));
  116. if(!newd) return NULL;
  117. // copy data if needed
  118. if(self->data) {
  119. stop = self->size < newsize ? self->size : newsize;
  120. for(index = 0; index < self->size; index ++) {
  121. newd[index] = self->data[index];
  122. }
  123. }
  124. // if we get here alloc was successful, so it should be safe to reassign
  125. // self->data
  126. self->data = newd;
  127. self->size = newsize;
  128. return self;
  129. }
  130. /* Allocates a new array with size elements. Size should be greater than 0 */
  131. TEMPLATE_NAME * TEMPLATE_FUNC(new)(int size) {
  132. TEMPLATE_NAME * res = TEMPLATE_FUNC(alloc)();
  133. if(!TEMPLATE_FUNC(init)(res, size)) {
  134. return TEMPLATE_FUNC(free)(res);
  135. }
  136. return res;
  137. }
  138. /* Sets the amount of elements of the the array, but ony if
  139. * amount bigger than the bigger than the current size.
  140. * Returns NULL if the array was not grown, otherwise returns self.
  141. */
  142. TEMPLATE_NAME * TEMPLATE_FUNC(grow)(TEMPLATE_NAME * self, int amount) {
  143. int mysize = TEMPLATE_FUNC(size)(self);
  144. if (mysize >= amount) return NULL;
  145. return TEMPLATE_FUNC(size_)(self, amount);
  146. }
  147. /* Returns true if the index is out of range, false if it's OK to use
  148. with this TARRAY. */
  149. int TEMPLATE_FUNC(outofrange)(TEMPLATE_NAME * self, int index) {
  150. if(!self) return TRUE;
  151. if (index < 0) return TRUE;
  152. return index >= TEMPLATE_FUNC(size)(self);
  153. }
  154. /* Returns a pointer to the index-th element of the array.
  155. Does no bounds checking! */
  156. TEMPLATE_T * TEMPLATE_FUNC(getptr_unsafe)(TEMPLATE_NAME * self, int index) {
  157. return self->data + index;
  158. }
  159. /* Returns the index-th element of the array. Does no bounds checking! */
  160. TEMPLATE_T TEMPLATE_FUNC(getraw_unsafe)(TEMPLATE_NAME * self, int index) {
  161. return self->data[index];
  162. }
  163. /* Puts the element value at the index'th position
  164. * in the array. Does no bounds checking. Returns self;
  165. */
  166. TEMPLATE_NAME * TEMPLATE_FUNC(putraw_unsafe)
  167. (TEMPLATE_NAME * self, int index, TEMPLATE_T value) {
  168. self->data[index] = value;
  169. return self;
  170. }
  171. /* Returns the index-th element of the array.
  172. Does bounds checking and returns zero if out of bounds */
  173. TEMPLATE_T TEMPLATE_FUNC(getraw)(TEMPLATE_NAME * self,
  174. size_t index, TEMPLATE_T zero) {
  175. // Bounds check
  176. if(TEMPLATE_FUNC(outofrange)(self, index)) { return zero; }
  177. return TEMPLATE_FUNC(getraw_unsafe)(self, index);
  178. }
  179. /* Returns the index-th element of the array in get.
  180. Does bounds checking and returns FALSE if out of bounds or
  181. if get is not set. Returns TRUE and stores the result in get if all is OK*/
  182. int TEMPLATE_FUNC(get)(TEMPLATE_NAME * self,
  183. int index, TEMPLATE_T * get) {
  184. // Bounds check
  185. if(!get) { return FALSE; }
  186. if(TEMPLATE_FUNC(outofrange)(self, index)) { return FALSE; }
  187. (*get) = TEMPLATE_FUNC(getraw_unsafe)(self, index);
  188. return TRUE;
  189. }
  190. /* Returns a pointer to the index-th element of the array.
  191. Does bounds checking and return NULL if out of bounds */
  192. TEMPLATE_T * TEMPLATE_FUNC(getptr)(TEMPLATE_NAME * self, int index) {
  193. // Bounds check
  194. if(TEMPLATE_FUNC(outofrange)(self, index)) { return NULL; }
  195. return TEMPLATE_FUNC(getptr_unsafe)(self, index);
  196. }
  197. /* Copies the TEMPLATE_FUNC(elementsize)(self) of bytes from the data
  198. * in value to the location pointed to by index.
  199. * Does bounds checking and return NULL if out of bounds.
  200. * Returns self if all was OK, NULL if not.
  201. */
  202. TEMPLATE_NAME * TEMPLATE_FUNC(put)(TEMPLATE_NAME * self,
  203. int index, TEMPLATE_T value) {
  204. // Bounds check
  205. if(TEMPLATE_FUNC(outofrange)(self, index)) { return NULL; }
  206. return TEMPLATE_FUNC(putraw_unsafe)(self, index, value);
  207. }
  208. /* Stores contents of a pointer at the index of the array.
  209. * Does bounds checking.
  210. */
  211. TEMPLATE_NAME * TEMPLATE_FUNC(putptr)(TEMPLATE_NAME * self, int index,
  212. TEMPLATE_T * ptr) {
  213. if(!ptr) return NULL;
  214. return TEMPLATE_FUNC(put)(self, index, (*ptr));
  215. // use &ptr because we want to put the contents of the pointer,
  216. // not the pointer itself.
  217. }
  218. #ifdef TEMPLATE_COMPARATOR
  219. /* Applies quicksort to the array using the given comparator. */
  220. TEMPLATE_NAME * TEMPLATE_FUNC(qsort)(TEMPLATE_NAME * self,
  221. TEMPLATE_COMPARATOR * compare) {
  222. void * base; int nmemb; size_t size;
  223. if(!self) return NULL;
  224. base = self->data;
  225. nmemb = self->size;
  226. size = sizeof(TEMPLATE_T);
  227. qsort(base, nmemb, size, compare);
  228. return self;
  229. }
  230. #endif
  231. #endif
  232. #endif
  233. #ifdef TEMPLATE_ZERO
  234. #undef TEMPLATE_ZERO
  235. #endif
  236. #ifdef TEMPLATE_COMPARATOR
  237. #undef TEMPLATE_COMPARATOR
  238. #endif
  239. /* Finally clean up by undefining all defined macros. **/
  240. #include <tend.h>
  241. #ifdef TEMPLATE_IMPLEMENT
  242. #undef TEMPLATE_IMPLEMENT
  243. #endif
  244. /* We need this because of a nasty CPP bug in older (4.4.3) gcc versions:
  245. * it seems the undefs in tend.h are not applied repeatedly. gcc 4.7.2 is ok. */