dte test coverage


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

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 34840 static inline StringView string_view(const char *str, size_t length)
34 {
35 34840 return (StringView) {
36 .data = str,
37 .length = length
38 };
39 }
40
41 21362 static inline StringView strview(const char *str)
42 {
43
2/2
✓ Branch 0 (2→3) taken 21073 times.
✓ Branch 1 (2→4) taken 289 times.
21362 return string_view(str, str ? strlen(str) : 0);
44 }
45
46 2427 static inline bool strview_equal(StringView a, StringView b)
47 {
48 2427 size_t n = a.length;
49
4/4
✓ Branch 0 (2→3) taken 1395 times.
✓ Branch 1 (2→6) taken 1032 times.
✓ Branch 2 (4→5) taken 889 times.
✓ Branch 3 (4→6) taken 506 times.
2427 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 0 (2→3) taken 13 times.
✓ Branch 1 (2→6) taken 3 times.
✗ Branch 2 (4→5) not taken.
✓ Branch 3 (4→6) taken 13 times.
16 return n == b.length && mem_equal_icase(a.data, b.data, n);
56 }
57
58 2401 static inline bool strview_equal_cstring(StringView sv, const char *str)
59 {
60 2401 return strview_equal(sv, strview(str));
61 }
62
63 13177 static inline bool strview_has_sv_prefix(StringView sv, StringView prefix)
64 {
65 13177 const size_t plen = prefix.length;
66
4/4
✓ Branch 0 (2→3) taken 11132 times.
✓ Branch 1 (2→6) taken 2045 times.
✓ Branch 2 (4→5) taken 10504 times.
✓ Branch 3 (4→6) taken 628 times.
13177 return sv.length >= plen && mem_equal(sv.data, prefix.data, plen);
67 }
68
69 666 static inline bool strview_has_sv_suffix(StringView sv, StringView suffix)
70 {
71 666 size_t len = sv.length;
72 666 size_t suflen = suffix.length;
73
4/4
✓ Branch 0 (2→3) taken 298 times.
✓ Branch 1 (2→6) taken 368 times.
✓ Branch 2 (4→5) taken 253 times.
✓ Branch 3 (4→6) taken 45 times.
666 return len >= suflen && mem_equal(sv.data + len - suflen, suffix.data, suflen);
74 }
75
76 11197 static inline bool strview_has_prefix(StringView sv, const char *prefix)
77 {
78 11197 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 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, 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 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_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 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);
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 0 (5→3) taken 20 times.
✓ Branch 1 (5→6) taken 3 times.
23 for (size_t i = 0, n = sv.length; i < n; i++) {
117
1/2
✓ Branch 0 (3→4) taken 20 times.
✗ Branch 1 (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 0 (2→3) taken 20 times.
✓ Branch 1 (2→4) taken 1 times.
21 return sv.length ? memchr(sv.data, c, sv.length) : NULL;
127 }
128
129 386 static inline const char *strview_memrchr(StringView sv, int c)
130 {
131
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;
132 }
133
134 382 static inline ssize_t strview_memrchr_idx(StringView sv, int c)
135 {
136 382 const char *ptr = strview_memrchr(sv, c);
137
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;
138 }
139
140 11272 static inline void strview_remove_prefix(StringView *sv, size_t len)
141 {
142 11272 BUG_ON(len > sv->length);
143
2/2
✓ Branch 0 (4→5) taken 657 times.
✓ Branch 1 (4→6) taken 10615 times.
11272 if (len > 0) {
144 657 sv->data += len;
145 657 sv->length -= len;
146 }
147 11272 }
148
149 583 static inline void strview_remove_suffix(StringView *sv, size_t len)
150 {
151 583 BUG_ON(len > sv->length);
152 583 sv->length -= len;
153 583 }
154
155 325 static inline bool strview_remove_matching_sv_prefix (
156 StringView *sv,
157 StringView prefix
158 ) {
159 325 bool match = strview_has_sv_prefix(*sv, prefix);
160
2/2
✓ Branch 0 (3→4) taken 96 times.
✓ Branch 1 (3→5) taken 229 times.
325 strview_remove_prefix(sv, match ? prefix.length : 0);
161 325 return match;
162 }
163
164 581 static inline bool strview_remove_matching_sv_suffix (
165 StringView *sv,
166 StringView suffix
167 ) {
168 581 bool match = strview_has_sv_suffix(*sv, suffix);
169
2/2
✓ Branch 0 (3→4) taken 12 times.
✓ Branch 1 (3→5) taken 569 times.
581 strview_remove_suffix(sv, match ? suffix.length : 0);
170 581 return match;
171 }
172
173 323 static inline bool strview_remove_matching_prefix(StringView *sv, const char *prefix)
174 {
175 323 return strview_remove_matching_sv_prefix(sv, strview(prefix));
176 }
177
178 581 static inline bool strview_remove_matching_suffix(StringView *sv, const char *suffix)
179 {
180 581 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 0 (4→5) taken 54 times.
✓ Branch 1 (4→7) taken 2 times.
✓ Branch 2 (5→6) taken 15 times.
✓ Branch 3 (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 10197 static inline size_t strview_trim_left(StringView *sv)
203 {
204 10197 size_t blank_len = ascii_blank_prefix_length(sv->data, sv->length);
205 10197 strview_remove_prefix(sv, blank_len);
206 10197 return blank_len;
207 }
208
209 NONNULL_ARGS
210 209 static inline void strview_trim_right(StringView *sv)
211 {
212 209 const char *data = sv->data;
213 209 size_t n = sv->length;
214
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])) {
215 n--;
216 }
217 209 sv->length = n;
218 209 }
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