sv.h 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. // Copyright 2021 Alexey Kutepov <[email protected]>
  2. // Permission is hereby granted, free of charge, to any person obtaining
  3. // a copy of this software and associated documentation files (the
  4. // "Software"), to deal in the Software without restriction, including
  5. // without limitation the rights to use, copy, modify, merge, publish,
  6. // distribute, sublicense, and/or sell copies of the Software, and to
  7. // permit persons to whom the Software is furnished to do so, subject to
  8. // the following conditions:
  9. // The above copyright notice and this permission notice shall be
  10. // included in all copies or substantial portions of the Software.
  11. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  12. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  13. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  14. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  15. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  16. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  17. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  18. #ifndef SV_H_
  19. #define SV_H_
  20. #include <stdint.h>
  21. #include <stdlib.h>
  22. #include <stdbool.h>
  23. #include <string.h>
  24. #include <ctype.h>
  25. #ifndef SVDEF
  26. #define SVDEF
  27. #endif // SVDEF
  28. typedef struct {
  29. size_t count;
  30. const char *data;
  31. } String_View;
  32. #define SV(cstr_lit) sv_from_parts(cstr_lit, sizeof(cstr_lit) - 1)
  33. #define SV_STATIC(cstr_lit) \
  34. { \
  35. sizeof(cstr_lit) - 1, \
  36. (cstr_lit) \
  37. }
  38. #define SV_NULL sv_from_parts(NULL, 0)
  39. // printf macros for String_View
  40. #define SV_Fmt "%.*s"
  41. #define SV_Arg(sv) (int) (sv).count, (sv).data
  42. // USAGE:
  43. // String_View name = ...;
  44. // printf("Name: "SV_Fmt"\n", SV_Arg(name));
  45. SVDEF String_View sv_from_parts(const char *data, size_t count);
  46. SVDEF String_View sv_from_cstr(const char *cstr);
  47. SVDEF String_View sv_trim_left(String_View sv);
  48. SVDEF String_View sv_trim_right(String_View sv);
  49. SVDEF String_View sv_trim(String_View sv);
  50. SVDEF String_View sv_take_left_while(String_View sv, bool (*predicate)(char x));
  51. SVDEF String_View sv_chop_by_delim(String_View *sv, char delim);
  52. SVDEF String_View sv_chop_by_sv(String_View *sv, String_View thicc_delim);
  53. SVDEF bool sv_try_chop_by_delim(String_View *sv, char delim, String_View *chunk);
  54. SVDEF String_View sv_chop_left(String_View *sv, size_t n);
  55. SVDEF String_View sv_chop_right(String_View *sv, size_t n);
  56. SVDEF String_View sv_chop_left_while(String_View *sv, bool (*predicate)(char x));
  57. SVDEF bool sv_index_of(String_View sv, char c, size_t *index);
  58. SVDEF bool sv_eq(String_View a, String_View b);
  59. SVDEF bool sv_eq_ignorecase(String_View a, String_View b);
  60. SVDEF bool sv_starts_with(String_View sv, String_View prefix);
  61. SVDEF bool sv_ends_with(String_View sv, String_View suffix);
  62. SVDEF uint64_t sv_to_u64(String_View sv);
  63. #endif // SV_H_
  64. #ifdef SV_IMPLEMENTATION
  65. SVDEF String_View sv_from_parts(const char *data, size_t count)
  66. {
  67. String_View sv;
  68. sv.count = count;
  69. sv.data = data;
  70. return sv;
  71. }
  72. SVDEF String_View sv_from_cstr(const char *cstr)
  73. {
  74. return sv_from_parts(cstr, strlen(cstr));
  75. }
  76. SVDEF String_View sv_trim_left(String_View sv)
  77. {
  78. size_t i = 0;
  79. while (i < sv.count && isspace(sv.data[i])) {
  80. i += 1;
  81. }
  82. return sv_from_parts(sv.data + i, sv.count - i);
  83. }
  84. SVDEF String_View sv_trim_right(String_View sv)
  85. {
  86. size_t i = 0;
  87. while (i < sv.count && isspace(sv.data[sv.count - 1 - i])) {
  88. i += 1;
  89. }
  90. return sv_from_parts(sv.data, sv.count - i);
  91. }
  92. SVDEF String_View sv_trim(String_View sv)
  93. {
  94. return sv_trim_right(sv_trim_left(sv));
  95. }
  96. SVDEF String_View sv_chop_left(String_View *sv, size_t n)
  97. {
  98. if (n > sv->count) {
  99. n = sv->count;
  100. }
  101. String_View result = sv_from_parts(sv->data, n);
  102. sv->data += n;
  103. sv->count -= n;
  104. return result;
  105. }
  106. SVDEF String_View sv_chop_right(String_View *sv, size_t n)
  107. {
  108. if (n > sv->count) {
  109. n = sv->count;
  110. }
  111. String_View result = sv_from_parts(sv->data + sv->count - n, n);
  112. sv->count -= n;
  113. return result;
  114. }
  115. SVDEF bool sv_index_of(String_View sv, char c, size_t *index)
  116. {
  117. size_t i = 0;
  118. while (i < sv.count && sv.data[i] != c) {
  119. i += 1;
  120. }
  121. if (i < sv.count) {
  122. if (index) {
  123. *index = i;
  124. }
  125. return true;
  126. } else {
  127. return false;
  128. }
  129. }
  130. SVDEF bool sv_try_chop_by_delim(String_View *sv, char delim, String_View *chunk)
  131. {
  132. size_t i = 0;
  133. while (i < sv->count && sv->data[i] != delim) {
  134. i += 1;
  135. }
  136. String_View result = sv_from_parts(sv->data, i);
  137. if (i < sv->count) {
  138. sv->count -= i + 1;
  139. sv->data += i + 1;
  140. if (chunk) {
  141. *chunk = result;
  142. }
  143. return true;
  144. }
  145. return false;
  146. }
  147. SVDEF String_View sv_chop_by_delim(String_View *sv, char delim)
  148. {
  149. size_t i = 0;
  150. while (i < sv->count && sv->data[i] != delim) {
  151. i += 1;
  152. }
  153. String_View result = sv_from_parts(sv->data, i);
  154. if (i < sv->count) {
  155. sv->count -= i + 1;
  156. sv->data += i + 1;
  157. } else {
  158. sv->count -= i;
  159. sv->data += i;
  160. }
  161. return result;
  162. }
  163. SVDEF String_View sv_chop_by_sv(String_View *sv, String_View thicc_delim)
  164. {
  165. String_View window = sv_from_parts(sv->data, thicc_delim.count);
  166. size_t i = 0;
  167. while (i + thicc_delim.count < sv->count
  168. && !(sv_eq(window, thicc_delim)))
  169. {
  170. i++;
  171. window.data++;
  172. }
  173. String_View result = sv_from_parts(sv->data, i);
  174. if (i + thicc_delim.count == sv->count) {
  175. // include last <thicc_delim.count> characters if they aren't
  176. // equal to thicc_delim
  177. result.count += thicc_delim.count;
  178. }
  179. // Chop!
  180. sv->data += i + thicc_delim.count;
  181. sv->count -= i + thicc_delim.count;
  182. return result;
  183. }
  184. SVDEF bool sv_starts_with(String_View sv, String_View expected_prefix)
  185. {
  186. if (expected_prefix.count <= sv.count) {
  187. String_View actual_prefix = sv_from_parts(sv.data, expected_prefix.count);
  188. return sv_eq(expected_prefix, actual_prefix);
  189. }
  190. return false;
  191. }
  192. SVDEF bool sv_ends_with(String_View sv, String_View expected_suffix)
  193. {
  194. if (expected_suffix.count <= sv.count) {
  195. String_View actual_suffix = sv_from_parts(sv.data + sv.count - expected_suffix.count, expected_suffix.count);
  196. return sv_eq(expected_suffix, actual_suffix);
  197. }
  198. return false;
  199. }
  200. SVDEF bool sv_eq(String_View a, String_View b)
  201. {
  202. if (a.count != b.count) {
  203. return false;
  204. } else {
  205. return memcmp(a.data, b.data, a.count) == 0;
  206. }
  207. }
  208. SVDEF bool sv_eq_ignorecase(String_View a, String_View b)
  209. {
  210. if (a.count != b.count) {
  211. return false;
  212. }
  213. char x, y;
  214. for (size_t i = 0; i < a.count; i++) {
  215. x = 'A' <= a.data[i] && a.data[i] <= 'Z'
  216. ? a.data[i] + 32
  217. : a.data[i];
  218. y = 'A' <= b.data[i] && b.data[i] <= 'Z'
  219. ? b.data[i] + 32
  220. : b.data[i];
  221. if (x != y) return false;
  222. }
  223. return true;
  224. }
  225. SVDEF uint64_t sv_to_u64(String_View sv)
  226. {
  227. uint64_t result = 0;
  228. for (size_t i = 0; i < sv.count && isdigit(sv.data[i]); ++i) {
  229. result = result * 10 + (uint64_t) sv.data[i] - '0';
  230. }
  231. return result;
  232. }
  233. SVDEF String_View sv_chop_left_while(String_View *sv, bool (*predicate)(char x))
  234. {
  235. size_t i = 0;
  236. while (i < sv->count && predicate(sv->data[i])) {
  237. i += 1;
  238. }
  239. return sv_chop_left(sv, i);
  240. }
  241. SVDEF String_View sv_take_left_while(String_View sv, bool (*predicate)(char x))
  242. {
  243. size_t i = 0;
  244. while (i < sv.count && predicate(sv.data[i])) {
  245. i += 1;
  246. }
  247. return sv_from_parts(sv.data, i);
  248. }
  249. #endif // SV_IMPLEMENTATION