ded

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