dlib.h (8368B)
1 #ifndef DLIB_H 2 #define DLIB_H 1 3 4 #include <assert.h> 5 #include <ctype.h> 6 #include <fcntl.h> 7 #include <limits.h> 8 #include <stdarg.h> 9 #include <stdio.h> 10 #include <stdbool.h> 11 #include <stdint.h> 12 #include <stdlib.h> 13 #include <errno.h> 14 #include <string.h> 15 #include <unistd.h> 16 17 #define unimplemented() \ 18 do { \ 19 fprintf(stderr, "%s:%i:1: Error: not implemented %s\n", __FILE__, __LINE__, __func__); \ 20 abort(); \ 21 } while (0) 22 23 #define pop_arg(argc, argv) ((argc)--, *(argv)++) 24 25 #define da_append(da, new)\ 26 do {\ 27 if ((da)->capacity <= (da)->count) {\ 28 (da)->capacity = (da)->capacity ? (da)->capacity * 2 : 16;\ 29 (da)->items = realloc((da)->items, sizeof(*(da)->items) * (da)->capacity);\ 30 }\ 31 (da)->items[(da)->count++] = (new);\ 32 } while(0) 33 34 #define da_prepend(da, new)\ 35 do {\ 36 if ((da)->capacity <= (da)->count) {\ 37 (da)->capacity = (da)->capacity ? (da)->capacity * 2 : 16;\ 38 (da)->items = realloc((da)->items, sizeof(*(da)->items) * (da)->capacity);\ 39 }\ 40 memmove((da)->items + 1, (da)->items, sizeof(*(da)->items) * ((da)->count++));\ 41 (da)->items[0] = (new);\ 42 } while(0) 43 44 #define da_reserve(da, len)\ 45 do {\ 46 if ((da)->capacity >= (len)) break;\ 47 (da)->capacity = (len);\ 48 (da)->items = realloc((da)->items, sizeof(*(da)->items) * (len));\ 49 } while(0) 50 51 #define da_expand(da, size)\ 52 do {\ 53 if ((da)->count >= (size)) break;\ 54 da_reserve(da, size);\ 55 (da)->count = (size);\ 56 } while(0) 57 58 #define da_delete(da, index)\ 59 do {\ 60 assert(index >= 0 && index < (da)->count);\ 61 (da)->items[index] = (da)->items[--(da)->count];\ 62 } while (0) 63 64 typedef struct { 65 union { 66 char *items; 67 const char *data; 68 }; 69 union { 70 ssize_t count; 71 ssize_t length; 72 }; 73 ssize_t capacity; 74 } Sb; 75 #define String_builder Sb 76 77 typedef struct { 78 union { 79 const char *items; 80 const char *data; 81 }; 82 union { 83 ssize_t count; 84 ssize_t length; 85 }; 86 } Sv; 87 #define String_view Sv 88 89 typedef struct { 90 void *base; 91 void *head; 92 void *end; 93 } Temp_allocator; 94 95 #define TA_DEFAULT_SIZE (1024*1024) 96 97 void ta_init(Temp_allocator *ta, size_t size); 98 void *ta_alloc(Temp_allocator *ta, size_t size); 99 100 #define sb_append_char da_append 101 void sb_printf(Sb *sb, const char *fmt, ...); 102 void sb_append_cstr(Sb *sb, const char *cstr); 103 void sb_append_sv(Sb *sb, Sv sv); 104 105 bool sb_read(Sb *sb, int fd); 106 bool sb_read_file(Sb *sb, const char *file_name); 107 void sb_write(int fd, Sb sb); 108 109 void sb_release(Sb *sb); 110 111 #define sv_literal(str) ((Sv){.items = (str), .count = (sizeof (str) - 1)}) 112 113 Sv sv_from_sb(Sb sb); 114 Sv sv_from_cstr(const char *cstr); 115 ssize_t sv_find_char(Sv sv, char c); 116 117 Sv sv_chop(Sv sv, ssize_t count, Sv *rest); 118 Sv sv_chop_delim(Sv sv, char c, Sv *rest); 119 120 Sv sv_getline(Sv *sv); 121 122 Sv sv_trim_left(Sv sv); 123 Sv sv_trim_right(Sv sv); 124 Sv sv_trim(Sv sv); 125 126 Sv sv_substring(Sv sv, ssize_t start, ssize_t req_count); 127 128 int sv_compare(Sv sv1, Sv sv2); 129 bool sv_equal(Sv sv1, Sv sv2); 130 bool sv_starts_with_cstr(Sv sv, const char *cstr); 131 132 void sv_write(int fd, Sv sv); 133 134 #ifdef DLIB_IMPLEMENTATION 135 136 void 137 ta_init(Temp_allocator *ta, size_t size) 138 { 139 ta->base = malloc(size); 140 ta->head = ta->base; 141 ta->end = ta->base + size; 142 } 143 144 void * 145 ta_alloc(Temp_allocator *ta, size_t size) 146 { 147 if (!ta->base) { 148 ta->base = malloc(TA_DEFAULT_SIZE); 149 ta->head = ta->base; 150 ta->end = ta->base + TA_DEFAULT_SIZE; 151 } 152 void *result = ta->head; 153 ta->head += (size + 0xF) & ~0xFul; 154 if (ta->head >= ta->end) { 155 fprintf(stderr, "Error: Temp allocator out of memory\n"); 156 exit(1); 157 } 158 return result; 159 } 160 161 void 162 sb_printf(Sb *sb, const char *fmt, ...) { 163 va_list args, args_copy; 164 va_start(args, fmt); 165 va_copy(args_copy, args); 166 int len = vsnprintf(NULL, 0, fmt, args_copy) + 1; 167 ssize_t new_size = sb->count + len; 168 da_reserve(sb, new_size); 169 va_end(args_copy); 170 vsnprintf(sb->items + sb->count, len, fmt, args); 171 va_end(args); 172 sb->count = new_size - 1; 173 } 174 175 void 176 sb_append_cstr(Sb *sb, const char *cstr) 177 { 178 ssize_t len = strlen(cstr); 179 da_reserve(sb, sb->count + len); 180 strcpy(sb->items + sb->count, cstr); 181 sb->count += len; 182 } 183 184 void 185 sb_append_sv(Sb *sb, Sv sv) 186 { 187 da_reserve(sb, sb->count + sv.count); 188 memcpy(sb->items + sb->count, sv.items, sv.count); 189 sb->count += sv.count; 190 } 191 192 bool 193 sb_read(Sb *sb, int fd) 194 { 195 ssize_t read_count; 196 ssize_t buf_size = 4096; 197 char *buf = malloc(buf_size); 198 do { 199 read_count = read(fd, buf, buf_size); 200 if (read_count < 0) { 201 if (errno == EINTR) { 202 continue; 203 } 204 perror("sb_read()"); 205 return false; 206 } 207 if (read_count == 0) { 208 break; 209 } 210 sb_append_sv(sb, ((Sv) {.items = buf, .length = read_count})); 211 if (read_count < buf_size) { 212 break; 213 } 214 } while (1); 215 free(buf); 216 return true; 217 } 218 219 bool 220 sb_read_file(Sb *sb, const char *file_name) 221 { 222 int fd = open(file_name, O_RDONLY); 223 if (fd < 0) { 224 perror("sb_read()"); 225 return false; 226 } 227 ssize_t read_count; 228 ssize_t buf_size = 4096; 229 char *buf = malloc(buf_size); 230 do { 231 read_count = read(fd, buf, buf_size); 232 if (read_count < 0) { 233 if (errno == EINTR) { 234 continue; 235 } 236 perror("sb_read_file()"); 237 return false; 238 } 239 if (read_count == 0) { 240 break; 241 } 242 sb_append_sv(sb, ((Sv) {.items = buf, .length = read_count})); 243 } while (1); 244 free(buf); 245 return true; 246 } 247 248 void 249 sb_write(int fd, Sb sb) 250 { 251 write(fd, sb.items, sb.length); 252 } 253 254 void 255 sb_release(Sb *sb) 256 { 257 if (sb->capacity) { 258 free(sb->items); 259 sb->items = NULL; 260 sb->count = 0; 261 sb->capacity = 0; 262 } 263 } 264 265 /* String view functions */ 266 267 void 268 sv_write(int fd, Sv sv) 269 { 270 write(fd, sv.items, sv.count); 271 } 272 273 Sv 274 sv_from_sb(Sb sb) 275 { 276 return (Sv) {.items = sb.items, .count = sb.count}; 277 } 278 279 Sv 280 sv_from_cstr(const char *cstr) 281 { 282 return (Sv) {.items = cstr, .count = strlen(cstr)}; 283 } 284 285 ssize_t 286 sv_find_char(Sv sv, char c) 287 { 288 ssize_t pos = 0; 289 while (sv.count > pos && sv.items[pos] != c) 290 pos++; 291 for (pos = 0; pos < sv.count && sv.items[pos] != c; pos++); 292 return pos < sv.count ? pos : -1; 293 } 294 295 Sv 296 sv_chop_delim(Sv sv, char c, Sv *rest) 297 { 298 ssize_t pos = sv_find_char(sv, c); 299 Sv res = sv; 300 if (pos > 0) { 301 res.count = pos; 302 303 rest->count -= pos + 1; 304 rest->items += pos + 1; 305 } 306 return res; 307 } 308 309 Sv 310 sv_chop(Sv sv, ssize_t count, Sv *rest) 311 { 312 Sv left = {0}; 313 ssize_t lcount, rcount; 314 if (count > sv.count) { 315 lcount = sv.count; 316 rcount = 0; 317 } else if (-count > sv.count) { 318 lcount = 0; 319 rcount = sv.count; 320 } else if (count < 0) { 321 lcount = sv.count + count; 322 rcount = -count; 323 } else { 324 lcount = count; 325 rcount = sv.count - count; 326 } 327 left.items = sv.items; 328 left.count = lcount; 329 if (rest) { 330 rest->items = sv.items + lcount; 331 rest->count = rcount; 332 } 333 return left; 334 } 335 336 Sv 337 sv_trim_left(Sv sv) 338 { 339 while (sv.count && isspace(sv.items[0])) { 340 sv.count--; 341 sv.items++; 342 } 343 return sv; 344 } 345 346 Sv 347 sv_trim_right(Sv sv) 348 { 349 while (sv.count && isspace(sv.items[sv.count - 1])) { 350 sv.count--; 351 } 352 return sv; 353 } 354 355 Sv 356 sv_trim(Sv sv) 357 { 358 return sv_trim_right(sv_trim_left(sv)); 359 } 360 361 Sv 362 sv_substring(Sv sv, ssize_t start, ssize_t req_count) 363 { 364 Sv ss = {0}; 365 if (start >= sv.count) return ss; 366 ss.count = (req_count < sv.count - start) ? req_count : sv.count - start; 367 ss.items = sv.items + start; 368 return ss; 369 } 370 371 int 372 sv_compare(Sv sv1, Sv sv2) 373 { 374 if (sv1.items == sv2.items && sv1.count == sv2.count) return 0; 375 signed char diff; 376 ssize_t pos; 377 for (pos = 0; pos < sv1.count; pos++) { 378 if (pos == sv2.count) return 1; 379 if ((diff = sv1.items[pos] - sv2.items[pos])) return diff; 380 } 381 return pos < sv2.count ? -1 : 0; 382 } 383 384 bool 385 sv_equal(Sv sv1, Sv sv2) 386 { 387 if (sv1.count != sv2.count) return false; 388 if (sv1.items == sv2.items) return true; 389 ssize_t pos; 390 for (pos = 0; pos < sv1.count && sv1.items[pos] == sv2.items[pos]; pos++); 391 return pos == sv1.count; 392 } 393 394 bool 395 sv_starts_with_cstr(Sv sv, const char *cstr) 396 { 397 size_t cstr_len = strlen(cstr); 398 assert(cstr_len <= SSIZE_MAX); 399 if (sv.count < (ssize_t) cstr_len) return false; 400 ssize_t pos; 401 for (pos = 0; pos < (ssize_t) cstr_len && sv.items[pos] == cstr[pos]; pos++); 402 return pos == (ssize_t) cstr_len; 403 } 404 405 Sv 406 sv_getline(Sv *sv) 407 { 408 Sv line = sv_chop_delim(*sv, '\n', sv); 409 if (line.count && line.items[line.count - 1] == '\r') { 410 line.count--; 411 } 412 return line; 413 } 414 415 #endif // DLIB_IMPLEMENTATION 416 417 #endif // DLIB_H