dte test coverage


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 50.0% high: ≥ 85.0%
Coverage Exec / Excl / Total
Lines: 100.0% 98 / 0 / 98
Functions: 100.0% 31 / 0 / 31
Branches: 95.2% 59 / 8 / 70

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 "xmemrchr.h"
12 #include "xstring.h"
13
14 // A non-owning, length-bounded "view" into another string, similar to
15 // the C++17 string_view class or what many languages call a "slice".
16 // The .data member will usually *not* be null-terminated and the
17 // underlying string *must* outlive the view.
18 typedef struct {
19 const char NONSTRING *data;
20 size_t length;
21 } StringView;
22
23 #define STRING_VIEW_INIT { \
24 .data = NULL, \
25 .length = 0 \
26 }
27
28 #define STRING_VIEW(s) { \
29 .data = s, \
30 .length = STRLEN(s) \
31 }
32
33 #define SV(s) STRING_VIEW(s)
34
35 49101 static inline StringView string_view(const char *str, size_t length)
36 {
37 49101 return (StringView) {
38 .data = str,
39 .length = length
40 };
41 }
42
43 23583 static inline StringView strview(const char *str)
44 {
45
2/2
✓ Branch 2 → 3 taken 23421 times.
✓ Branch 2 → 4 taken 162 times.
23583 return string_view(str, str ? strlen(str) : 0);
46 }
47
48 // Return a view of the `str` substring between `start` and `end`.
49 // This is similar to xstrslice(), but without the need to allocate,
50 // copy or null-terminate.
51 689 static inline StringView strview_from_slice(const char *str, size_t start, size_t end)
52 {
53 689 BUG_ON(start > end);
54 689 BUG_ON(end && !str);
55
2/2
✓ Branch 6 → 7 taken 418 times.
✓ Branch 6 → 8 taken 271 times.
689 return string_view(start ? str + start : str, end - start);
56 }
57
58 2825 static inline bool strview_equal(StringView a, StringView b)
59 {
60 2825 size_t n = a.length;
61
4/4
✓ Branch 2 → 3 taken 1778 times.
✓ Branch 2 → 6 taken 1047 times.
✓ Branch 4 → 5 taken 889 times.
✓ Branch 4 → 6 taken 889 times.
2825 return n == b.length && mem_equal(a.data, b.data, n);
62 }
63
64 16 static inline bool strview_equal_icase(StringView a, StringView b)
65 {
66 16 size_t n = a.length;
67
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);
68 }
69
70 2413 static inline bool strview_equal_cstring(StringView sv, const char *str)
71 {
72 2413 return strview_equal(sv, strview(str));
73 }
74
75 14133 static inline bool strview_has_sv_prefix(StringView sv, StringView prefix)
76 {
77 14133 const size_t plen = prefix.length;
78
4/4
✓ Branch 2 → 3 taken 12126 times.
✓ Branch 2 → 6 taken 2007 times.
✓ Branch 4 → 5 taken 10889 times.
✓ Branch 4 → 6 taken 1237 times.
14133 return sv.length >= plen && mem_equal(sv.data, prefix.data, plen);
79 }
80
81 1852 static inline bool strview_has_sv_suffix(StringView sv, StringView suffix)
82 {
83 1852 size_t len = sv.length;
84 1852 size_t suflen = suffix.length;
85
4/4
✓ Branch 2 → 3 taken 1480 times.
✓ Branch 2 → 6 taken 372 times.
✓ Branch 4 → 5 taken 774 times.
✓ Branch 4 → 6 taken 706 times.
1852 return len >= suflen && mem_equal(sv.data + len - suflen, suffix.data, suflen);
86 }
87
88 11580 static inline bool strview_has_prefix(StringView sv, const char *prefix)
89 {
90 11580 return strview_has_sv_prefix(sv, strview(prefix));
91 }
92
93 12 static inline bool strview_has_prefix_icase(StringView sv, const char *prefix)
94 {
95 12 size_t length = strlen(prefix);
96
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);
97 }
98
99 25 static inline bool strview_has_either_prefix (
100 StringView sv,
101 const char *pfx1,
102 const char *pfx2
103 ) {
104 25 return strview_has_sv_prefix(sv, strview(pfx1))
105
4/4
✓ Branch 3 → 4 taken 21 times.
✓ Branch 3 → 7 taken 4 times.
✓ Branch 5 → 6 taken 19 times.
✓ Branch 5 → 7 taken 2 times.
25 || strview_has_sv_prefix(sv, strview(pfx2));
106 }
107
108 902 static inline bool strview_has_suffix(StringView sv, const char *suffix)
109 {
110 902 return strview_has_sv_suffix(sv, strview(suffix));
111 }
112
113 365 static inline bool strview_has_sv_prefix_and_suffix (
114 StringView sv,
115 StringView prefix,
116 StringView suffix
117 ) {
118 365 return
119 365 sv.length >= prefix.length + suffix.length
120
2/2
✓ Branch 4 → 5 taken 6 times.
✓ Branch 4 → 8 taken 234 times.
240 && strview_has_sv_prefix(sv, prefix)
121
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)
122 ;
123 }
124
125 2 static inline bool strview_has_prefix_and_suffix (
126 StringView sv,
127 const char *prefix,
128 const char *suffix
129 ) {
130 2 return strview_has_sv_prefix_and_suffix(sv, strview(prefix), strview(suffix));
131 }
132
133 10792 static inline size_t strview_blank_prefix_length(StringView sv)
134 {
135 10792 size_t i = 0;
136
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])) {
137 14289 i++;
138 }
139 10792 return i;
140 }
141
142 239 static inline size_t strview_blank_suffix_length(StringView sv)
143 {
144 239 size_t n = sv.length;
145
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])) {
146 n--;
147 }
148 239 return sv.length - n;
149 }
150
151 103 static inline bool strview_isblank(StringView sv)
152 {
153 103 return strview_blank_prefix_length(sv) == sv.length;
154 }
155
156 3 static inline bool strview_contains_char_type(StringView sv, AsciiCharType mask)
157 {
158
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++) {
159
1/2
✓ Branch 3 → 4 taken 20 times.
✗ Branch 3 → 6 not taken.
20 if (ascii_test(sv.data[i], mask)) {
160 return true;
161 }
162 }
163 return false;
164 }
165
166 78 static inline const char *strview_memchr(StringView sv, int c)
167 {
168
2/2
✓ Branch 2 → 3 taken 77 times.
✓ Branch 2 → 4 taken 1 time.
78 return sv.length ? memchr(sv.data, c, sv.length) : NULL;
169 }
170
171 714 static inline const char *strview_memrchr(StringView sv, int c)
172 {
173
2/2
✓ Branch 2 → 3 taken 449 times.
✓ Branch 2 → 4 taken 265 times.
714 return sv.length ? xmemrchr(sv.data, c, sv.length) : NULL;
174 }
175
176 710 static inline ssize_t strview_memrchr_idx(StringView sv, int c)
177 {
178 710 const char *ptr = strview_memrchr(sv, c);
179
2/2
✓ Branch 2 → 3 taken 301 times.
✓ Branch 2 → 4 taken 409 times.
710 return ptr ? (ssize_t)(ptr - sv.data) : -1;
180 }
181
182 11836 static inline size_t strview_remove_prefix(StringView *sv, size_t len)
183 {
184 11836 BUG_ON(len > sv->length);
185
2/2
✓ Branch 4 → 5 taken 3889 times.
✓ Branch 4 → 6 taken 7947 times.
11836 sv->data = len ? sv->data + len : sv->data;
186 11836 sv->length -= len;
187 11836 return len;
188 }
189
190 1095 static inline size_t strview_remove_suffix(StringView *sv, size_t len)
191 {
192 1095 BUG_ON(len > sv->length);
193 1095 sv->length -= len;
194 1095 return len;
195 }
196
197 751 static inline bool strview_remove_matching_sv_prefix (
198 StringView *sv,
199 StringView prefix
200 ) {
201 751 bool match = strview_has_sv_prefix(*sv, prefix);
202
2/2
✓ Branch 3 → 4 taken 140 times.
✓ Branch 3 → 5 taken 611 times.
751 strview_remove_prefix(sv, match ? prefix.length : 0);
203 751 return match;
204 }
205
206 883 static inline bool strview_remove_matching_sv_suffix (
207 StringView *sv,
208 StringView suffix
209 ) {
210 883 bool match = strview_has_sv_suffix(*sv, suffix);
211
2/2
✓ Branch 3 → 4 taken 14 times.
✓ Branch 3 → 5 taken 869 times.
883 strview_remove_suffix(sv, match ? suffix.length : 0);
212 883 return match;
213 }
214
215 749 static inline bool strview_remove_matching_prefix(StringView *sv, const char *prefix)
216 {
217 749 return strview_remove_matching_sv_prefix(sv, strview(prefix));
218 }
219
220 883 static inline bool strview_remove_matching_suffix(StringView *sv, const char *suffix)
221 {
222 883 return strview_remove_matching_sv_suffix(sv, strview(suffix));
223 }
224
225 56 static inline bool strview_remove_matching_affixes (
226 StringView *sv,
227 StringView prefix,
228 StringView suffix
229 ) {
230 56 size_t total_affix_length = prefix.length + suffix.length;
231 56 bool pmatch = strview_has_sv_prefix(*sv, prefix);
232 56 bool smatch = strview_has_sv_suffix(*sv, suffix);
233
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;
234
235 15 if (match) {
236 15 sv->data += prefix.length;
237 15 sv->length -= total_affix_length;
238 }
239
240 56 return match;
241 }
242
243 NONNULL_ARGS
244 10659 static inline size_t strview_trim_left(StringView *sv)
245 {
246 10659 return strview_remove_prefix(sv, strview_blank_prefix_length(*sv));
247 }
248
249 NONNULL_ARGS
250 209 static inline size_t strview_trim_right(StringView *sv)
251 {
252 209 return strview_remove_suffix(sv, strview_blank_suffix_length(*sv));
253 }
254
255 NONNULL_ARGS
256 7 static inline size_t strview_trim(StringView *sv)
257 {
258 7 size_t r = strview_trim_right(sv);
259 7 return r + strview_trim_left(sv);
260 }
261
262 #endif
263