dte test coverage


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 50.0% high: ≥ 85.0%
Coverage Exec / Excl / Total
Lines: 100.0% 106 / 0 / 106
Functions: 100.0% 34 / 0 / 34
Branches: 93.8% 60 / 8 / 72

src/util/string-view.h
Line Branch Exec Source
1 #ifndef UTIL_STRING_VIEW_H
2 #define UTIL_STRING_VIEW_H
3
4 #include <stdbool.h>
5 #include <stddef.h>
6 #include <string.h>
7 #include <sys/types.h>
8 #include "ascii.h"
9 #include "debug.h"
10 #include "macros.h"
11 #include "xmalloc.h"
12 #include "xmemrchr.h"
13 #include "xstring.h"
14
15 // A non-owning, length-bounded "view" into another string, similar to
16 // the C++17 string_view class or what many languages call a "slice".
17 // The .data member will usually *not* be null-terminated and the
18 // underlying string *must* outlive the view.
19 typedef struct {
20 const char NONSTRING *data;
21 size_t length;
22 } StringView;
23
24 #define STRING_VIEW_INIT { \
25 .data = NULL, \
26 .length = 0 \
27 }
28
29 #define STRING_VIEW(s) { \
30 .data = s, \
31 .length = STRLEN(s) \
32 }
33
34 #define SV(s) STRING_VIEW(s)
35
36 122006 static inline StringView string_view(const char *str, size_t length)
37 {
38 122006 return (StringView) {
39 .data = str,
40 .length = length
41 };
42 }
43
44 60046 static inline StringView strview(const char *str)
45 {
46
2/2
✓ Branch 2 → 3 taken 59883 times.
✓ Branch 2 → 4 taken 163 times.
60046 return string_view(str, str ? strlen(str) : 0);
47 }
48
49 // Return a view of the `str` substring between `start` and `end`.
50 // This is similar to xstrslice(), but without the need to allocate,
51 // copy or null-terminate.
52 36478 static inline StringView strview_from_slice(const char *str, size_t start, size_t end)
53 {
54 36478 BUG_ON(start > end);
55 36478 BUG_ON(end && !str);
56
2/2
✓ Branch 6 → 7 taken 25568 times.
✓ Branch 6 → 8 taken 10910 times.
36478 return string_view(start ? str + start : str, end - start);
57 }
58
59 2865 static inline bool strview_equal(StringView a, StringView b)
60 {
61 2865 size_t n = a.length;
62
4/4
✓ Branch 2 → 3 taken 1818 times.
✓ Branch 2 → 6 taken 1047 times.
✓ Branch 4 → 5 taken 889 times.
✓ Branch 4 → 6 taken 929 times.
2865 return n == b.length && mem_equal(a.data, b.data, n);
63 }
64
65 16 static inline bool strview_equal_icase(StringView a, StringView b)
66 {
67 16 size_t n = a.length;
68
3/4
✓ Branch 2 → 3 taken 13 times.
✓ Branch 2 → 6 taken 3 times.
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 13 times.
16 return n == b.length && mem_equal_icase(a.data, b.data, n);
69 }
70
71 2413 static inline bool strview_equal_cstring(StringView sv, const char *str)
72 {
73 2413 return strview_equal(sv, strview(str));
74 }
75
76 49761 static inline bool strview_has_sv_prefix(StringView sv, StringView prefix)
77 {
78 49761 const size_t plen = prefix.length;
79
4/4
✓ Branch 2 → 3 taken 46582 times.
✓ Branch 2 → 6 taken 3179 times.
✓ Branch 4 → 5 taken 44557 times.
✓ Branch 4 → 6 taken 2025 times.
49761 return sv.length >= plen && mem_equal(sv.data, prefix.data, plen);
80 }
81
82 1871 static inline bool strview_has_sv_suffix(StringView sv, StringView suffix)
83 {
84 1871 size_t len = sv.length;
85 1871 size_t suflen = suffix.length;
86
4/4
✓ Branch 2 → 3 taken 1495 times.
✓ Branch 2 → 6 taken 376 times.
✓ Branch 4 → 5 taken 781 times.
✓ Branch 4 → 6 taken 714 times.
1871 return len >= suflen && mem_equal(sv.data + len - suflen, suffix.data, suflen);
87 }
88
89 45227 static inline bool strview_has_prefix(StringView sv, const char *prefix)
90 {
91 45227 return strview_has_sv_prefix(sv, strview(prefix));
92 }
93
94 12 static inline bool strview_has_prefix_icase(StringView sv, const char *prefix)
95 {
96 12 size_t length = strlen(prefix);
97
4/4
✓ Branch 2 → 3 taken 11 times.
✓ Branch 2 → 6 taken 1 time.
✓ Branch 4 → 5 taken 7 times.
✓ Branch 4 → 6 taken 4 times.
12 return sv.length >= length && mem_equal_icase(sv.data, prefix, length);
98 }
99
100 47 static inline bool strview_has_either_prefix (
101 StringView sv,
102 const char *pfx1,
103 const char *pfx2
104 ) {
105 47 return strview_has_sv_prefix(sv, strview(pfx1))
106
4/4
✓ Branch 3 → 4 taken 24 times.
✓ Branch 3 → 7 taken 23 times.
✓ Branch 5 → 6 taken 22 times.
✓ Branch 5 → 7 taken 2 times.
47 || strview_has_sv_prefix(sv, strview(pfx2));
107 }
108
109 914 static inline bool strview_has_suffix(StringView sv, const char *suffix)
110 {
111 914 return strview_has_sv_suffix(sv, strview(suffix));
112 }
113
114 365 static inline bool strview_has_sv_prefix_and_suffix (
115 StringView sv,
116 StringView prefix,
117 StringView suffix
118 ) {
119 365 return
120 365 sv.length >= prefix.length + suffix.length
121
2/2
✓ Branch 4 → 5 taken 6 times.
✓ Branch 4 → 8 taken 234 times.
240 && strview_has_sv_prefix(sv, prefix)
122
3/4
✓ Branch 2 → 3 taken 240 times.
✓ Branch 2 → 8 taken 125 times.
✗ Branch 6 → 7 not taken.
✓ Branch 6 → 8 taken 6 times.
371 && strview_has_sv_suffix(sv, suffix)
123 ;
124 }
125
126 2 static inline bool strview_has_prefix_and_suffix (
127 StringView sv,
128 const char *prefix,
129 const char *suffix
130 ) {
131 2 return strview_has_sv_prefix_and_suffix(sv, strview(prefix), strview(suffix));
132 }
133
134 10792 static inline size_t strview_blank_prefix_length(StringView sv)
135 {
136 10792 size_t i = 0;
137
4/4
✓ Branch 4 → 5 taken 23513 times.
✓ Branch 4 → 6 taken 1568 times.
✓ Branch 5 → 3 taken 14289 times.
✓ Branch 5 → 6 taken 9224 times.
25081 while (i < sv.length && ascii_isblank(sv.data[i])) {
138 14289 i++;
139 }
140 10792 return i;
141 }
142
143 239 static inline size_t strview_blank_suffix_length(StringView sv)
144 {
145 239 size_t n = sv.length;
146
4/4
✓ Branch 3 → 4 taken 295 times.
✓ Branch 3 → 5 taken 43 times.
✓ Branch 4 → 3 taken 99 times.
✓ Branch 4 → 5 taken 196 times.
338 while (n && ascii_isblank(sv.data[n - 1])) {
147 n--;
148 }
149 239 return sv.length - n;
150 }
151
152 103 static inline bool strview_isblank(StringView sv)
153 {
154 103 return strview_blank_prefix_length(sv) == sv.length;
155 }
156
157 3 static inline bool strview_contains_char_type(StringView sv, AsciiCharType mask)
158 {
159
2/2
✓ Branch 5 → 3 taken 20 times.
✓ Branch 5 → 6 taken 3 times.
23 for (size_t i = 0, n = sv.length; i < n; i++) {
160
1/2
✓ Branch 3 → 4 taken 20 times.
✗ Branch 3 → 6 not taken.
20 if (ascii_test(sv.data[i], mask)) {
161 return true;
162 }
163 }
164 return false;
165 }
166
167 79 static inline const char *strview_memchr(StringView sv, int c)
168 {
169 79 return xmemchr(sv.data, c, sv.length);
170 }
171
172 716 static inline const char *strview_memrchr(StringView sv, int c)
173 {
174 716 return xmemrchr(sv.data, c, sv.length);
175 }
176
177 1 static inline ssize_t strview_memchr_idx(StringView sv, int c)
178 {
179 1 const char *ptr = strview_memchr(sv, c);
180
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 1 time.
1 return ptr ? (ssize_t)(ptr - sv.data) : -1;
181 }
182
183 712 static inline ssize_t strview_memrchr_idx(StringView sv, int c)
184 {
185 712 const char *ptr = strview_memrchr(sv, c);
186
2/2
✓ Branch 2 → 3 taken 302 times.
✓ Branch 2 → 4 taken 410 times.
712 return ptr ? (ssize_t)(ptr - sv.data) : -1;
187 }
188
189 11917 static inline size_t strview_remove_prefix(StringView *sv, size_t len)
190 {
191 11917 BUG_ON(len > sv->length);
192
2/2
✓ Branch 4 → 5 taken 3956 times.
✓ Branch 4 → 6 taken 7961 times.
11917 sv->data = len ? sv->data + len : sv->data;
193 11917 sv->length -= len;
194 11917 return len;
195 }
196
197 1099 static inline size_t strview_remove_suffix(StringView *sv, size_t len)
198 {
199 1099 BUG_ON(len > sv->length);
200 1099 sv->length -= len;
201 1099 return len;
202 }
203
204 783 static inline bool strview_remove_matching_sv_prefix (
205 StringView *sv,
206 StringView prefix
207 ) {
208 783 bool match = strview_has_sv_prefix(*sv, prefix);
209
2/2
✓ Branch 3 → 4 taken 158 times.
✓ Branch 3 → 5 taken 625 times.
783 strview_remove_prefix(sv, match ? prefix.length : 0);
210 783 return match;
211 }
212
213 887 static inline bool strview_remove_matching_sv_suffix (
214 StringView *sv,
215 StringView suffix
216 ) {
217 887 bool match = strview_has_sv_suffix(*sv, suffix);
218
2/2
✓ Branch 3 → 4 taken 15 times.
✓ Branch 3 → 5 taken 872 times.
887 strview_remove_suffix(sv, match ? suffix.length : 0);
219 887 return match;
220 }
221
222 781 static inline bool strview_remove_matching_prefix(StringView *sv, const char *prefix)
223 {
224 781 return strview_remove_matching_sv_prefix(sv, strview(prefix));
225 }
226
227 887 static inline bool strview_remove_matching_suffix(StringView *sv, const char *suffix)
228 {
229 887 return strview_remove_matching_sv_suffix(sv, strview(suffix));
230 }
231
232 // Remove `prefix1` or `prefix2` from the start of `sv` (if present) and
233 // return 1 or 2 accordingly, or 0 if neither is present
234 250 static inline unsigned int strview_remove_either_matching_prefix (
235 StringView *sv,
236 const char *prefix1,
237 const char *prefix2
238 ) {
239 250 bool match1 = strview_remove_matching_prefix(sv, prefix1);
240
4/4
✓ Branch 3 → 4 taken 206 times.
✓ Branch 3 → 7 taken 44 times.
✓ Branch 5 → 6 taken 188 times.
✓ Branch 5 → 7 taken 18 times.
250 return match1 ? 1 : (strview_remove_matching_prefix(sv, prefix2) ? 2 : 0);
241 }
242
243 56 static inline bool strview_remove_matching_affixes (
244 StringView *sv,
245 StringView prefix,
246 StringView suffix
247 ) {
248 56 size_t total_affix_length = prefix.length + suffix.length;
249 56 bool pmatch = strview_has_sv_prefix(*sv, prefix);
250 56 bool smatch = strview_has_sv_suffix(*sv, suffix);
251
4/4
✓ Branch 4 → 5 taken 54 times.
✓ Branch 4 → 7 taken 2 times.
✓ Branch 5 → 6 taken 15 times.
✓ Branch 5 → 7 taken 39 times.
56 bool match = (total_affix_length <= sv->length) && pmatch && smatch;
252
253 15 if (match) {
254 15 sv->data += prefix.length;
255 15 sv->length -= total_affix_length;
256 }
257
258 56 return match;
259 }
260
261 NONNULL_ARGS
262 10659 static inline size_t strview_trim_left(StringView *sv)
263 {
264 10659 return strview_remove_prefix(sv, strview_blank_prefix_length(*sv));
265 }
266
267 NONNULL_ARGS
268 209 static inline size_t strview_trim_right(StringView *sv)
269 {
270 209 return strview_remove_suffix(sv, strview_blank_suffix_length(*sv));
271 }
272
273 NONNULL_ARGS
274 7 static inline size_t strview_trim(StringView *sv)
275 {
276 7 size_t r = strview_trim_right(sv);
277 7 return r + strview_trim_left(sv);
278 }
279
280 MALLOC RETURNS_NONNULL
281 144 static inline char *strview_clone_cstring(StringView sv)
282 {
283 144 return xmemjoin(sv.data, sv.length, "", 1);
284 }
285
286 #endif
287