dte test coverage


Directory: ./
File: src/util/string-view.h
Date: 2025-07-13 15:27:15
Exec Total Coverage
Lines: 90 90 100.0%
Functions: 29 29 100.0%
Branches: 55 60 91.7%

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 unsigned 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 18825 static inline StringView string_view(const char *str, size_t length)
34 {
35 18825 return (StringView) {
36 .data = str,
37 .length = length
38 };
39 }
40
41 5382 static inline StringView strview_from_cstring(const char *str)
42 {
43
2/2
✓ Branch 0 (2→3) taken 5124 times.
✓ Branch 1 (2→4) taken 258 times.
5382 return string_view(str, str ? strlen(str) : 0);
44 }
45
46 NONNULL_ARGS
47 2 static inline bool strview_equal(const StringView *a, const StringView *b)
48 {
49 2 size_t n = a->length;
50
2/4
✓ Branch 0 (2→3) taken 2 times.
✗ Branch 1 (2→6) not taken.
✗ Branch 2 (4→5) not taken.
✓ Branch 3 (4→6) taken 2 times.
2 return n == b->length && mem_equal(a->data, b->data, n);
51 }
52
53 NONNULL_ARGS
54 2324 static inline bool strview_equal_strn (
55 const StringView *sv,
56 const char *str,
57 size_t len
58 ) {
59
4/4
✓ Branch 0 (2→3) taken 1394 times.
✓ Branch 1 (2→6) taken 930 times.
✓ Branch 2 (4→5) taken 889 times.
✓ Branch 3 (4→6) taken 505 times.
2324 return len == sv->length && mem_equal(sv->data, str, len);
60 }
61
62 NONNULL_ARGS
63 15 static inline bool strview_equal_strn_icase (
64 const StringView *sv,
65 const char *str,
66 size_t len
67 ) {
68
3/4
✓ Branch 0 (2→3) taken 12 times.
✓ Branch 1 (2→6) taken 3 times.
✗ Branch 2 (4→5) not taken.
✓ Branch 3 (4→6) taken 12 times.
15 return len == sv->length && mem_equal_icase(sv->data, str, len);
69 }
70
71 NONNULL_ARGS
72 2299 static inline bool strview_equal_cstring(const StringView *sv, const char *str)
73 {
74 2299 return strview_equal_strn(sv, str, strlen(str));
75 }
76
77 NONNULL_ARGS
78 15 static inline bool strview_equal_cstring_icase(const StringView *sv, const char *str)
79 {
80 15 return strview_equal_strn_icase(sv, str, strlen(str));
81 }
82
83 NONNULL_ARG(1) NONNULL_ARG_IF_NONZERO_LENGTH(2, 3)
84 11692 static inline bool strview_has_strn_prefix(const StringView *sv, const char *p, size_t n)
85 {
86
4/4
✓ Branch 0 (2→3) taken 9777 times.
✓ Branch 1 (2→6) taken 1915 times.
✓ Branch 2 (4→5) taken 9323 times.
✓ Branch 3 (4→6) taken 454 times.
11692 return sv->length >= n && mem_equal(sv->data, p, n);
87 }
88
89 NONNULL_ARG(1) NONNULL_ARG_IF_NONZERO_LENGTH(2, 3)
90 618 static inline bool strview_has_strn_suffix(const StringView *sv, const char *suf, size_t suflen)
91 {
92 // See also: https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3322.pdf
93 618 size_t len = sv->length;
94
6/6
✓ Branch 0 (2→3) taken 609 times.
✓ Branch 1 (2→7) taken 9 times.
✓ Branch 2 (3→4) taken 241 times.
✓ Branch 3 (3→7) taken 368 times.
✓ Branch 4 (5→6) taken 31 times.
✓ Branch 5 (5→7) taken 210 times.
618 return suflen == 0 || (len >= suflen && mem_equal(sv->data + len - suflen, suf, suflen));
95 }
96
97 NONNULL_ARG(1) NONNULL_ARG_IF_NONZERO_LENGTH(2, 3) NONNULL_ARG_IF_NONZERO_LENGTH(4, 5)
98 56 static inline bool strview_has_strn_prefix_and_suffix (
99 const StringView *sv,
100 const char *prefix, size_t prefix_len,
101 const char *suffix, size_t suffix_len
102 ) {
103 56 return prefix_len + suffix_len <= sv->length
104
2/2
✓ Branch 0 (4→5) taken 15 times.
✓ Branch 1 (4→8) taken 39 times.
54 && strview_has_strn_prefix(sv, prefix, prefix_len)
105
3/4
✓ Branch 0 (2→3) taken 54 times.
✓ Branch 1 (2→8) taken 2 times.
✗ Branch 2 (6→7) not taken.
✓ Branch 3 (6→8) taken 15 times.
71 && strview_has_strn_suffix(sv, suffix, suffix_len);
106 }
107
108 NONNULL_ARGS
109 11052 static inline bool strview_has_prefix(const StringView *sv, const char *p)
110 {
111 11052 return strview_has_strn_prefix(sv, p, strlen(p));
112 }
113
114 NONNULL_ARGS
115 12 static inline bool strview_has_prefix_icase(const StringView *sv, const char *p)
116 {
117 12 size_t length = strlen(p);
118
4/4
✓ Branch 0 (2→3) taken 11 times.
✓ Branch 1 (2→6) taken 1 times.
✓ Branch 2 (4→5) taken 7 times.
✓ Branch 3 (4→6) taken 4 times.
12 return sv->length >= length && mem_equal_icase(sv->data, p, length);
119 }
120
121 NONNULL_ARGS
122 25 static inline bool strview_has_either_prefix (
123 const StringView *sv,
124 const char *pfx1,
125 const char *pfx2
126 ) {
127 25 return strview_has_strn_prefix(sv, pfx1, strlen(pfx1))
128
4/4
✓ Branch 0 (3→4) taken 21 times.
✓ Branch 1 (3→7) taken 4 times.
✓ Branch 2 (5→6) taken 2 times.
✓ Branch 3 (5→7) taken 19 times.
25 || strview_has_strn_prefix(sv, pfx2, strlen(pfx2));
129 }
130
131 NONNULL_ARGS
132 19 static inline bool strview_has_suffix(const StringView *sv, const char *suffix)
133 {
134 19 return strview_has_strn_suffix(sv, suffix, strlen(suffix));
135 }
136
137 NONNULL_ARGS
138 2 static inline bool strview_has_prefix_and_suffix (
139 const StringView *sv,
140 const char *prefix,
141 const char *suffix
142 ) {
143
3/4
✓ Branch 0 (3→4) taken 1 times.
✓ Branch 1 (3→7) taken 1 times.
✗ Branch 2 (5→6) not taken.
✓ Branch 3 (5→7) taken 1 times.
2 return strview_has_prefix(sv, prefix) && strview_has_suffix(sv, suffix);
144 }
145
146 NONNULL_ARGS
147 103 static inline bool strview_isblank(const StringView *sv)
148 {
149 103 size_t len = sv->length;
150 103 return len == ascii_blank_prefix_length(sv->data, len);
151 }
152
153 NONNULL_ARGS
154 3 static inline bool strview_contains_char_type(const StringView *sv, AsciiCharType mask)
155 {
156 3 return strn_contains_ascii_char_type(sv->data, sv->length, mask);
157 }
158
159 NONNULL_ARGS
160 21 static inline const unsigned char *strview_memchr(const StringView *sv, int c)
161 {
162
2/2
✓ Branch 0 (2→3) taken 20 times.
✓ Branch 1 (2→4) taken 1 times.
21 return sv->length ? memchr(sv->data, c, sv->length) : NULL;
163 }
164
165 NONNULL_ARGS
166 386 static inline const unsigned char *strview_memrchr(const StringView *sv, int c)
167 {
168
2/2
✓ Branch 0 (2→3) taken 253 times.
✓ Branch 1 (2→4) taken 133 times.
386 return sv->length ? xmemrchr(sv->data, c, sv->length) : NULL;
169 }
170
171 NONNULL_ARGS
172 382 static inline ssize_t strview_memrchr_idx(const StringView *sv, int c)
173 {
174 382 const unsigned char *ptr = strview_memrchr(sv, c);
175
2/2
✓ Branch 0 (2→3) taken 223 times.
✓ Branch 1 (2→4) taken 159 times.
382 return ptr ? (ssize_t)(ptr - sv->data) : -1;
176 }
177
178 10983 static inline void strview_remove_prefix(StringView *sv, size_t len)
179 {
180 10983 BUG_ON(len > sv->length);
181
2/2
✓ Branch 0 (4→5) taken 669 times.
✓ Branch 1 (4→6) taken 10314 times.
10983 if (len > 0) {
182 669 sv->data += len;
183 669 sv->length -= len;
184 }
185 10983 }
186
187 15 static inline void strview_remove_suffix(StringView *sv, size_t len)
188 {
189 15 BUG_ON(len > sv->length);
190 15 sv->length -= len;
191 15 }
192
193 325 static inline bool strview_remove_matching_strn_prefix (
194 StringView *sv,
195 const char *prefix,
196 size_t prefix_len
197 ) {
198
2/2
✓ Branch 0 (3→4) taken 96 times.
✓ Branch 1 (3→6) taken 229 times.
325 if (!strview_has_strn_prefix(sv, prefix, prefix_len)) {
199 return false;
200 }
201 96 strview_remove_prefix(sv, prefix_len);
202 96 return true;
203 }
204
205 323 static inline bool strview_remove_matching_prefix(StringView *sv, const char *prefix)
206 {
207 323 return strview_remove_matching_strn_prefix(sv, prefix, strlen(prefix));
208 }
209
210 581 static inline bool strview_remove_matching_suffix(StringView *sv, const char *suffix)
211 {
212 581 size_t suffix_len = strlen(suffix);
213
2/2
✓ Branch 0 (3→4) taken 12 times.
✓ Branch 1 (3→5) taken 569 times.
581 if (!strview_has_strn_suffix(sv, suffix, suffix_len)) {
214 return false;
215 }
216 12 sv->length -= suffix_len;
217 12 return true;
218 }
219
220 56 static inline bool strview_remove_matching_prefix_and_suffix (
221 StringView *sv,
222 const char *prefix,
223 const char *suffix
224 ) {
225 56 size_t plen = strlen(prefix);
226 56 size_t slen = strlen(suffix);
227
2/2
✓ Branch 0 (3→4) taken 15 times.
✓ Branch 1 (3→7) taken 41 times.
56 if (strview_has_strn_prefix_and_suffix(sv, prefix, plen, suffix, slen)) {
228 15 strview_remove_prefix(sv, plen);
229 15 strview_remove_suffix(sv, slen);
230 15 return true;
231 }
232 return false;
233 }
234
235 NONNULL_ARGS
236 10124 static inline size_t strview_trim_left(StringView *sv)
237 {
238 10124 size_t blank_len = ascii_blank_prefix_length(sv->data, sv->length);
239 10124 strview_remove_prefix(sv, blank_len);
240 10124 return blank_len;
241 }
242
243 NONNULL_ARGS
244 209 static inline void strview_trim_right(StringView *sv)
245 {
246 209 const unsigned char *data = sv->data;
247 209 size_t n = sv->length;
248
4/4
✓ Branch 0 (3→4) taken 233 times.
✓ Branch 1 (3→5) taken 44 times.
✓ Branch 2 (4→3) taken 68 times.
✓ Branch 3 (4→5) taken 165 times.
277 while (n && ascii_isblank(data[n - 1])) {
249 n--;
250 }
251 209 sv->length = n;
252 209 }
253
254 NONNULL_ARGS
255 7 static inline void strview_trim(StringView *sv)
256 {
257 7 strview_trim_left(sv);
258 7 strview_trim_right(sv);
259 7 }
260
261 #endif
262