ring.h 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  1. #ifndef __sti__ring_h__
  2. #define __sti__ring_h__
  3. // Public Domain.
  4. #include <stdlib.h> // size_t, calloc, free
  5. // ----------------------------
  6. // non-thread-safe ring buffers
  7. // ----------------------------
  8. // declare a ring buffer
  9. #define RING(t) \
  10. struct { \
  11. size_t len, alloc, first; \
  12. t* data; \
  13. }
  14. // initialisze a ring buffer
  15. #define RING_INIT(x, sz) \
  16. do { \
  17. (x)->data = calloc(1, sz * sizeof(*((x)->data))); \
  18. (x)->len = 0; \
  19. (x)->first = 0; \
  20. (x)->alloc = sz; \
  21. } while(0)
  22. // helpers
  23. #define RING_LEN(x) ((x)->len)
  24. #define RING_ALLOC(x) ((x)->alloc)
  25. #define RING_DATA(x) ((x)->data)
  26. #define RING_ITEM(x, i) (RING_DATA(x)[((x)->first + (i)) % (x)->alloc])
  27. #define RING_TAIL(x) (RING_DATA(x)[((x)->first + (x)->len - 1) % (x)->alloc])
  28. #define RING_HEAD(x) (RING_DATA(x)[(x)->first])
  29. // #define RING_FIND(x, ptr_o) vec_find(RING_DATA(x), RING_LEN(x), sizeof(*RING_DATA(x)), ptr_o)
  30. #define RING_TRUNC(x) \
  31. do { \
  32. (x)->len = 0; \
  33. (x)->first = 0; \
  34. while(0)
  35. //
  36. #define RING_GROW(x) ring_resize((void**)&RING_DATA(x), &RING_ALLOC(x), sizeof(*RING_DATA(x)))
  37. /*
  38. // check if a size increase is needed to insert one more item
  39. #define RING_CHECK(x) \
  40. do { \
  41. if(RING_LEN(x) >= RING_ALLOC(x)) { \
  42. RING_GROW(x); \
  43. } \
  44. } while(0)
  45. */
  46. // operations
  47. // assign new entry at the end
  48. #define RING_PUSH(x, e) \
  49. do { \
  50. if((x)->alloc > 0) { \
  51. if((x)->len >= (x)->alloc) { \
  52. (x)->data[((x)->first + (x)->len) % (x)->alloc] = (e); \
  53. (x)->first = ((x)->first + 1) % (x)->alloc; \
  54. } \
  55. else { \
  56. (x)->data[((x)->first + (x)->len) % (x)->alloc] = (e); \
  57. (x)->len++; \
  58. } \
  59. } \
  60. } while(0)
  61. // remove latest entry
  62. #define RING_POP(x, e) \
  63. do { \
  64. if((x)->len > 0 && (x)->alloc > 0) { \
  65. (e) = (x)->data[((x)->first + (x)->len - 1) % (x)->alloc]; \
  66. (x)->len--; \
  67. } \
  68. } while(0)
  69. #define RING_PREPEND(x, e) \
  70. do { \
  71. if((x)->alloc > 0) { \
  72. if((x)->len >= (x)->alloc) { \
  73. (x)->data[((x)->first + (x)->len) % (x)->alloc] = (e); \
  74. (x)->first = ((x)->first + 1) % (x)->alloc; \
  75. } \
  76. else { \
  77. (x)->data[((x)->first + (x)->len) % (x)->alloc] = (e); \
  78. (x)->len++; \
  79. } \
  80. } \
  81. } while(0)
  82. #define RING_PEEK(x) RING_DATA(x)[RING_LEN(x) - 1]
  83. #define RING_POP1(x) \
  84. do { \
  85. if((x)->len > 0 && (x)->alloc > 0) { \
  86. (x)->len--; \
  87. } \
  88. } while(0)
  89. void ring_rm_(void* data, size_t stride, size_t* len, size_t* first, size_t alloc, size_t i);
  90. #define RING_RM(x, i) \
  91. ring_rm_((x)->data, sizeof(*((x)->data)), &((x)->len), &((x)->first), (x)->alloc, (i));
  92. #define RING_FREE(x) \
  93. do { \
  94. if(RING_DATA(x)) free(RING_DATA(x)); \
  95. (x)->data = 0; \
  96. (x)->len = 0; \
  97. (x)->first = 0; \
  98. (x)->alloc = 0; \
  99. } while(0)
  100. #define RING_COPY(copy, orig) \
  101. do { \
  102. void* tmp; \
  103. tmp = realloc(RING_DATA(copy), RING_ALLOC(orig) * sizeof(*RING_DATA(orig)) ); \
  104. if(!tmp) { \
  105. fprintf(stderr, "Out of memory in ring copy"); \
  106. exit(1); \
  107. } \
  108. \
  109. RING_DATA(copy) = tmp; \
  110. RING_LEN(copy) = RING_LEN(orig); \
  111. RING_ALLOC(copy) = RING_ALLOC(orig); \
  112. (copy)->first = (orig)->first; \
  113. \
  114. memcpy(RING_DATA(copy), RING_DATA(orig), RING_LEN(orig) * sizeof(*RING_DATA(orig))); \
  115. } while(0)
  116. /*
  117. Loop macro magic
  118. https://www.chiark.greenend.org.uk/~sgtatham/mp/
  119. HashTable obj;
  120. HT_LOOP(&obj, key, char*, val) {
  121. printf("loop: %s, %s", key, val);
  122. }
  123. effective source:
  124. #define HT_LOOP(obj, keyname, valtype, valname)
  125. if(0)
  126. finished: ;
  127. else
  128. for(char* keyname;;) // internal declarations, multiple loops to avoid comma op funny business
  129. for(valtype valname;;)
  130. for(void* iter = NULL ;;)
  131. if(HT_next(obj, iter, &keyname, &valname))
  132. goto main_loop;
  133. else
  134. while(1)
  135. if(1) {
  136. // when the user uses break
  137. goto finished;
  138. }
  139. else
  140. while(1)
  141. if(!HT_next(obj, iter, &keyname, &valname)) {
  142. // normal termination
  143. goto finished;
  144. }
  145. else
  146. main_loop:
  147. // { user block; not in macro }
  148. */
  149. #define RING__PASTEINNER(a, b) a ## b
  150. #define RING__PASTE(a, b) RING__PASTEINNER(a, b)
  151. #define RING__ITER(key, val) RING__PASTE(RING_iter_ ## key ## __ ## val ## __, __LINE__)
  152. #define RING__FINISHED(key, val) RING__PASTE(RING_finished__ ## key ## __ ## val ## __, __LINE__)
  153. #define RING__MAINLOOP(key, val) RING__PASTE(RING_main_loop__ ## key ## __ ## val ## __, __LINE__)
  154. #define RING_EACH(obj, index, valname) \
  155. if(0) \
  156. RING__FINISHED(index, val): ; \
  157. else \
  158. for(typeof(*RING_DATA(obj)) valname ;;) \
  159. for(size_t index = 0;;) \
  160. if(index < RING_LEN(obj) && (valname = RING_ITEM(obj, index), 1)) \
  161. goto RING__MAINLOOP(index, val); \
  162. else \
  163. while(1) \
  164. if(1) { \
  165. goto RING__FINISHED(index, val); \
  166. } \
  167. else \
  168. while(1) \
  169. if(++index >= RING_LEN(obj) || (valname = RING_ITEM(obj, index), 0)) { \
  170. goto RING__FINISHED(index, val); \
  171. } \
  172. else \
  173. RING__MAINLOOP(index, val) :
  174. // { user block; not in macro }
  175. // reverse
  176. #define RING_R_EACH(obj, index, valname) \
  177. if(0) \
  178. RING__FINISHED(index, val): ; \
  179. else \
  180. for(typeof(*RING_DATA(obj)) valname ;;) \
  181. for(ptrdiff_t index = (ptrdiff_t)RING_LEN(obj) - 1;;) \
  182. if(index >= 0 && (valname = RING_ITEM(obj, index), 1)) \
  183. goto RING__MAINLOOP(index, val); \
  184. else \
  185. while(1) \
  186. if(1) { \
  187. goto RING__FINISHED(index, val); \
  188. } \
  189. else \
  190. while(1) \
  191. if(--index < 0 || (valname = RING_ITEM(obj, index), 0)) { \
  192. goto RING__FINISHED(index, val); \
  193. } \
  194. else \
  195. RING__MAINLOOP(index, val) :
  196. // { user block; not in macro }
  197. // this version only iterates the index
  198. #define RING_LOOP(obj, index) \
  199. if(0) \
  200. RING__FINISHED(index, val): ; \
  201. else \
  202. for(size_t index = 0;;) \
  203. if(index < RING_LEN(obj)) \
  204. goto RING__MAINLOOP(index, val); \
  205. else \
  206. while(1) \
  207. if(1) { \
  208. goto RING__FINISHED(index, val); \
  209. } \
  210. else \
  211. while(1) \
  212. if(++index >= RING_LEN(obj)) { \
  213. goto RING__FINISHED(index, val); \
  214. } \
  215. else \
  216. RING__MAINLOOP(index, val) :
  217. // { user block; not in macro }
  218. // reverse; this version only iterates the index
  219. #define RING_R_LOOP(obj, index) \
  220. if(0) \
  221. RING__FINISHED(index, val): ; \
  222. else \
  223. for(ptrdiff_t index = (ptrdiff_t)RING_LEN(obj) - 1;;) \
  224. if(index >= 0) \
  225. goto RING__MAINLOOP(index, val); \
  226. else \
  227. while(1) \
  228. if(1) { \
  229. goto RING__FINISHED(index, val); \
  230. } \
  231. else \
  232. while(1) \
  233. if(--index < 0) { \
  234. goto RING__FINISHED(index, val); \
  235. } \
  236. else \
  237. RING__MAINLOOP(index, val) :
  238. // { user block; not in macro }
  239. #endif // __sti__ring_h__