changed author email
[guish.git] / src / cutils.h
blob67af8b3272bd5e5e31ffc0aba37c03fdecf17103
1 /************************************************************************
2 * Copyright (C) 2024 Francesco Palumbo <phranz.dev@gmail.com>, Naples Italy
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <https://www.gnu.org/licenses/>.
16 *************************************************************************/
18 #ifndef CUTILS_H
19 #define CUTILS_H
21 #define CUTILS_VERSION "0.2.1"
23 #include <stdio.h>
24 #include <stdarg.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <sys/stat.h>
29 #if defined(__linux__)
30 #include <sys/sysmacros.h>
31 #else
32 #include <sys/types.h>
33 #endif
36 * Equivalent to p->func(p, a, b)
38 #define __(p, f, ...) (p->f(p, ## __VA_ARGS__))
41 * Allocate memory for a type (calls type's _init)
43 * t: type
44 * ...: additional params
46 #define alloc(t, ...) (t ## _init(malloc(sizeof(t)), ## __VA_ARGS__))
50 * Release memory hold by type's instance (calls ptr's free)
52 * p: type pointer
54 #define release(p) (p ? (p->free(p), (p=NULL)) : NULL)
57 * Utility to call free and setting pointer to NULL
59 * p: type pointer
61 #define zfree(p) (free(p), (p=NULL))
64 * Declare a vector of a specific type
66 * t: contained type
67 * n: new type name
69 #define dectype_vector(t, n) \
70 typedef struct n { \
71 t* data; \
72 const size_t count; \
73 void (*free)(struct n*); \
74 int (*push)(struct n*, t); \
75 int (*push_back)(struct n*, t); \
76 int (*pop)(struct n*, t*); \
77 int (*pop_back)(struct n*, t*); \
78 int (*get)(struct n*, size_t, t*); \
79 int (*first)(struct n*, t*); \
80 int (*last)(struct n*, t*); \
81 int (*put)(struct n*, size_t, t); \
82 int (*insert)(struct n*, size_t, t); \
83 int (*remove)(struct n*, size_t); \
84 void (*clear)(struct n*); \
85 } n; \
86 n* n ## _init(n*);
88 #define define_vector(t, n) \
90 * Add an element to the end of a vector
92 * p: vector pointer
93 * v: a value of type t
95 * return: boolean operation success/failure
96 */ \
97 static int n ## _push(n* p, t v) { \
98 if (!(p->count+1)) \
99 return 0; \
100 t* mem = realloc(p->data, sizeof(t)*(p->count+1)); \
101 if (mem) { \
102 p->data = mem; \
103 mem[p->count] = v; \
104 } else { \
105 return 0; \
107 ++*(size_t*)&p->count; \
108 return 1; \
111 * Add an element to the beginning of a vector
113 * p: vector pointer
114 * v (output): a value of type t
116 * return: boolean operation success/failure
117 */ \
118 static int n ## _push_back(n* p, t v) { \
119 return p->insert(p, 0, v); \
122 * Get and remove the last element of a vector
124 * p: vector pointer
125 * v (output): a pointer of type t
127 * return: boolean operation success/failure
128 */ \
129 static int n ## _pop(n* p, t* v) { \
130 if (!p->count || !v) \
131 return 0; \
132 if (!p->data) \
133 return 1; \
134 *v = p->data[p->count-1]; \
135 if (!(p->count-1)) { \
136 free(p->data); \
137 p->data = NULL; \
138 } else { \
139 t* mem = realloc(p->data, sizeof(t)*(p->count-1)); \
140 if (mem) \
141 p->data = mem; \
142 else \
143 return 0; \
145 --*(size_t*)&p->count; \
146 return 1; \
149 * Get and remove the first element of a vector
151 * p: vector pointer
152 * v (output): a pointer of type t
154 * return: boolean operation success/failure
155 */ \
156 static int n ## _pop_back(n* p, t* v) { \
157 if (!p->count || !v) \
158 return 0; \
159 *v = p->data[0]; \
160 if (!(p->count-1)) { \
161 free(p->data); \
162 p->data = NULL; \
163 --*(size_t*)&p->count; \
164 return 1; \
166 for (size_t x=0; x+1<p->count; ++x) \
167 p->data[x] = p->data[x+1]; \
168 t* mem = realloc(p->data, sizeof(t)*(p->count-1)); \
169 if (mem) \
170 p->data = mem; \
171 else \
172 return 0; \
173 --*(size_t*)&p->count; \
174 return 1; \
177 * Get a vector element by index
179 * p: vector pointer
180 * i: index
181 * v (output): a pointer of type t
183 * return: boolean operation success/failure
184 */ \
185 static int n ## _get(n* p, size_t i, t* v) { \
186 if (!p->count || i>p->count-1 || !v) \
187 return 0; \
188 *v = p->data[i]; \
189 return 1; \
192 * Get the first element of a vector
194 * p: vector pointer
195 * v (output): a pointer of type t
197 * return: boolean operation success/failure
198 */ \
199 static int n ## _first(n* p, t* v) { \
200 if (!p->count || !v) \
201 return 0; \
202 *v = p->data[0]; \
203 return 1; \
206 * Get the last element of a vector
208 * p: vector pointer
209 * v (output): a pointer of type t
211 * return: boolean operation success/failure
212 */ \
213 static int n ## _last(n* p, t* v) { \
214 if (!p->count || !v) \
215 return 0; \
216 *v = p->data[p->count-1]; \
217 return 1; \
220 * Change the value of a vector by index
222 * p: vector pointer
223 * i: index
224 * v: a value of type t
226 * return: boolean operation success/failure
227 */ \
228 static int n ## _put(n* p, size_t i, t v) { \
229 if (!p->count || i>p->count-1) \
230 return 0; \
231 p->data[i] = v; \
232 return 1; \
235 * Remove a vector element by index
237 * p: vector pointer
238 * i: index
240 * return: boolean operation success/failure
241 */ \
242 static int n ## _remove(n* p, size_t i) { \
243 if (!p->count) \
244 return 1; \
245 if (i>p->count-1) \
246 return 0; \
247 t l = p->data[p->count-1]; \
248 if (!(p->count-1)) { \
249 free(p->data); \
250 p->data = NULL; \
251 --*(size_t*)&p->count; \
252 return 1; \
254 t* mem = realloc(p->data, sizeof(t)*(p->count-1)); \
255 if (mem) \
256 p->data = mem; \
257 else \
258 return 0; \
259 --*(size_t*)&p->count; \
260 for (size_t x=i; x+1<p->count; ++x) \
261 p->data[x] = p->data[x+1]; \
262 if (i != p->count) \
263 p->data[p->count-1] = l; \
264 return 1; \
267 * Insert an element at index
269 * p: vector pointer
270 * i: index
271 * v: a value of type t
273 * return: boolean operation success/failure
274 */ \
275 static int n ## _insert(n* p, size_t i, t v) { \
276 if (i>p->count || !(p->count+1)) \
277 return 0; \
278 t* mem = realloc(p->data, sizeof(t)*(p->count+1)); \
279 if (mem) \
280 p->data = mem; \
281 else \
282 return 0; \
284 if (i != p->count) { \
285 p->data[p->count] = p->data[p->count-1]; \
286 for (size_t x=p->count; x!=i; --x) \
287 p->data[x] = p->data[x-1]; \
289 p->data[i] = v; \
290 ++*(size_t*)&p->count; \
291 return 1; \
294 * Remove all elements from a vector
296 * p: vector pointer
297 */ \
298 static void n ## _clear(n* p) { \
299 *(size_t*)&p->count = 0; \
300 free(p->data); \
301 p->data = NULL; \
304 * Release vector's resources
306 * p: vector pointer
307 */ \
308 static void n ## _free(n* p) { \
309 n ## _clear(p); \
310 free(p); \
313 * Initialize vector's resources
315 * p: vector pointer
316 */ \
317 n* n ## _init(n* p) { \
318 if (!p) \
319 return NULL; \
320 memset(p, 0, sizeof(*p)); \
321 p->push = n ## _push; \
322 p->push_back = n ## _push_back; \
323 p->pop = n ## _pop; \
324 p->pop_back = n ## _pop_back; \
325 p->put = n ## _put; \
326 p->get = n ## _get; \
327 p->first = n ## _first; \
328 p->last = n ## _last; \
329 p->remove = n ## _remove; \
330 p->insert = n ## _insert; \
331 p->clear = n ## _clear; \
332 p->free = n ## _free; \
333 return p; \
338 * Declare a list of a specific type
340 * t: contained type
341 * n: new type name
343 #define dectype_list(t, n) \
344 typedef struct __node_ ## n { \
345 struct __node_ ## n* prev; \
346 struct __node_ ## n* next; \
347 t data; \
348 } __node_ ## n; \
349 dectype_pair(size_t, __node_ ## n*, __cached_node_ ## n) \
350 typedef struct n { \
351 __node_ ## n* head; \
352 __node_ ## n* tail; \
353 __cached_node_ ## n cached; \
354 size_t count; \
355 void (*free)(struct n*); \
356 int (*push)(struct n*, t); \
357 int (*push_back)(struct n*, t); \
358 int (*put)(struct n*, size_t, t); \
359 int (*insert)(struct n*, size_t, t); \
360 int (*pop)(struct n*, t*); \
361 int (*pop_back)(struct n*, t*); \
362 int (*get)(struct n*, size_t, t*); \
363 int (*first)(struct n*, t*); \
364 int (*last)(struct n*, t*); \
365 int (*remove)(struct n*, size_t); \
366 void (*clear)(struct n*); \
367 } n; \
368 n* n ## _init(n*);
370 #define define_list(t, n) \
371 static int __ ## n ## _htalloc(n* p) { \
372 p->head = calloc(1, sizeof(__node_ ## n)); \
373 if (!p->head) \
374 return 0; \
375 p->head->next = NULL; \
376 p->head->prev = NULL; \
377 p->tail = p->head; \
378 return 1; \
380 static int __ ## n ## _talloc(n* p) { \
381 __node_ ## n* node = calloc(1, sizeof(__node_ ## n)); \
382 if (!node) \
383 return 0; \
384 p->tail->next = node; \
385 node->prev = p->tail; \
386 node->next = NULL; \
387 p->tail = node; \
388 return 1; \
391 * Add an element to the end of a list
393 * p: list pointer
394 * v: a value of type t
396 * return: boolean operation success/failure
397 */ \
398 static int n ## _push(n* p, t v) { \
399 if (!p->head || !p->tail) { \
400 if (!__ ## n ## _htalloc(p)) \
401 return 0; \
402 p->head->data = v; \
403 p->cached.val = p->head; \
404 } else { \
405 if (!(p->count+1)) \
406 return 0; \
407 if(!__ ## n ## _talloc(p)) \
408 return 0; \
409 p->tail->data = v; \
410 p->cached.val = p->tail; \
412 ++*(size_t*)&p->count; \
413 p->cached.key = p->count-1; \
414 return 1; \
417 * Add an element to the beginning of a list
419 * p: list pointer
420 * v: a value of type t
422 * return: boolean operation success/failure
423 */ \
424 static int n ## _push_back(n* p, t v) { \
425 return p->insert(p, 0, v); \
428 * Insert an element at index
430 * p: list pointer
431 * i: index
432 * v: a value of type t
434 * return: boolean operation success/failure
435 */ \
436 static int n ## _insert(n* p, size_t i, t v) { \
437 if (i>p->count || !(p->count+1)) \
438 return 0; \
439 if (i == p->count) \
440 return p->push(p, v); \
441 __node_ ## n* node = calloc(1, sizeof(__node_ ## n)); \
442 if (!node) \
443 return 0; \
444 if (!i) { \
445 node->prev = NULL; \
446 node->next = p->head; \
447 p->head->prev = node; \
448 p->head = node; \
449 node->data = v; \
450 } else { \
451 __node_ ## n* c = p->head; \
452 size_t j = 0; \
453 if (p->cached.key >= i && p->cached.val) { \
454 c = p->cached.val; \
455 j = p->cached.key; \
457 for (; j!=i; ++j, c=c->next); \
458 node->prev = c->prev; \
459 node->next = c; \
460 c->prev->next = node; \
461 c->prev = node; \
462 node->data = v; \
464 ++*(size_t*)&p->count; \
465 p->cached.key = i; \
466 p->cached.val = node; \
467 return 1; \
470 * Change the value of a list by index
472 * p: list pointer
473 * i: index
474 * v: a value of type t
476 * return: boolean operation success/failure
477 */ \
478 static int n ## _put(n* p, size_t i, t v) { \
479 if (i >= p->count) \
480 return 0; \
481 if (p->cached.key == i && p->cached.val) { \
482 p->cached.val->data = v; \
483 return 1; \
485 __node_ ## n* c = p->head; \
486 if (i == p->count-1) \
487 c = p->tail; \
488 else \
489 for (size_t j=0; j!=i && c->next; ++j, c=c->next); \
490 c->data = v; \
491 p->cached.key = i; \
492 p->cached.val = c; \
493 return 1; \
496 * Get and remove the last element of a list
498 * p: list pointer
499 * v (output): a pointer of type t
501 * return: boolean operation success/failure
502 */ \
503 static int n ## _pop(n* p, t* v) { \
504 if (!p->tail || !v) \
505 return 0; \
506 __node_ ## n* tofree = p->tail; \
507 *v = p->tail->data; \
508 if (p->tail->prev) { \
509 p->tail->prev->next = NULL; \
510 p->tail = p->tail->prev; \
511 } else { \
512 p->head = p->tail = NULL; \
514 free(tofree); \
515 --*(size_t*)&p->count; \
516 if (p->count) { \
517 p->cached.key = p->count-1; \
518 p->cached.val = p->tail; \
519 } else { \
520 memset(&p->cached, 0, sizeof(p->cached)); \
522 return 1; \
525 * Get and remove the first element of a list
527 * p: vector list
528 * v (output): a pointer of type t
530 * return: boolean operation success/failure
531 */ \
532 static int n ## _pop_back(n* p, t* v) { \
533 if (!p->count || !v) \
534 return 0; \
535 if (p->get(p, 0, v)) { \
536 p->remove(p, 0); \
537 memset(&p->cached, 0, sizeof(p->cached)); \
539 return 1; \
542 * Get a list element by index
544 * p: list pointer
545 * i: index
546 * v (output): a pointer of type t
548 * return: boolean operation success/failure
549 */ \
550 static int n ## _get(n* p, size_t i, t* v) { \
551 if (!p->count || !v || i>=p->count) \
552 return 0; \
553 if (i<p->count && p->cached.key == i && p->cached.val) { \
554 *v = p->cached.val->data; \
555 return 1; \
557 __node_ ## n* c = p->head; \
558 size_t j = 0; \
559 if (p->cached.key < i && p->cached.val) { \
560 j = p->cached.key; \
561 c = p->cached.val; \
563 for (; j!=i && c; ++j) \
564 c = c->next; \
565 p->cached.key = i; \
566 p->cached.val = c; \
567 *v = c->data; \
568 return 1; \
571 * Get the first element of a list
573 * p: list pointer
574 * v (output): a pointer of type t
576 * return: boolean operation success/failure
577 */ \
578 static int n ## _first(n* p, t* v) { \
579 if (!p->count || !v) \
580 return 0; \
581 *v = p->head->data; \
582 return 1; \
585 * Get the last element of a list
587 * p: list pointer
588 * v (output): a pointer of type t
590 * return: boolean operation success/failure
591 */ \
592 static int n ## _last(n* p, t* v) { \
593 if (!p->count || !v) \
594 return 0; \
595 *v = p->tail->data; \
596 return 1; \
599 * Remove a list element by index
601 * p: list pointer
602 * i: index
604 * return: boolean operation success/failure
605 */ \
606 static int n ## _remove(n* p, size_t i) { \
607 if (!p->count) \
608 return 1; \
609 if (i>=p->count) \
610 return 0; \
611 if (p->cached.key <= i) \
612 memset(&p->cached, 0, sizeof(p->cached)); \
613 __node_ ## n* c = p->head; \
614 for (size_t j=0; j!=i; ++j) \
615 c = c->next; \
616 if ((c == p->head) && (c == p->tail)) { \
617 p->head = p->tail = NULL; \
618 } else if (c == p->head) { \
619 c->next->prev = NULL; \
620 p->head = c->next; \
621 } else if (c == p->tail) { \
622 c->prev->next = NULL; \
623 p->tail = c->prev; \
624 } else { \
625 c->next->prev = c->prev; \
626 c->prev->next = c->next; \
628 free(c); \
629 --*(size_t*)&p->count; \
630 return 1; \
633 * Remove all elements from a list
635 * p: list pointer
636 */ \
637 static void n ## _clear(n* p) { \
638 if (!p->count) \
639 return; \
640 __node_ ## n* i = p->head; \
641 __node_ ## n* j; \
642 do { \
643 j = i->next; \
644 free(i); \
645 i = j; \
646 } while (i); \
647 *(size_t*)&p->count = 0; \
648 p->head = p->tail = NULL; \
649 memset(&p->cached, 0, sizeof(p->cached)); \
652 * Release list's resources
654 * p: list pointer
655 */ \
656 static void n ## _free(n* p) { \
657 n ## _clear(p); \
658 free(p); \
661 * Initialize list's resources
663 * p: list pointer
664 */ \
665 n* n ## _init(n* p) { \
666 if (!p) \
667 return NULL; \
668 memset(p, 0, sizeof(*p)); \
669 p->push = n ## _push; \
670 p->push_back = n ## _push_back; \
671 p->put = n ## _put; \
672 p->insert = n ## _insert; \
673 p->pop = n ## _pop; \
674 p->pop_back = n ## _pop_back; \
675 p->get = n ## _get; \
676 p->first = n ## _first; \
677 p->last = n ## _last; \
678 p->remove = n ## _remove; \
679 p->clear = n ## _clear; \
680 p->free = n ## _free; \
681 return p; \
685 * Declare a pair of specific types.
687 * t1: key type
688 * t2: value type
689 * n: new type name
691 #define dectype_pair(t1, t2, n) \
692 typedef struct n { \
693 t1 key; \
694 t2 val; \
695 void (*free)(struct n*); \
696 } n; \
697 n* n ## _init(struct n*);
699 #define define_pair(t1, t2, n) \
700 static void n ## _free(struct n* p) { \
701 free(p); \
703 n* n ## _init(struct n* p) { \
704 if (!p) \
705 return NULL; \
706 memset(p, 0, sizeof(*p)); \
707 p->free = n ## _free; \
708 return p; \
712 * Initial number of elements of a map
714 #ifndef MAPSIZE
715 #define MAPSIZE 47U
716 #endif
719 * Default load factor
721 #ifndef LFACTOR
722 #define LFACTOR 0.75
723 #endif
726 * Declare a map of a specific type.
727 * By default pointers/values are hashed,
728 * not whole strings; to change this behaviour
729 * and use strings (for maps that have strings
730 * as keys), set strcmp field to 1:
731 * es. p->strcmp = 1;
733 * t1: key type
734 * t2: value type
735 * n: new type name
737 #define dectype_map(t1, t2, n) \
738 dectype_pair(t1, t2, __pair_ ## n) \
739 dectype_list(__pair_ ## n*, __bucket_ ## n) \
740 dectype_vector(__pair_ ## n*, __items_ ## n) \
741 dectype_vector(__bucket_ ## n*, __vec_ ## n) \
742 typedef struct n { \
743 __vec_ ## n* data; \
744 __pair_ ## n* cached; \
745 __bucket_ ## n* r; \
746 int strcmp; \
747 size_t count; \
748 size_t size; \
749 float lfactor; \
750 void (*free)(struct n*); \
751 int (*full)(struct n*); \
752 int (*rehash)(struct n*); \
753 int (*insert)(struct n*, t1, t2); \
754 __items_ ## n* (*items)(struct n*); \
755 int (*get)(struct n*, t1, t2*); \
756 int (*item)(struct n*, t1, void*); \
757 int (*contains)(struct n*, t1); \
758 int (*remove)(struct n*, t1); \
759 void (*clear)(struct n*); \
760 } n; \
761 n* n ## _init(n*);
763 #define define_map(t1, t2, n) \
764 define_pair(t1, t2, __pair_ ## n) \
765 define_list(__pair_ ## n*, __bucket_ ## n) \
766 define_vector(__pair_ ## n*, __items_ ## n) \
767 define_vector(__bucket_ ## n*, __vec_ ## n) \
769 * Check if hashmap is saturated (have to be
770 * rehashed).
772 * p: map pointer
774 * return: boolean saturated
775 */ \
776 static int n ## _full(n* p) { \
777 return p->count >= (p->size * p->lfactor); \
780 * Returns a vector with key-value pairs;
781 * the vector must be freed after use.
783 * p: map pointer
785 * return: pointer to vector of pairs on success,
786 * NULL on failure.
787 */ \
788 static __items_ ## n* n ## _items(n* p) { \
789 __items_ ## n* b = alloc(__items_ ## n); \
790 __bucket_ ## n* l; \
791 __pair_ ## n* e; \
792 size_t r = p->count; \
793 for (size_t i=0; i<p->data->count && r; ++i) \
794 if (p->data->get(p->data, i, &l)) \
795 if (l) \
796 for (size_t j=0; j<l->count; ++j) \
797 if (l->get(l, j, &e)) { \
798 if (b->push(b, e)) { \
799 --r; \
800 } else { \
801 release(b); \
802 return NULL; \
805 return b; \
808 * Rehash map
810 * p: map pointer
812 * return: boolean operation success/failure
813 */ \
814 static int n ## _rehash(n* p) { \
815 if (p->r || (p->size > (p->size+p->size))) \
816 return 0; \
817 p->cached = NULL; \
818 __bucket_ ## n* r = alloc(__bucket_ ## n); \
819 p->r = r; \
820 __bucket_ ## n* b; \
821 __pair_ ## n* e; \
822 while (p->data->count) { \
823 if (p->data->pop(p->data, &b)) { \
824 if (b) { \
825 while (b->count) { \
826 if (b->pop(b, &e)) { \
827 if (!r->push(r, e)) { \
828 p->data->push(p->data, b); \
829 return 0; \
831 } else { \
832 return 0; \
835 b->free(b); \
837 } else { \
838 return 0; \
841 while (p->count >= (p->size*p->lfactor)) { \
842 if (p->size > (p->size+p->size)) { \
843 p->size = ((size_t)-1); \
844 break; \
846 p->size *= 2; \
848 *(size_t*)&p->count = 0; \
849 for (size_t i=0; i<p->size; ++i) \
850 if (!p->data->push(p->data, NULL)) \
851 return 0; \
852 while (r->count) { \
853 if (r->pop(r, &e)) { \
854 if (p->insert(p, e->key, e->val)) { \
855 e->free(e); \
856 } else { \
857 r->push(r, e); \
858 return 0; \
862 r->free(r); \
863 return 1; \
865 static size_t __ ## n ## _hash(n* p, t1 k) { \
866 char b[64] = {0}; \
867 size_t h; \
868 char* s; \
869 sprintf(b, "%p", (void*)(size_t)k); \
870 s = p->strcmp ? (char*)(size_t)strtoull(b, NULL, 16) : b; \
871 size_t l = strlen(s); \
872 h = 3; \
873 for (size_t i=0; i<l; ++i) \
874 h = (h << 7) + (i ^ s[i]) + l; \
875 return h % p->size; \
877 static int __ ## n ## _cmpkeys(n* p, t1 ok, t1 nk) { \
878 if (!ok || !nk) \
879 return 0; \
880 if (p->strcmp) \
881 return eq((char*)(size_t)ok, (char*)(size_t)nk); \
882 return ok == nk; \
885 * Insert key and value in map
887 * p: map pointer
888 * k: key of type t1
889 * v: value of type t2
891 * return: boolean operation success/failure
892 */ \
893 static int n ## _insert(n* p, t1 k, t2 v) { \
894 if (!(p->count+1)) \
895 return 0; \
896 size_t x = __ ## n ## _hash(p, k); \
897 __bucket_ ## n* b; \
898 __pair_ ## n* e; \
899 if (!p->data->get(p->data, x, &b)) \
900 return 0; \
901 int ja = 0; \
902 int je = 0; \
903 if (!b) { \
904 ja = 1; \
905 b = alloc(__bucket_ ## n); \
906 if (!b) \
907 return 0; \
908 if (!p->data->put(p->data, x, b)) { \
909 b->free(b); \
910 return 0; \
913 for (size_t i=0; i<b->count; ++i) \
914 if (b->get(b, i, &e)) \
915 if (__ ## n ## _cmpkeys(p, e->key, k)) { \
916 e->key = k; \
917 e->val = v; \
918 return 1; \
920 e = alloc(__pair_ ## n); \
921 if (!e) { \
922 if (ja) \
923 b->free(b); \
924 return 0; \
926 je = 1; \
927 e->key = k; \
928 e->val = v; \
929 if (!b->push(b, e)) { \
930 if (ja) \
931 b->free(b); \
932 if (je) \
933 e->free(e); \
934 return 0; \
936 ++*(size_t*)&p->count; \
937 return 1; \
940 * Get a value from a key
942 * p: map pointer
943 * k: key of type t1
944 * v (output): pointer value of type t2
946 * return: boolean operation success/failure
947 */ \
948 static int n ## _get(n* p, t1 k, t2* v) { \
949 if (!p->count || !v) \
950 return 0; \
951 if (p->cached && __ ## n ## _cmpkeys(p, p->cached->key, k)) { \
952 *v = p->cached->val; \
953 return 1; \
955 __bucket_ ## n* b; \
956 __pair_ ## n* e; \
957 size_t x = __ ## n ## _hash(p, k); \
958 if (!p->data->get(p->data, x, &b)) \
959 return 0; \
960 if (b && b->count) { \
961 for (size_t i=0; i<b->count; ++i) { \
962 if (!b->get(b, i, &e)) \
963 return 0; \
964 if (__ ## n ## _cmpkeys(p, e->key, k)) { \
965 p->cached = e; \
966 *v = e->val; \
967 return 1; \
971 return 0; \
974 * Get key, value pair from a key
976 * p: map pointer
977 * k: key of type t1
978 * v (output): pair of type <t1, t2>
980 * return: boolean operation success/failure
981 */ \
982 static int n ## _item(n* p, t1 k, void* v) { \
983 if (!p->count || !v) \
984 return 0; \
985 __pair_ ## n** t = (__pair_ ## n**)v; \
986 if (p->cached && __ ## n ## _cmpkeys(p, p->cached->key, k)) { \
987 *t = p->cached; \
988 return 1; \
990 __bucket_ ## n* b; \
991 __pair_ ## n* e; \
992 size_t x = __ ## n ## _hash(p, k); \
993 if (!p->data->get(p->data, x, &b)) \
994 return 0; \
995 if (b && b->count) { \
996 for (size_t i=0; i<b->count; ++i) { \
997 if (!b->get(b, i, &e)) \
998 return 0; \
999 if (__ ## n ## _cmpkeys(p, e->key, k)) { \
1000 p->cached = e; \
1001 *t = e; \
1002 return 1; \
1006 return 0; \
1009 * Check if there is a key in a map
1011 * p: map pointer
1012 * k: key of type t1
1014 * return: boolean contains key
1015 */ \
1016 static int n ## _contains(n* p, t1 k) { \
1017 t2 tmp; \
1018 return p->get(p, k, &tmp); \
1021 * Remove key and value by key
1023 * p: map pointer
1024 * k: key of type t1
1026 * return: boolean operation success/failure
1027 */ \
1028 static int n ## _remove(n* p, t1 k) { \
1029 if (!p->count) \
1030 return 0; \
1031 if (p->cached && __ ## n ## _cmpkeys(p, p->cached->key, k)) \
1032 p->cached = NULL; \
1033 size_t x = __ ## n ## _hash(p, k); \
1034 __bucket_ ## n* b; \
1035 __pair_ ## n* e; \
1036 if (!p->data->get(p->data, x, &b)) \
1037 return 0; \
1038 if (b && b->count) { \
1039 for (size_t i=0; i<b->count; ++i) { \
1040 if (!b->get(b, i, &e)) \
1041 return 0; \
1042 if (__ ## n ## _cmpkeys(p, e->key, k)) { \
1043 b->remove(b, i); \
1044 e->free(e); \
1045 --*(size_t*)&p->count; \
1046 return 1; \
1050 return 0; \
1053 * Remove all items from a map
1055 * p: map pointer
1057 * return: boolean operation success/failure
1058 */ \
1059 static void n ## _clear(n* p) { \
1060 p->cached = NULL; \
1061 __bucket_ ## n* b; \
1062 __pair_ ## n* e; \
1063 while (p->data->count) { \
1064 if (!p->data->pop(p->data, &b)) \
1065 return; \
1066 if (!b) \
1067 continue; \
1068 while (b->count) \
1069 if (b->pop(b, &e)) \
1070 if (e) \
1071 e->free(e); \
1072 b->free(b); \
1076 * Release map's resources
1078 * p: map pointer
1079 */ \
1080 static void n ## _free(n* p) { \
1081 n ## _clear(p); \
1082 p->data->free(p->data); \
1083 free(p); \
1086 * Initialize map's resources
1088 * p: map pointer
1089 */ \
1090 n* n ## _init(n* p) { \
1091 if (!p) \
1092 return NULL; \
1093 memset(p, 0, sizeof(*p)); \
1094 p->full = n ## _full; \
1095 p->rehash = n ## _rehash; \
1096 p->insert = n ## _insert; \
1097 p->items = n ## _items; \
1098 p->get = n ## _get; \
1099 p->item = n ## _item; \
1100 p->contains = n ## _contains; \
1101 p->remove = n ## _remove; \
1102 p->clear = n ## _clear; \
1103 p->free = n ## _free; \
1104 p->data = alloc(__vec_ ## n); \
1105 if (!p->data) \
1106 return NULL; \
1107 p->size = MAPSIZE; \
1108 p->lfactor = LFACTOR; \
1109 for (size_t i=0; i<p->size; ++i) \
1110 p->data->push(p->data, NULL); \
1111 return p; \
1115 * Reverse a vector or a list in-place.
1117 * e: container item's type
1118 * c: pointer to container
1120 #define vlrev(e, c) \
1121 do { \
1122 if (!c || c->count < 2) \
1123 break; \
1124 e l; \
1125 e r; \
1126 size_t i = 0; \
1127 size_t j = c->count-1; \
1128 while (i<j) { \
1129 c->get(c, i, &l); \
1130 c->get(c, j, &r); \
1131 c->put(c, i, r); \
1132 c->put(c, j, l); \
1133 ++i; \
1134 --j; \
1136 } while (0)
1139 * Swap two items of a vector or a list by index.
1141 * c: pointer to container
1142 * e: container item's type
1143 * i1: first index
1144 * i2: second index
1146 #define vlswap(c, e, i1, i2) \
1147 do { \
1148 if (!c || i1 > c->count-1 || i2 > c->count-1 || i1 == i2) \
1149 break; \
1150 size_t __i1 = i1; \
1151 size_t __i2 = i2; \
1152 e e1; \
1153 e e2; \
1154 c->get(c, __i1, &e1); \
1155 c->get(c, __i2, &e2); \
1156 c->put(c, __i1, e2); \
1157 c->put(c, __i2, e1); \
1158 } while (0)
1161 * For each item (pair) of a map
1162 * do something.
1164 * m: map pointer
1165 * t: type of pair
1166 * p: pointer to pair of contained type
1167 * c: code to execute
1169 #define eachitem(m, t, p, c) \
1170 do { \
1171 if (!m) \
1172 break; \
1173 vec_ ## t* __v = (vec_ ## t*)m->items(m); \
1174 if (!__v) \
1175 break; \
1176 for (size_t __i=0; __i<__v->count; ++__i) { \
1177 if (__v->get(__v, __i, &p)) { \
1181 release(__v); \
1182 } while (0)
1185 * For each element of a vector/list
1186 * do something.
1188 * p: list/vector pointer
1189 * e: pointer to a value of contained type
1190 * c: code to execute
1192 #define each(p, e, c) \
1193 do { \
1194 if (!p) \
1195 break; \
1196 for (size_t __i=0; __i<p->count; ++__i) { \
1197 if (p->get(p, __i, &e)) { \
1201 } while (0)
1204 * Call a function on a pointer
1205 * at the end of a block of code
1207 * p: pointer to a value
1208 * e: function
1209 * c: code to execute
1211 #define with(p, f, c) \
1212 do { \
1216 f(p); \
1217 } while (0)
1220 * Splits a string into multiple
1221 * strings and puts them into
1222 * an already allocated list or vector.
1223 * If a delimiter replacer is given (r),
1224 * and it's not NULL, then append a copy
1225 * of it to list or vector.s
1227 * s: string to split
1228 * d: delimiter
1229 * p: pointer to a list or a vector
1230 * r: string to replace delimiter
1232 #define ssplit(s, d, p, r) \
1233 do { \
1234 if (!p) \
1235 break; \
1236 char* __sub = NULL; \
1237 size_t __b = 0; \
1238 size_t __l = 0; \
1239 size_t __sl = strlen(s); \
1240 for (size_t __i=0; __i<__sl; ++__i) { \
1241 if (s[__i] == d) { \
1242 if (__l) { \
1243 __sub = calloc(1, sizeof(char)*(__l+1)); \
1244 if (!__sub) \
1245 break; \
1246 size_t __j = __b; \
1247 for (size_t __x=0; __x<__l; ++__x, ++__j) \
1248 __sub[__x] = s[__j]; \
1249 p->push(p, __sub); \
1250 __l = 0; \
1252 if (r) \
1253 p->push(p, salloc(r)); \
1254 } else { \
1255 if (!__l) \
1256 __b = __i; \
1257 ++__l; \
1258 if (__i==__sl-1) { \
1259 __sub = calloc(1, sizeof(char)*(__l+1)); \
1260 if (!__sub) \
1261 break; \
1262 size_t __j = __b; \
1263 for (size_t __x=0; __x<__l; ++__x, ++__j) \
1264 __sub[__x] = s[__j]; \
1265 p->push(p, __sub); \
1266 __l = 0; \
1270 } while (0)
1273 * Join a vector of strings or a list of strings
1274 * into a single string. If the output buffer (b) is NULL, the
1275 * memory will be automatically allocated, and must be freed
1276 * after use; otherwise this macro simply uses the given
1277 * allocated buffer.
1279 * p: string to split
1280 * s: delimiter string
1281 * b: string buffer
1283 #define cjoin(p, s, b) \
1284 do { \
1285 if (!p || !p->count) \
1286 break; \
1288 size_t __lb = 0; \
1289 size_t __ls; \
1290 size_t __lc; \
1291 char* __c; \
1292 int __f = 0; \
1294 if (!b) { \
1295 b = calloc(1, sizeof(char)); \
1296 if (!b) \
1297 break; \
1298 } else { \
1299 __f = 1; \
1300 b[0] = 0; \
1302 for (size_t __i=0; __i<p->count; ++__i) { \
1303 if (p->get(p, __i, &__c) && __c) { \
1304 __lc = strlen(__c); \
1305 __ls = (__i+1==p->count) ? 0 : strlen(s); \
1306 if (!__f) { \
1307 char* __m = NULL; \
1308 __m = realloc(b, sizeof(char)*(__lb+__lc+__ls+1)); \
1309 if (__m) { \
1310 b = __m; \
1311 } else { \
1312 free(b); \
1313 b = NULL; \
1316 memcpy(b+__lb, __c, __lc); \
1317 memcpy(b+__lb+__lc, s, __ls); \
1318 __lb += __lc+__ls; \
1321 b[__lb] = 0; \
1322 } while (0)
1325 * Check if a vector of strings or a list of strings
1326 * contains a specified string.
1328 * p: list/vector of strings
1329 * v: string to search
1330 * r: boolean output value
1332 #define scont(p, v, r) \
1333 do { \
1334 r = 0; \
1335 const char* __s; \
1336 each(p, __s, \
1337 if (eq(__s, v)) { \
1338 r = 1; \
1339 break; \
1341 ); \
1342 } while (0)
1344 #define declare_utils() \
1345 int eq(const char*, const char*); \
1346 int ieq(const char*, const char*); \
1347 char* sjoin(char*, const char*, ...); \
1348 int oneof(char, const char*); \
1349 char* shellsub(char*, const char*); \
1350 int cmdret(const char*); \
1351 char* trim(char*); \
1352 char* salloc(char*); \
1353 char* sadd(char*, const char*); \
1354 char* sins(char*, const char*, size_t); \
1355 char* srep(char*, const char*, const char*, const char*, size_t); \
1356 int valid(char); \
1357 int isfile(int); \
1358 int issock(int); \
1359 int ispipe(int); \
1362 #define define_utils() \
1364 * Compare 2 strings for equality
1366 * a: first string
1367 * b: second string
1369 * return: boolean is/not equal
1370 */ \
1371 int eq(const char* a, const char* b) { \
1372 if (a == b) \
1373 return 1; \
1374 if (!a || !b) \
1375 return 0; \
1376 return !strcmp(a, b); \
1379 * Compare 2 strings for equality (case insensitive)
1381 * a: first string
1382 * b: second string
1384 * return: boolean is/not equal
1385 */ \
1386 int ieq(const char* a, const char* b) { \
1387 if (a == b) \
1388 return 1; \
1389 if (!a || !b) \
1390 return 0; \
1391 for (; *a; a++, b++) { \
1392 if ((*a < 0x41 || (*a >= 0x5B && *a <= 0x60) || *a > 0x7A) && *a != *b) \
1393 return 0; \
1394 if ((*a & ~(1<<5)) != (*b & ~(1<<5))) \
1395 return 0; \
1397 return 1; \
1400 * Joins a variable number of strings into a single
1401 * one, using a specified separator. If a NULL
1402 * buffer is given, then the memory is automatically
1403 * allocated, and must be freed after use; otherwise
1404 * the given buffer is used. The final argument to this
1405 * function must be NULL!
1407 * r: output buffer
1408 * s: separator string
1409 * ...: strings to join
1411 * return: string buffer
1412 */ \
1413 char* sjoin(char* r, const char* s, ...) { \
1414 if (!s) \
1415 return NULL; \
1417 va_list args; \
1418 va_start(args, s); \
1420 const char* a; \
1421 size_t la; \
1423 size_t ls = strlen(s); \
1424 size_t lr = 0; \
1425 size_t c = 0; \
1426 char* R = r; \
1428 do { \
1429 if (c>20) { \
1430 va_end(args); \
1431 return NULL; \
1433 a = va_arg(args, const char*); \
1434 } while (++c, a); \
1435 --c; \
1436 va_end(args); \
1437 va_start(args, s); \
1438 for (size_t i=0; i<c; ++i) { \
1439 const char* a = va_arg(args, const char*); \
1440 la = strlen(a); \
1441 ls = (i+1==c) ? 0 : strlen(s); \
1442 if (!R) { \
1443 char* m = realloc(r, sizeof(char)*(lr+la+ls+1)); \
1444 if (!m) { \
1445 free(r); \
1446 r = NULL; \
1447 break; \
1449 r = m; \
1451 memcpy(r+lr, a, la); \
1452 memcpy(r+lr+la, s, ls); \
1453 lr += la + ls; \
1455 va_end(args); \
1456 r[lr] = 0; \
1457 return r; \
1460 * Checks if a character is present inside
1461 * a given string.
1463 * c: character to check
1464 * s: string to search
1466 * return: boolean character is inside
1467 */ \
1468 int oneof(char c, const char* s) { \
1469 do { \
1470 if (c == *s) \
1471 return 1; \
1472 } while (*s++); \
1473 return 0; \
1476 * Uses popen to get the output of a shell command
1477 * and puts it in a given buffer. If the buffer is NULL,
1478 * the memory is automatically allocated, and must
1479 * be freed after use.
1481 * s: output buffer
1482 * c: command
1484 * return: string buffer
1485 */ \
1486 char* shellsub(char* s, const char* c) { \
1487 FILE* f = popen(c, "r"); \
1488 char* r = NULL; \
1489 char* m = NULL; \
1490 size_t n = 0; \
1491 size_t ls = 0; \
1492 size_t l = 0; \
1494 int b = !!s; \
1495 int ft = 1; \
1497 if (!f) \
1498 return NULL; \
1500 while (getline(&r, &n, f)>0) { \
1501 ls = s ? strlen(s) : 0; \
1502 l = ls + n; \
1503 if (!b) { \
1504 m = realloc(s, sizeof(char)*(l+1)); \
1505 if (!m) { \
1506 free(r); \
1507 free(s); \
1508 pclose(f); \
1509 return NULL; \
1511 s = m; \
1513 if (ft) { \
1514 ft = 0; \
1515 s[0] = 0; \
1517 strcat(s, r); \
1519 pclose(f); \
1520 free(r); \
1521 return s; \
1524 * Executes a given command and returns
1525 * its exit status.
1527 * s: command
1529 * return: command exit status
1530 */ \
1531 int cmdret(const char* s) { \
1532 int r = system(s); \
1533 return WIFEXITED(r) ? WEXITSTATUS(r) : r; \
1536 * Removes the trailing newline from a string.
1538 * s: string
1540 * return: string buffer
1541 */ \
1542 char* trim(char* s) { \
1543 if (!s) \
1544 return NULL; \
1546 size_t l = strlen(s); \
1547 if (s[l-1] == '\n') \
1548 s[l-1] = 0; \
1549 return s; \
1552 * Allocates enough memory to copy
1553 * a given string, and then copies it.
1554 * The string returned must be freed after use.
1556 * s: string
1558 * return: allocated string buffer
1559 */ \
1560 char* salloc(char* s) { \
1561 if (!s) \
1562 return NULL; \
1564 char* r; \
1565 size_t l = strlen(s); \
1566 r = calloc(l+1, sizeof(char)); \
1567 if (!r) \
1568 return NULL; \
1569 strcpy(r, s); \
1570 return r; \
1573 * Inserts a string into another one at specific
1574 * position and returns the result. If initial string is NULL,
1575 * memory is automatically allocated, and must
1576 * be freed after use, otherwise memory is reallocated
1577 * to insert the string.
1578 * Never pass a buffer to this function!
1580 * s: first string
1581 * a: second string
1583 * return: (re)allocated string buffer
1584 */ \
1585 char* sins(char* s, const char* a, size_t p) { \
1586 if (!a || !*a) \
1587 return s ? s : NULL; \
1589 size_t ls = 0; \
1590 size_t la = strlen(a); \
1591 char* m; \
1593 if (s) \
1594 ls = strlen(s); \
1595 if (p > ls) \
1596 return NULL; \
1597 m = realloc(s, sizeof(char)*(ls+la+1)); \
1598 if (!m) \
1599 return NULL; \
1600 s = m; \
1601 if (!ls) \
1602 s[0] = 0; \
1604 size_t i = ls+la; \
1605 size_t j = ls; \
1606 for (; j>=p; --i, --j) { \
1607 s[i] = s[j]; \
1608 if (!j) \
1609 break; \
1611 i = 0; \
1612 while (i < la) { \
1613 s[p+i] = a[i]; \
1614 ++i; \
1616 return s; \
1619 * Joins two strings into one, and returns
1620 * the result. If initial string is NULL,
1621 * memory is automatically allocated, and must
1622 * be freed after use, otherwise memory is reallocated
1623 * to add a new string.
1624 * Never pass a buffer to this function!
1626 * s: first string
1627 * a: second string
1629 * return: (re)allocated string buffer
1630 */ \
1631 char* sadd(char* s, const char* a) { \
1632 if (!a) \
1633 return s ? s : NULL; \
1635 size_t ls = 0; \
1636 size_t la = strlen(a); \
1637 char* m; \
1639 if (s) \
1640 ls = strlen(s); \
1641 m = realloc(s, sizeof(char)*(ls+la+1)); \
1642 if (!m) \
1643 return NULL; \
1644 s = m; \
1645 if (!ls) \
1646 s[0] = 0; \
1648 strcat(s, a); \
1649 return s; \
1652 * Replaces a string found in another string with another
1653 * string (a given number of times). If output buffer is
1654 * given, then simply uses it, otherwise memory is automatically
1655 * allocated, and must be freed after use.
1656 * If number of replacement is '0', the replaces all occurrences.
1658 * b: output buffer
1659 * s: string to search into
1660 * r: substring to find and replace
1661 * t: substring replacement
1662 * n: number of replacements
1664 * return: string buffer
1665 */ \
1666 char* srep(char* b, const char* s, const char* r, const char* t, size_t n) { \
1667 const char* d = s; \
1668 char* B = b; \
1669 char* p = NULL; \
1670 char* f; \
1671 char* m; \
1673 size_t ofs; \
1674 size_t ls = strlen(s); \
1675 size_t lr = strlen(r); \
1676 size_t lt = strlen(t); \
1677 size_t lret = 0; \
1679 for (size_t o=1; (f = strstr(d, r)); ++o) { \
1680 lret += (f-d) + lt; \
1681 if (!B) { \
1682 m = realloc(b, sizeof(char)*(lret+1)); \
1683 if (!m) { \
1684 free(b); \
1685 return NULL; \
1687 b = m; \
1689 if (o == 1) \
1690 b[0] = 0; \
1692 strncat(b, d, f-d); \
1693 strcat(b, t); \
1694 d = f+lr; \
1695 p = f; \
1696 if (n && o == n) \
1697 break; \
1699 if (!b) { \
1700 b = malloc(sizeof(char)*(ls+1)); \
1701 if (!b) \
1702 return NULL; \
1703 strncpy(b, s, ls+1); \
1704 return b; \
1706 lret = strlen(b); \
1707 if (!B && p) { \
1708 m = realloc(b, sizeof(char)*(lret+(lt+ls-(p-s))+1)); \
1709 if (!m) { \
1710 free(b); \
1711 return NULL; \
1713 b = m; \
1715 ofs = (p - s) + lr; \
1716 strncat(b, s+ofs, ls-ofs); \
1717 return b; \
1720 * Checks if a character is not "strange" :D
1722 * c: character to check
1724 * return: boolean is not strange
1725 */ \
1726 int valid(char c) { \
1727 return (c >= 0x09 && c <=0x0d) || (c >= 0x20 && c <= 0x7e); \
1730 * Checks if file descriptor refers to a regular file.
1731 * Doesn't check for syscall errors.
1733 * fd: file descriptor
1735 * return: boolean is a file
1736 */ \
1737 int isfile(int fd) { \
1738 struct stat sb; \
1739 if (fstat(fd, &sb) == -1) \
1740 return 0; \
1742 return S_IFREG == (sb.st_mode & S_IFMT); \
1745 * Checks if file descriptor refers to a socket.
1746 * Doesn't check for syscall errors.
1748 * fd: file descriptor
1750 * return: boolean is a socket
1751 */ \
1752 int issock(int fd) { \
1753 struct stat sb; \
1754 if (fstat(fd, &sb) == -1) \
1755 return 0; \
1757 return S_IFSOCK == (sb.st_mode & S_IFMT); \
1760 * Checks if file descriptor refers to a pipe.
1761 * Doesn't check for syscall errors.
1763 * fd: file descriptor
1765 * return: boolean is a pipe
1766 */ \
1767 int ispipe(int fd) { \
1768 struct stat sb; \
1769 if (fstat(fd, &sb) == -1) \
1770 return 0; \
1772 return S_IFIFO == (sb.st_mode & S_IFMT); \
1775 #endif