aboutsummaryrefslogtreecommitdiff
path: root/cstring/include/cstring.h
diff options
context:
space:
mode:
Diffstat (limited to 'cstring/include/cstring.h')
-rw-r--r--cstring/include/cstring.h199
1 files changed, 105 insertions, 94 deletions
diff --git a/cstring/include/cstring.h b/cstring/include/cstring.h
index 84976b1..b07dad6 100644
--- a/cstring/include/cstring.h
+++ b/cstring/include/cstring.h
@@ -17,100 +17,111 @@
17 17
18/// A fixed-size string. 18/// A fixed-size string.
19/// The string is null-terminated so that it can be used with the usual C APIs. 19/// The string is null-terminated so that it can be used with the usual C APIs.
20#define DEF_STRING(STRING, SIZE) \ 20#define DEF_STRING(STRING, SIZE) \
21 typedef struct STRING { \ 21 typedef struct STRING { \
22 size_t length; \ 22 size_t length; \
23 char str[SIZE]; \ 23 char str[SIZE]; \
24 } STRING; \ 24 } STRING; \
25 \ 25 \
26 static const size_t STRING##_size = SIZE; \ 26 static const size_t STRING##_size = SIZE; \
27 \ 27 \
28 static inline const char* STRING##_cstr(const STRING* str) { \ 28 static inline const char* STRING##_cstr(const STRING* str) { \
29 return str->str; \ 29 return str->str; \
30 } \ 30 } \
31 \ 31 \
32 static inline size_t STRING##_length(STRING str) { return str.length; } \ 32 static inline size_t STRING##_length(const STRING* str) { \
33 \ 33 return str->length; \
34 static inline STRING STRING##_make(const char* cstr) { \ 34 } \
35 if (!cstr) { \ 35 \
36 return (STRING){0}; \ 36 static inline STRING STRING##_make(const char* cstr) { \
37 } else { \ 37 if (!cstr) { \
38 STRING str = (STRING){0}; \ 38 return (STRING){0}; \
39 str.length = strlcpy(str.str, cstr, SIZE); \ 39 } else { \
40 return str; \ 40 STRING str = (STRING){0}; \
41 } \ 41 str.length = strlcpy(str.str, cstr, SIZE); \
42 } \ 42 return str; \
43 \ 43 } \
44 static inline STRING STRING##_dirname(STRING path) { \ 44 } \
45 STRING str = path; \ 45 \
46 for (int i = str.length - 1; i >= 0; --i) { \ 46 static inline STRING STRING##_dirname(const STRING path) { \
47 if (str.str[i] == '/' || str.str[i] == '\\') { \ 47 STRING str = path; \
48 str.str[i] = 0; \ 48 for (int i = str.length - 1; i >= 0; --i) { \
49 str.length = i; \ 49 if (str.str[i] == '/' || str.str[i] == '\\') { \
50 return str; \ 50 str.str[i] = 0; \
51 } else { \ 51 str.length = i; \
52 str.str[i] = 0; \ 52 return str; \
53 } \ 53 } else { \
54 } \ 54 str.str[i] = 0; \
55 str = (STRING){0}; \ 55 } \
56 str.str[0] = '.'; \ 56 } \
57 str.length = 1; \ 57 str = (STRING){0}; \
58 return str; \ 58 str.str[0] = '.'; \
59 } \ 59 str.length = 1; \
60 \ 60 return str; \
61 static inline void STRING##_append_cstr(STRING* a, const char* b) { \ 61 } \
62 size_t b_length = strlen(b); \ 62 \
63 ASSERT(a->length + b_length + 1 < SIZE); \ 63 static inline void STRING##_append_cstr_len( \
64 strlcpy(a->str + a->length, b, SIZE); \ 64 STRING* a, const char* b, const size_t b_length) { \
65 a->length = a->length + b_length; \ 65 ASSERT(a->length + b_length + 1 <= SIZE); \
66 } \ 66 strlcpy(a->str + a->length, b, SIZE - a->length); \
67 \ 67 a->length += b_length; \
68 static inline void STRING##_append(STRING* a, STRING b) { \ 68 } \
69 ASSERT(a->length + b.length + 1 < SIZE); \ 69 \
70 strlcpy(a->str + a->length, b.str, SIZE); \ 70 static inline void STRING##_append_cstr(STRING* a, const char* b) { \
71 a->length = a->length + b.length; \ 71 STRING##_append_cstr_len(a, b, strlen(b)); \
72 } \ 72 } \
73 \ 73 \
74 static inline STRING STRING##_concat(STRING a, STRING b) { \ 74 static inline void STRING##_append(STRING* a, const STRING b) { \
75 ASSERT(a.length + b.length + 1 < SIZE); \ 75 STRING##_append_cstr_len(a, b.str, b.length); \
76 STRING str = {0}; \ 76 } \
77 strlcpy(str.str, a.str, SIZE); \ 77 \
78 strlcpy(str.str + a.length, b.str, SIZE); \ 78 static inline STRING STRING##_concat_cstr_len( \
79 str.length = a.length + b.length; \ 79 const STRING a, const char* b, const size_t b_length) { \
80 return str; \ 80 ASSERT(a.length + b_length + 1 <= SIZE); \
81 } \ 81 STRING str = {0}; \
82 \ 82 strlcpy(str.str, a.str, SIZE); \
83 static inline STRING STRING##_concat_cstr(STRING a, const char* b) { \ 83 strlcpy(str.str + a.length, b, SIZE - a.length); \
84 return STRING##_concat(a, STRING##_make(b)); \ 84 str.length = a.length + b_length; \
85 } \ 85 return str; \
86 \ 86 } \
87 static inline STRING STRING##_concat_path(STRING a, STRING b) { \ 87 \
88 return STRING##_concat(STRING##_concat(a, STRING##_make("/")), b); \ 88 static inline STRING STRING##_concat_cstr(const STRING a, const char* b) { \
89 } \ 89 return STRING##_concat_cstr_len(a, b, strlen(b)); \
90 \ 90 } \
91 static inline bool STRING##_eq(STRING a, STRING b) { \ 91 \
92 if (a.length != b.length) { \ 92 static inline STRING STRING##_concat(const STRING a, const STRING b) { \
93 return false; \ 93 return STRING##_concat_cstr_len(a, b.str, b.length); \
94 } \ 94 } \
95 return strncmp(a.str, b.str, a.length) == 0; \ 95 \
96 } \ 96 static inline STRING STRING##_concat_path(const STRING a, const STRING b) { \
97 \ 97 return STRING##_concat(STRING##_concat_cstr(a, "/"), b); \
98 static inline bool STRING##_eq_cstr(STRING a, const char* b) { \ 98 } \
99 return (a.length == strlen(b)) && strncmp(a.str, b, a.length) == 0; \ 99 \
100 } \ 100 static inline bool STRING##_eq_cstr_len( \
101 \ 101 const STRING a, const char* b, size_t b_length) { \
102 static inline bool STRING##_empty(STRING a) { return a.length == 0; } \ 102 return (a.length == b_length) && strncmp(a.str, b, a.length) == 0; \
103 \ 103 } \
104 static inline STRING STRING##_itoa(int n) { \ 104 \
105 STRING str = (STRING){0}; \ 105 static inline bool STRING##_eq_cstr(const STRING a, const char* b) { \
106 const int written = snprintf(str.str, SIZE, "%d", n); \ 106 return STRING##_eq_cstr_len(a, b, strlen(b)); \
107 ASSERT(written >= 0); \ 107 } \
108 str.length = (size_t)written; \ 108 \
109 return str; \ 109 static inline bool STRING##_eq(const STRING a, const STRING b) { \
110 } \ 110 return STRING##_eq_cstr_len(a, b.str, b.length); \
111 \ 111 } \
112 static inline uint64_t STRING##_hash(STRING str) { \ 112 \
113 return cstring_hash(str.str); \ 113 static inline bool STRING##_empty(const STRING a) { return a.length == 0; } \
114 \
115 static inline STRING STRING##_itoa(int n) { \
116 STRING str = (STRING){0}; \
117 const int written = snprintf(str.str, SIZE, "%d", n); \
118 ASSERT(written >= 0); \
119 str.length = (size_t)written; \
120 return str; \
121 } \
122 \
123 static inline uint64_t STRING##_hash(const STRING str) { \
124 return cstring_hash(str.str); \
114 } 125 }
115 126
116/// Return a hash of the given string. 127/// Return a hash of the given string.