Team Fortress 2 Source Code as on 22/4/2020
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.

262 lines
11 KiB

  1. // stretchy_buffer.h - v1.03 - public domain - nothings.org/stb
  2. // a vector<>-like dynamic array for C
  3. //
  4. // version history:
  5. // 1.03 - compile as C++ maybe
  6. // 1.02 - tweaks to syntax for no good reason
  7. // 1.01 - added a "common uses" documentation section
  8. // 1.0 - fixed bug in the version I posted prematurely
  9. // 0.9 - rewrite to try to avoid strict-aliasing optimization
  10. // issues, but won't compile as C++
  11. //
  12. // Will probably not work correctly with strict-aliasing optimizations.
  13. //
  14. // The idea:
  15. //
  16. // This implements an approximation to C++ vector<> for C, in that it
  17. // provides a generic definition for dynamic arrays which you can
  18. // still access in a typesafe way using arr[i] or *(arr+i). However,
  19. // it is simply a convenience wrapper around the common idiom of
  20. // of keeping a set of variables (in a struct or globals) which store
  21. // - pointer to array
  22. // - the length of the "in-use" part of the array
  23. // - the current size of the allocated array
  24. //
  25. // I find it to be the single most useful non-built-in-structure when
  26. // programming in C (hash tables a close second), but to be clear
  27. // it lacks many of the capabilities of C++ vector<>: there is no
  28. // range checking, the object address isn't stable (see next section
  29. // for details), the set of methods available is small (although
  30. // the file stb.h has another implementation of stretchy buffers
  31. // called 'stb_arr' which provides more methods, e.g. for insertion
  32. // and deletion).
  33. //
  34. // How to use:
  35. //
  36. // Unlike other stb header file libraries, there is no need to
  37. // define an _IMPLEMENTATION symbol. Every #include creates as
  38. // much implementation is needed.
  39. //
  40. // stretchy_buffer.h does not define any types, so you do not
  41. // need to #include it to before defining data types that are
  42. // stretchy buffers, only in files that *manipulate* stretchy
  43. // buffers.
  44. //
  45. // If you want a stretchy buffer aka dynamic array containing
  46. // objects of TYPE, declare such an array as:
  47. //
  48. // TYPE *myarray = NULL;
  49. //
  50. // (There is no typesafe way to distinguish between stretchy
  51. // buffers and regular arrays/pointers; this is necessary to
  52. // make ordinary array indexing work on these objects.)
  53. //
  54. // Unlike C++ vector<>, the stretchy_buffer has the same
  55. // semantics as an object that you manually malloc and realloc.
  56. // The pointer may relocate every time you add a new object
  57. // to it, so you:
  58. //
  59. // 1. can't take long-term pointers to elements of the array
  60. // 2. have to return the pointer from functions which might expand it
  61. // (either as a return value or by storing it to a ptr-to-ptr)
  62. //
  63. // Now you can do the following things with this array:
  64. //
  65. // sb_free(TYPE *a) free the array
  66. // sb_count(TYPE *a) the number of elements in the array
  67. // sb_push(TYPE *a, TYPE v) adds v on the end of the array, a la push_back
  68. // sb_add(TYPE *a, int n) adds n uninitialized elements at end of array & returns pointer to first added
  69. // sb_last(TYPE *a) returns an lvalue of the last item in the array
  70. // a[n] access the nth (counting from 0) element of the array
  71. //
  72. // #define STRETCHY_BUFFER_NO_SHORT_NAMES to only export
  73. // names of the form 'stb_sb_' if you have a name that would
  74. // otherwise collide.
  75. //
  76. // Note that these are all macros and many of them evaluate
  77. // their arguments more than once, so the arguments should
  78. // be side-effect-free.
  79. //
  80. // Note that 'TYPE *a' in sb_push and sb_add must be lvalues
  81. // so that the library can overwrite the existing pointer if
  82. // the object has to be reallocated.
  83. //
  84. // In an out-of-memory condition, the code will try to
  85. // set up a null-pointer or otherwise-invalid-pointer
  86. // exception to happen later. It's possible optimizing
  87. // compilers could detect this write-to-null statically
  88. // and optimize away some of the code, but it should only
  89. // be along the failure path. Nevertheless, for more security
  90. // in the face of such compilers, #define STRETCHY_BUFFER_OUT_OF_MEMORY
  91. // to a statement such as assert(0) or exit(1) or something
  92. // to force a failure when out-of-memory occurs.
  93. //
  94. // Common use:
  95. //
  96. // The main application for this is when building a list of
  97. // things with an unknown quantity, either due to loading from
  98. // a file or through a process which produces an unpredictable
  99. // number.
  100. //
  101. // My most common idiom is something like:
  102. //
  103. // SomeStruct *arr = NULL;
  104. // while (something)
  105. // {
  106. // SomeStruct new_one;
  107. // new_one.whatever = whatever;
  108. // new_one.whatup = whatup;
  109. // new_one.foobar = barfoo;
  110. // sb_push(arr, new_one);
  111. // }
  112. //
  113. // and various closely-related factorings of that. For example,
  114. // you might have several functions to create/init new SomeStructs,
  115. // and if you use the above idiom, you might prefer to make them
  116. // return structs rather than take non-const-pointers-to-structs,
  117. // so you can do things like:
  118. //
  119. // SomeStruct *arr = NULL;
  120. // while (something)
  121. // {
  122. // if (case_A) {
  123. // sb_push(arr, some_func1());
  124. // } else if (case_B) {
  125. // sb_push(arr, some_func2());
  126. // } else {
  127. // sb_push(arr, some_func3());
  128. // }
  129. // }
  130. //
  131. // Note that the above relies on the fact that sb_push doesn't
  132. // evaluate its second argument more than once. The macros do
  133. // evaluate the *array* argument multiple times, and numeric
  134. // arguments may be evaluated multiple times, but you can rely
  135. // on the second argument of sb_push being evaluated only once.
  136. //
  137. // Of course, you don't have to store bare objects in the array;
  138. // if you need the objects to have stable pointers, store an array
  139. // of pointers instead:
  140. //
  141. // SomeStruct **arr = NULL;
  142. // while (something)
  143. // {
  144. // SomeStruct *new_one = malloc(sizeof(*new_one));
  145. // new_one->whatever = whatever;
  146. // new_one->whatup = whatup;
  147. // new_one->foobar = barfoo;
  148. // sb_push(arr, new_one);
  149. // }
  150. //
  151. // How it works:
  152. //
  153. // A long-standing tradition in things like malloc implementations
  154. // is to store extra data before the beginning of the block returned
  155. // to the user. The stretchy buffer implementation here uses the
  156. // same trick; the current-count and current-allocation-size are
  157. // stored before the beginning of the array returned to the user.
  158. // (This means you can't directly free() the pointer, because the
  159. // allocated pointer is different from the type-safe pointer provided
  160. // to the user.)
  161. //
  162. // The details are trivial and implementation is straightforward;
  163. // the main trick is in realizing in the first place that it's
  164. // possible to do this in a generic, type-safe way in C.
  165. //
  166. // Contributors:
  167. //
  168. // Timothy Wright (github:ZenToad)
  169. //
  170. // LICENSE
  171. //
  172. // See end of file for license information.
  173. #ifndef STB_STRETCHY_BUFFER_H_INCLUDED
  174. #define STB_STRETCHY_BUFFER_H_INCLUDED
  175. #ifndef NO_STRETCHY_BUFFER_SHORT_NAMES
  176. #define sb_free stb_sb_free
  177. #define sb_push stb_sb_push
  178. #define sb_count stb_sb_count
  179. #define sb_add stb_sb_add
  180. #define sb_last stb_sb_last
  181. #endif
  182. #define stb_sb_free(a) ((a) ? free(stb__sbraw(a)),0 : 0)
  183. #define stb_sb_push(a,v) (stb__sbmaybegrow(a,1), (a)[stb__sbn(a)++] = (v))
  184. #define stb_sb_count(a) ((a) ? stb__sbn(a) : 0)
  185. #define stb_sb_add(a,n) (stb__sbmaybegrow(a,n), stb__sbn(a)+=(n), &(a)[stb__sbn(a)-(n)])
  186. #define stb_sb_last(a) ((a)[stb__sbn(a)-1])
  187. #define stb__sbraw(a) ((int *) (a) - 2)
  188. #define stb__sbm(a) stb__sbraw(a)[0]
  189. #define stb__sbn(a) stb__sbraw(a)[1]
  190. #define stb__sbneedgrow(a,n) ((a)==0 || stb__sbn(a)+(n) >= stb__sbm(a))
  191. #define stb__sbmaybegrow(a,n) (stb__sbneedgrow(a,(n)) ? stb__sbgrow(a,n) : 0)
  192. #define stb__sbgrow(a,n) (*((void **)&(a)) = stb__sbgrowf((a), (n), sizeof(*(a))))
  193. #include <stdlib.h>
  194. static void * stb__sbgrowf(void *arr, int increment, int itemsize)
  195. {
  196. int dbl_cur = arr ? 2*stb__sbm(arr) : 0;
  197. int min_needed = stb_sb_count(arr) + increment;
  198. int m = dbl_cur > min_needed ? dbl_cur : min_needed;
  199. int *p = (int *) realloc(arr ? stb__sbraw(arr) : 0, itemsize * m + sizeof(int)*2);
  200. if (p) {
  201. if (!arr)
  202. p[1] = 0;
  203. p[0] = m;
  204. return p+2;
  205. } else {
  206. #ifdef STRETCHY_BUFFER_OUT_OF_MEMORY
  207. STRETCHY_BUFFER_OUT_OF_MEMORY ;
  208. #endif
  209. return (void *) (2*sizeof(int)); // try to force a NULL pointer exception later
  210. }
  211. }
  212. #endif // STB_STRETCHY_BUFFER_H_INCLUDED
  213. /*
  214. ------------------------------------------------------------------------------
  215. This software is available under 2 licenses -- choose whichever you prefer.
  216. ------------------------------------------------------------------------------
  217. ALTERNATIVE A - MIT License
  218. Copyright (c) 2017 Sean Barrett
  219. Permission is hereby granted, free of charge, to any person obtaining a copy of
  220. this software and associated documentation files (the "Software"), to deal in
  221. the Software without restriction, including without limitation the rights to
  222. use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
  223. of the Software, and to permit persons to whom the Software is furnished to do
  224. so, subject to the following conditions:
  225. The above copyright notice and this permission notice shall be included in all
  226. copies or substantial portions of the Software.
  227. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  228. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  229. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  230. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  231. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  232. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  233. SOFTWARE.
  234. ------------------------------------------------------------------------------
  235. ALTERNATIVE B - Public Domain (www.unlicense.org)
  236. This is free and unencumbered software released into the public domain.
  237. Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
  238. software, either in source code form or as a compiled binary, for any purpose,
  239. commercial or non-commercial, and by any means.
  240. In jurisdictions that recognize copyright laws, the author or authors of this
  241. software dedicate any and all copyright interest in the software to the public
  242. domain. We make this dedication for the benefit of the public at large and to
  243. the detriment of our heirs and successors. We intend this dedication to be an
  244. overt act of relinquishment in perpetuity of all present and future rights to
  245. this software under copyright law.
  246. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  247. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  248. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  249. AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  250. ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  251. WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  252. ------------------------------------------------------------------------------
  253. */