vec.c 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. // Public Domain.
  2. #include <stdlib.h> // realloc
  3. #include <string.h> // memcmp
  4. #include <stdio.h> // fprintf
  5. #include "vec.h"
  6. // super nifty site:
  7. // http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
  8. inline static size_t sti_vec_nextPOT(size_t in) {
  9. in--;
  10. in |= in >> 1;
  11. in |= in >> 2;
  12. in |= in >> 4;
  13. in |= in >> 8;
  14. in |= in >> 16;
  15. in++;
  16. return in;
  17. }
  18. void vec_resize_to(void** data, size_t* size, size_t elem_size, size_t new_size) {
  19. void* tmp;
  20. if(*size >= new_size) return;
  21. *size = sti_vec_nextPOT(new_size);
  22. tmp = realloc(*data, *size * elem_size);
  23. if(!tmp) {
  24. fprintf(stderr, "Out of memory in vector resize, %ld bytes requested\n", *size);
  25. return;
  26. }
  27. *data = tmp;
  28. }
  29. void vec_c_resize_to(void** data, size_t* size, size_t elem_size, size_t new_size) {
  30. void* tmp;
  31. if(*size >= new_size) return;
  32. size_t npot = sti_vec_nextPOT(new_size);
  33. tmp = realloc(*data, npot * elem_size);
  34. if(!tmp) {
  35. fprintf(stderr, "Out of memory in vector resize, %ld bytes requested\n", npot);
  36. return;
  37. }
  38. memset(tmp + *size * elem_size, 0, (npot - *size) * elem_size);
  39. *size = npot;
  40. *data = tmp;
  41. }
  42. void vec_resize(void** data, size_t* size, size_t elem_size) {
  43. void* tmp;
  44. if(*size < 8) *size = 8;
  45. else *size *= 2;
  46. tmp = realloc(*data, *size * elem_size);
  47. if(!tmp) {
  48. fprintf(stderr, "Out of memory in vector resize");
  49. return;
  50. }
  51. *data = tmp;
  52. }
  53. ptrdiff_t vec_find(void* data, size_t len, size_t stride, void* search) {
  54. size_t i;
  55. for(i = 0; i < len; i++) {
  56. if(0 == memcmp((char*)data + (i * stride), search, stride)) {
  57. return i;
  58. }
  59. }
  60. return -1;
  61. }
  62. ptrdiff_t vec_rm_val(char* data, size_t* len, size_t stride, void* search) {
  63. size_t i;
  64. for(i = 0; i < *len; i++) {
  65. if(0 == memcmp(data + (i * stride), search, stride)) {
  66. if(i < *len) {
  67. memcpy(data + (i * stride), data + ((*len - 1) * stride), stride);
  68. }
  69. (*len)--;
  70. return 0;
  71. }
  72. }
  73. return 1;
  74. }
  75. void vec_copy(
  76. char** dst_data, char* src_data,
  77. size_t* dst_alloc, size_t src_alloc,
  78. size_t* dst_len, size_t src_len,
  79. size_t elem_size
  80. ) {
  81. if(*dst_alloc < src_alloc) {
  82. *dst_alloc = src_alloc;
  83. if(*dst_data == 0) {
  84. *dst_data = malloc(elem_size * src_alloc);
  85. }
  86. else {
  87. *dst_data = realloc(*dst_data, elem_size * src_alloc);
  88. }
  89. }
  90. *dst_len = src_len;
  91. memcpy(*dst_data, src_data, elem_size * *dst_len);
  92. }
  93. // IMPORTANT: the vec is assumed to be sorted except the specified index
  94. ssize_t vec_bubble_index(void* data, size_t len, size_t stride, size_t index, int (*cmp)(const void*,const void*)) {
  95. #define signum(x) ((x > 0) - (x < 0))
  96. // find the destination index
  97. // TEMP: linear search for now
  98. ssize_t dst_index = index;
  99. if(len == 0) return -1;
  100. // there are three scenarios:
  101. // index is the first element, so only search forward.
  102. // index is the last element, so only search backward.
  103. // index is in the middle, so we need to decide which direction to go
  104. int direction;
  105. if(index == 0) {
  106. direction = 1;
  107. }
  108. else if(index >= len - 1) {
  109. direction = -1;
  110. }
  111. else {
  112. int res_p = cmp(data + ((index + 1) * stride), data + (index * stride));
  113. int res_m = cmp(data + ((index - 1) * stride), data + (index * stride));
  114. // if either is 0, index is properly sorted already
  115. if(res_p == 0 || res_m == 0) return index;
  116. if(res_p >= 0 && res_m <= 0) return index; // already sorted
  117. direction = res_p > 0 ? -1 : 1;
  118. }
  119. // dst_index += direction;
  120. do {
  121. dst_index += direction;
  122. int res = cmp(data + ((dst_index) * stride), data + (index * stride));
  123. if(res == 0 || signum(res) == direction) break;
  124. } while(dst_index > 0 && dst_index < len - 1);
  125. // TODO: sanity checks on degenerate moves
  126. void* tmp = alloca(stride);
  127. memcpy(tmp, data + (index * stride), stride);
  128. if(dst_index > index) { // move intermediate values backwards
  129. memmove(data + (index * stride), data + ((index + 1) * stride), stride * (dst_index - index));
  130. }
  131. else if(dst_index < index) { // move intermediate values forwards
  132. memmove(data + ((dst_index + 1) * stride), data + (dst_index * stride), stride * (index - dst_index));
  133. }
  134. else {
  135. // no move; already sorted
  136. }
  137. memcpy(data + (dst_index * stride), tmp, stride);
  138. return dst_index;
  139. }
  140. void vec_uniq(void* data, size_t* lenp, size_t stride, int (*cmp)(const void*,const void*)) {
  141. size_t read_index = 0;
  142. size_t write_index = 0;
  143. size_t len = *lenp;
  144. while(read_index < len) {
  145. memcpy(data + (write_index * stride), data + (read_index * stride), stride);
  146. do {
  147. read_index++;
  148. } while(read_index < len && 0 == cmp(data + (write_index * stride), data + (read_index * stride)));
  149. write_index++;
  150. }
  151. *lenp = write_index;
  152. }
  153. void vec_uniq_r(void* data, size_t* lenp, size_t stride, int (*cmp)(const void*,const void*,void*), void* arg) {
  154. size_t read_index = 0;
  155. size_t write_index = 0;
  156. size_t len = *lenp;
  157. while(read_index < len) {
  158. memcpy(data + (write_index * stride), data + (read_index * stride), stride);
  159. do {
  160. read_index++;
  161. } while(read_index < len && 0 == cmp(data + (write_index * stride), data + (read_index * stride), arg));
  162. write_index++;
  163. }
  164. *lenp = write_index;
  165. }