svec.h 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. #ifndef __sti__svec_h__
  2. #define __sti__svec_h__
  3. #include <stddef.h>
  4. #include <stdlib.h>
  5. /*
  6. SVEC stands for Stable Vector. Pointers to indices will never change and can be cached forever
  7. */
  8. #define SVEC_CHUNK_SIZE(x) 512
  9. struct svec_base_props {
  10. void** data; // overlaps with the data pointer in the union
  11. size_t len, alloc; \
  12. size_t chunksAlloc; \
  13. size_t chunksLen; \
  14. };
  15. void svec_resize(struct svec_base_props* base, size_t elem_size, size_t chunk_size);
  16. long svec_pointer_index(struct svec_base_props* base, size_t elem_size, size_t chunk_size, void* ptr);
  17. void svec_free(struct svec_base_props* base);
  18. #define SVEC(type) \
  19. union { \
  20. type** chunks; \
  21. struct svec_base_props b; \
  22. }
  23. // initialisze a vector
  24. #define SVEC_init(x) \
  25. do { \
  26. (x)->chunks = NULL; \
  27. (x)->b.len = 0; \
  28. (x)->b.alloc = 0; \
  29. (x)->b.chunksAlloc = 0; \
  30. (x)->b.chunksLen = 0; \
  31. } while(0)
  32. // helpers
  33. #define SVEC_len(x) ((x)->b.len)
  34. #define SVEC_item(x, i) ((x)->chunks[(i) / SVEC_CHUNK_SIZE(x)][(i) % SVEC_CHUNK_SIZE(x)])
  35. #define SVEC_itemp(x, i) ({ \
  36. typeof(i) __SVEC_tmp = (i); \
  37. &((x)->chunks[(__SVEC_tmp) / SVEC_CHUNK_SIZE(x)][(__SVEC_tmp) % SVEC_CHUNK_SIZE(x)]); \
  38. })
  39. #define SVEC_tail(x) (SVEC_item((x)->b.len - 1))
  40. #define SVEC_head(x) (SVEC_item(0))
  41. #define SVEC_push(x, y) \
  42. do { \
  43. if((x)->b.len <= (x)->b.alloc) { \
  44. svec_resize(&(x)->b, sizeof(**(x)->chunks), SVEC_CHUNK_SIZE(x)); \
  45. } \
  46. *SVEC_itemp((x), (x)->b.len++) = (y); \
  47. } while(0);
  48. #define SVEC_inc(x) \
  49. ({ \
  50. if((x)->b.len <= (x)->b.alloc) { \
  51. svec_resize(&(x)->b, sizeof(**(x)->chunks), SVEC_CHUNK_SIZE(x)); \
  52. } \
  53. memset(SVEC_itemp((x), (x)->b.len), 0, sizeof(**(x)->chunks)); \
  54. SVEC_itemp((x), (x)->b.len++); \
  55. })
  56. #define SVEC_pointer_index(x, p) svec_pointer_index(&(x)->b, sizeof(**(x)->chunks), SVEC_CHUNK_SIZE(x), (p));
  57. #define SVEC_free(x) svec_free(&(x)->b);
  58. #define SVEC_EACH _Pragma("GCC error \"'SVEC_EACH' does not exist. Use 'SVEC_EACHP'.\"")
  59. /*
  60. Loop macro magic
  61. https://www.chiark.greenend.org.uk/~sgtatham/mp/
  62. HashTable obj;
  63. HT_LOOP(&obj, key, char*, val) {
  64. printf("loop: %s, %s", key, val);
  65. }
  66. effective source:
  67. #define HT_LOOP(obj, keyname, valtype, valname)
  68. if(0)
  69. finished: ;
  70. else
  71. for(char* keyname;;) // internal declarations, multiple loops to avoid comma op funny business
  72. for(valtype valname;;)
  73. for(void* iter = NULL ;;)
  74. if(HT_next(obj, iter, &keyname, &valname))
  75. goto main_loop;
  76. else
  77. while(1)
  78. if(1) {
  79. // when the user uses break
  80. goto finished;
  81. }
  82. else
  83. while(1)
  84. if(!HT_next(obj, iter, &keyname, &valname)) {
  85. // normal termination
  86. goto finished;
  87. }
  88. else
  89. main_loop:
  90. // { user block; not in macro }
  91. */
  92. // pointer version
  93. #define SVEC__PASTE(a, b) CAT(a, b)
  94. #define SVEC__ITER(key, val) SVEC__PASTE(SVEC_iter_ ## key ## __ ## val ## __, __LINE__)
  95. #define SVEC__FINISHED(key, val) SVEC__PASTE(SVEC_finished__ ## key ## __ ## val ## __, __LINE__)
  96. #define SVEC__MAINLOOP(key, val) SVEC__PASTE(SVEC_main_loop__ ## key ## __ ## val ## __, __LINE__)
  97. #define SVEC_EACHP(obj, index, valname) \
  98. if(0) \
  99. SVEC__FINISHED(index, val): ; \
  100. else \
  101. for(typeof(*(obj)->chunks) valname ;;) \
  102. for(size_t index = 0;;) \
  103. if(index < SVEC_len(obj) && (valname = SVEC_itemp(obj, index), 1)) \
  104. goto SVEC__MAINLOOP(index, val); \
  105. else \
  106. while(1) \
  107. if(1) { \
  108. goto SVEC__FINISHED(index, val); \
  109. } \
  110. else \
  111. while(1) \
  112. if(++index >= SVEC_len(obj) || (valname = SVEC_itemp(obj, index), 0)) { \
  113. goto SVEC__FINISHED(index, val); \
  114. } \
  115. else \
  116. SVEC__MAINLOOP(index, val) :
  117. // { user block; not in macro }
  118. #endif // __sti__svec_h__