dte test coverage


Directory: ./
File: src/util/string-view.h
Date: 2025-05-08 15:05:54
Exec Total Coverage
Lines: 86 86 100.0%
Functions: 27 27 100.0%
Branches: 51 56 91.1%

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 16410 static inline StringView string_view(const char *str, size_t length)
34 {
35 16410 return (StringView) {
36 .data = str,
37 .length = length
38 };
39 }
40
41 4836 static inline StringView strview_from_cstring(const char *str)
42 {
43
2/2
✓ Branch 0 (2→3) taken 4584 times.
✓ Branch 1 (2→4) taken 252 times.
4836 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 2105 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 1257 times.
✓ Branch 1 (2→6) taken 848 times.
✓ Branch 2 (4→5) taken 799 times.
✓ Branch 3 (4→6) taken 458 times.
2105 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 2080 static inline bool strview_equal_cstring(const StringView *sv, const char *str)
73 {
74 2080 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 10241 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 8450 times.
✓ Branch 1 (2→6) taken 1791 times.
✓ Branch 2 (4→5) taken 8044 times.
✓ Branch 3 (4→6) taken 406 times.
10241 return sv->length >= n && mem_equal(sv->data, p, n);
87 }
88
89 NONNULL_ARG(1) NONNULL_ARG_IF_NONZERO_LENGTH(2, 3)
90 333 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 333 size_t len = sv->length;
94
6/6
✓ Branch 0 (2→3) taken 324 times.
✓ Branch 1 (2→7) taken 9 times.
✓ Branch 2 (3→4) taken 140 times.
✓ Branch 3 (3→7) taken 184 times.
✓ Branch 4 (5→6) taken 28 times.
✓ Branch 5 (5→7) taken 112 times.
333 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 9833 static inline bool strview_has_prefix(const StringView *sv, const char *p)
110 {
111 9833 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 19 static inline bool strview_has_suffix(const StringView *sv, const char *suffix)
123 {
124 19 return strview_has_strn_suffix(sv, suffix, strlen(suffix));
125 }
126
127 NONNULL_ARGS
128 2 static inline bool strview_has_prefix_and_suffix (
129 const StringView *sv,
130 const char *prefix,
131 const char *suffix
132 ) {
133
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);
134 }
135
136 NONNULL_ARGS
137 103 static inline bool strview_isblank(const StringView *sv)
138 {
139 103 size_t len = sv->length;
140 103 return len == ascii_blank_prefix_length(sv->data, len);
141 }
142
143 NONNULL_ARGS
144 3 static inline bool strview_contains_char_type(const StringView *sv, AsciiCharType mask)
145 {
146 3 return strn_contains_ascii_char_type(sv->data, sv->length, mask);
147 }
148
149 NONNULL_ARGS
150 15 static inline const unsigned char *strview_memchr(const StringView *sv, int c)
151 {
152
2/2
✓ Branch 0 (2→3) taken 14 times.
✓ Branch 1 (2→4) taken 1 times.
15 return sv->length ? memchr(sv->data, c, sv->length) : NULL;
153 }
154
155 NONNULL_ARGS
156 380 static inline const unsigned char *strview_memrchr(const StringView *sv, int c)
157 {
158
2/2
✓ Branch 0 (2→3) taken 250 times.
✓ Branch 1 (2→4) taken 130 times.
380 return sv->length ? xmemrchr(sv->data, c, sv->length) : NULL;
159 }
160
161 NONNULL_ARGS
162 376 static inline ssize_t strview_memrchr_idx(const StringView *sv, int c)
163 {
164 376 const unsigned char *ptr = strview_memrchr(sv, c);
165
2/2
✓ Branch 0 (2→3) taken 220 times.
✓ Branch 1 (2→4) taken 156 times.
376 return ptr ? (ssize_t)(ptr - sv->data) : -1;
166 }
167
168 9909 static inline void strview_remove_prefix(StringView *sv, size_t len)
169 {
170 9909 BUG_ON(len > sv->length);
171
2/2
✓ Branch 0 (4→5) taken 564 times.
✓ Branch 1 (4→6) taken 9345 times.
9909 if (len > 0) {
172 564 sv->data += len;
173 564 sv->length -= len;
174 }
175 9909 }
176
177 15 static inline void strview_remove_suffix(StringView *sv, size_t len)
178 {
179 15 BUG_ON(len > sv->length);
180 15 sv->length -= len;
181 15 }
182
183 317 static inline bool strview_remove_matching_prefix(StringView *sv, const char *prefix)
184 {
185 317 size_t prefix_len = strlen(prefix);
186
2/2
✓ Branch 0 (3→4) taken 89 times.
✓ Branch 1 (3→6) taken 228 times.
317 if (!strview_has_strn_prefix(sv, prefix, prefix_len)) {
187 return false;
188 }
189 89 strview_remove_prefix(sv, prefix_len);
190 89 return true;
191 }
192
193 296 static inline bool strview_remove_matching_suffix(StringView *sv, const char *suffix)
194 {
195 296 size_t suffix_len = strlen(suffix);
196
2/2
✓ Branch 0 (3→4) taken 9 times.
✓ Branch 1 (3→5) taken 287 times.
296 if (!strview_has_strn_suffix(sv, suffix, suffix_len)) {
197 return false;
198 }
199 9 sv->length -= suffix_len;
200 9 return true;
201 }
202
203 56 static inline bool strview_remove_matching_prefix_and_suffix (
204 StringView *sv,
205 const char *prefix,
206 const char *suffix
207 ) {
208 56 size_t plen = strlen(prefix);
209 56 size_t slen = strlen(suffix);
210
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)) {
211 15 strview_remove_prefix(sv, plen);
212 15 strview_remove_suffix(sv, slen);
213 15 return true;
214 }
215 return false;
216 }
217
218 NONNULL_ARGS
219 9155 static inline size_t strview_trim_left(StringView *sv)
220 {
221 9155 size_t blank_len = ascii_blank_prefix_length(sv->data, sv->length);
222 9155 strview_remove_prefix(sv, blank_len);
223 9155 return blank_len;
224 }
225
226 NONNULL_ARGS
227 209 static inline void strview_trim_right(StringView *sv)
228 {
229 209 const unsigned char *data = sv->data;
230 209 size_t n = sv->length;
231
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])) {
232 n--;
233 }
234 209 sv->length = n;
235 209 }
236
237 NONNULL_ARGS
238 7 static inline void strview_trim(StringView *sv)
239 {
240 7 strview_trim_left(sv);
241 7 strview_trim_right(sv);
242 7 }
243
244 #endif
245