dte test coverage


Directory: ./
File: src/util/string-view.h
Date: 2026-01-09 16:07:09
Coverage Exec Excl Total
Lines: 100.0% 88 0 88
Functions: 100.0% 27 0 27
Branches: 94.4% 51 0 54

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 35026 static inline StringView string_view(const char *str, size_t length)
34 {
35 35026 return (StringView) {
36 .data = str,
37 .length = length
38 };
39 }
40
41 21510 static inline StringView strview(const char *str)
42 {
43
2/2
✓ Branch 2 → 3 taken 21220 times.
✓ Branch 2 → 4 taken 290 times.
21510 return string_view(str, str ? strlen(str) : 0);
44 }
45
46 2433 static inline bool strview_equal(StringView a, StringView b)
47 {
48 2433 size_t n = a.length;
49
4/4
✓ Branch 2 → 3 taken 1395 times.
✓ Branch 2 → 6 taken 1038 times.
✓ Branch 4 → 5 taken 889 times.
✓ Branch 4 → 6 taken 506 times.
2433 return n == b.length && mem_equal(a.data, b.data, n);
50 }
51
52 16 static inline bool strview_equal_icase(StringView a, StringView b)
53 {
54 16 size_t n = a.length;
55
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);
56 }
57
58 2406 static inline bool strview_equal_cstring(StringView sv, const char *str)
59 {
60 2406 return strview_equal(sv, strview(str));
61 }
62
63 13288 static inline bool strview_has_sv_prefix(StringView sv, StringView prefix)
64 {
65 13288 const size_t plen = prefix.length;
66
4/4
✓ Branch 2 → 3 taken 11235 times.
✓ Branch 2 → 6 taken 2053 times.
✓ Branch 4 → 5 taken 10604 times.
✓ Branch 4 → 6 taken 631 times.
13288 return sv.length >= plen && mem_equal(sv.data, prefix.data, plen);
67 }
68
69 668 static inline bool strview_has_sv_suffix(StringView sv, StringView suffix)
70 {
71 668 size_t len = sv.length;
72 668 size_t suflen = suffix.length;
73
4/4
✓ Branch 2 → 3 taken 300 times.
✓ Branch 2 → 6 taken 368 times.
✓ Branch 4 → 5 taken 255 times.
✓ Branch 4 → 6 taken 45 times.
668 return len >= suflen && mem_equal(sv.data + len - suflen, suffix.data, suflen);
74 }
75
76 11281 static inline bool strview_has_prefix(StringView sv, const char *prefix)
77 {
78 11281 return strview_has_sv_prefix(sv, strview(prefix));
79 }
80
81 12 static inline bool strview_has_prefix_icase(StringView sv, const char *prefix)
82 {
83 12 size_t length = strlen(prefix);
84
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);
85 }
86
87 25 static inline bool strview_has_either_prefix (
88 StringView sv,
89 const char *pfx1,
90 const char *pfx2
91 ) {
92 25 return strview_has_sv_prefix(sv, strview(pfx1))
93
4/4
✓ Branch 3 → 4 taken 21 times.
✓ Branch 3 → 7 taken 4 times.
✓ Branch 5 → 6 taken 2 times.
✓ Branch 5 → 7 taken 19 times.
25 || strview_has_sv_prefix(sv, strview(pfx2));
94 }
95
96 24 static inline bool strview_has_suffix(StringView sv, const char *suffix)
97 {
98 24 return strview_has_sv_suffix(sv, strview(suffix));
99 }
100
101 2 static inline bool strview_has_prefix_and_suffix (
102 StringView sv,
103 const char *prefix,
104 const char *suffix
105 ) {
106
3/4
✓ Branch 3 → 4 taken 1 time.
✓ Branch 3 → 7 taken 1 time.
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 1 time.
2 return strview_has_prefix(sv, prefix) && strview_has_suffix(sv, suffix);
107 }
108
109 103 static inline bool strview_isblank(StringView sv)
110 {
111 103 return ascii_blank_prefix_length(sv.data, sv.length) == sv.length;
112 }
113
114 3 static inline bool strview_contains_char_type(StringView sv, AsciiCharType mask)
115 {
116
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++) {
117
1/2
✓ Branch 3 → 4 taken 20 times.
✗ Branch 3 → 6 not taken.
20 if (ascii_test(sv.data[i], mask)) {
118 return true;
119 }
120 }
121 return false;
122 }
123
124 21 static inline const char *strview_memchr(StringView sv, int c)
125 {
126
2/2
✓ Branch 2 → 3 taken 20 times.
✓ Branch 2 → 4 taken 1 time.
21 return sv.length ? memchr(sv.data, c, sv.length) : NULL;
127 }
128
129 387 static inline const char *strview_memrchr(StringView sv, int c)
130 {
131
2/2
✓ Branch 2 → 3 taken 254 times.
✓ Branch 2 → 4 taken 133 times.
387 return sv.length ? xmemrchr(sv.data, c, sv.length) : NULL;
132 }
133
134 383 static inline ssize_t strview_memrchr_idx(StringView sv, int c)
135 {
136 383 const char *ptr = strview_memrchr(sv, c);
137
2/2
✓ Branch 2 → 3 taken 224 times.
✓ Branch 2 → 4 taken 159 times.
383 return ptr ? (ssize_t)(ptr - sv.data) : -1;
138 }
139
140 11371 static inline void strview_remove_prefix(StringView *sv, size_t len)
141 {
142 11371 BUG_ON(len > sv->length);
143
2/2
✓ Branch 4 → 5 taken 676 times.
✓ Branch 4 → 6 taken 10695 times.
11371 if (len > 0) {
144 676 sv->data += len;
145 676 sv->length -= len;
146 }
147 11371 }
148
149 585 static inline void strview_remove_suffix(StringView *sv, size_t len)
150 {
151 585 BUG_ON(len > sv->length);
152 585 sv->length -= len;
153 585 }
154
155 326 static inline bool strview_remove_matching_sv_prefix (
156 StringView *sv,
157 StringView prefix
158 ) {
159 326 bool match = strview_has_sv_prefix(*sv, prefix);
160
2/2
✓ Branch 3 → 4 taken 96 times.
✓ Branch 3 → 5 taken 230 times.
326 strview_remove_prefix(sv, match ? prefix.length : 0);
161 326 return match;
162 }
163
164 583 static inline bool strview_remove_matching_sv_suffix (
165 StringView *sv,
166 StringView suffix
167 ) {
168 583 bool match = strview_has_sv_suffix(*sv, suffix);
169
2/2
✓ Branch 3 → 4 taken 12 times.
✓ Branch 3 → 5 taken 571 times.
583 strview_remove_suffix(sv, match ? suffix.length : 0);
170 583 return match;
171 }
172
173 324 static inline bool strview_remove_matching_prefix(StringView *sv, const char *prefix)
174 {
175 324 return strview_remove_matching_sv_prefix(sv, strview(prefix));
176 }
177
178 583 static inline bool strview_remove_matching_suffix(StringView *sv, const char *suffix)
179 {
180 583 return strview_remove_matching_sv_suffix(sv, strview(suffix));
181 }
182
183 56 static inline bool strview_remove_matching_affixes (
184 StringView *sv,
185 StringView prefix,
186 StringView suffix
187 ) {
188 56 size_t total_affix_length = prefix.length + suffix.length;
189 56 bool pmatch = strview_has_sv_prefix(*sv, prefix);
190 56 bool smatch = strview_has_sv_suffix(*sv, suffix);
191
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;
192
193 15 if (match) {
194 15 sv->data += prefix.length;
195 15 sv->length -= total_affix_length;
196 }
197
198 56 return match;
199 }
200
201 NONNULL_ARGS
202 10293 static inline size_t strview_trim_left(StringView *sv)
203 {
204 10293 size_t blank_len = ascii_blank_prefix_length(sv->data, sv->length);
205 10293 strview_remove_prefix(sv, blank_len);
206 10293 return blank_len;
207 }
208
209 NONNULL_ARGS
210 210 static inline void strview_trim_right(StringView *sv)
211 {
212 210 const char *data = sv->data;
213 210 size_t n = sv->length;
214
4/4
✓ Branch 3 → 4 taken 234 times.
✓ Branch 3 → 5 taken 44 times.
✓ Branch 4 → 3 taken 68 times.
✓ Branch 4 → 5 taken 166 times.
278 while (n && ascii_isblank(data[n - 1])) {
215 n--;
216 }
217 210 sv->length = n;
218 210 }
219
220 NONNULL_ARGS
221 7 static inline void strview_trim(StringView *sv)
222 {
223 7 strview_trim_left(sv);
224 7 strview_trim_right(sv);
225 7 }
226
227 #endif
228