No flags found
Use flags to group coverage reports by test type, project and/or folders.
Then setup custom commit statuses and notifications for each flag.
e.g., #unittest #integration
#production #enterprise
#frontend #backend
08da19a
... +2 ...
330a682
Use flags to group coverage reports by test type, project and/or folders.
Then setup custom commit statuses and notifications for each flag.
e.g., #unittest #integration
#production #enterprise
#frontend #backend
1301 | 1301 | { |
|
1302 | 1302 | import mir.parse: fromString, parse; |
|
1303 | 1303 | ||
1304 | + | if (str.length < 4) |
|
1305 | + | return false; |
|
1306 | + | ||
1304 | 1307 | static if (ext) |
|
1305 | - | auto isOnlyTime = str.length >= 3 && ((str[0] == 'T' || (yaml && (str[0] == 't' || str[0] == ' ' || str[0] == '\t'))) || str[2] == ':'); |
|
1308 | + | auto isOnlyTime = (str[0] == 'T' || yaml && (str[0] == 't')) || str[2] == ':'; |
|
1306 | 1309 | else |
|
1307 | - | auto isOnlyTime = str.length >= 3 && (str[0] == 'T' || (yaml && (str[0] == 't' || str[0] == ' ' || str[0] == '\t'))); |
|
1310 | + | auto isOnlyTime = str[0] == 'T' || yaml && (str[0] == 't'); |
|
1308 | 1311 | ||
1309 | 1312 | if (!isOnlyTime) |
|
1310 | 1313 | { |
1 | + | /++ |
|
2 | + | $(H1 String routines) |
|
3 | + | ||
4 | + | The module contains SIMD-accelerated string routines. |
|
5 | + | ||
6 | + | Copyright: 2022 Ilia Ki, Symmetry Investments |
|
7 | + | ||
8 | + | Authors: Ilia Ki |
|
9 | + | +/ |
|
10 | + | module mir.string; |
|
11 | + | ||
12 | + | import std.traits: isSomeChar; |
|
13 | + | ||
14 | + | private alias Representation(T : char) = byte; |
|
15 | + | private alias Representation(T : wchar) = short; |
|
16 | + | private alias Representation(T : dchar) = int; |
|
17 | + | ||
18 | + | private enum size_t ScanVecSize = 16; |
|
19 | + | ||
20 | + | /// |
|
21 | + | bool containsAny(C, size_t L) |
|
22 | + | (scope const(C)[] str, const C[L] chars...) |
|
23 | + | @trusted pure nothrow @nogc |
|
24 | + | if (isSomeChar!C && L) |
|
25 | + | { |
|
26 | + | enum size_t N = ScanVecSize / C.sizeof; |
|
27 | + | ||
28 | + | alias U = Representation!C; |
|
29 | + | ||
30 | + | // version(none) |
|
31 | + | version (LittleEndian) |
|
32 | + | version (LDC) |
|
33 | + | static if (N <= 8) |
|
34 | + | static if (is(__vector(U[N]))) |
|
35 | + | { |
|
36 | + | alias V = __vector(U[N]); |
|
37 | + | pragma(msg, V); |
|
38 | + | V[L] charsv; |
|
39 | + | static foreach (i; 0 .. L) |
|
40 | + | charsv[i] = chars[i]; |
|
41 | + | ||
42 | + | while (str.length >= N) |
|
43 | + | { |
|
44 | + | auto a = cast(V) *cast(const U[N]*) str.ptr; |
|
45 | + | ||
46 | + | import ldc.simd: mask = equalMask; |
|
47 | + | ||
48 | + | V[L] masked; |
|
49 | + | static foreach (i; 0 .. L) |
|
50 | + | masked[i] = mask!(__vector(U[N]))(a, charsv[i]); |
|
51 | + | ||
52 | + | static foreach (i; 0 .. L) |
|
53 | + | static if (i == 0) |
|
54 | + | V m = masked[i]; |
|
55 | + | else |
|
56 | + | m |= masked[i]; |
|
57 | + | ||
58 | + | if (m != V.init) |
|
59 | + | return true; |
|
60 | + | ||
61 | + | str = str[N .. $]; |
|
62 | + | } |
|
63 | + | } |
|
64 | + | ||
65 | + | foreach (C c; str) |
|
66 | + | static foreach (i; 0 .. L) |
|
67 | + | if (c == chars[i]) |
|
68 | + | return true; |
|
69 | + | return false; |
|
70 | + | } |
|
71 | + | ||
72 | + | /// |
|
73 | + | version(mir_test) |
|
74 | + | @safe pure nothrow @nogc |
|
75 | + | unittest |
|
76 | + | { |
|
77 | + | import mir.test: should; |
|
78 | + | ||
79 | + | assert(" hello world ".containsAny('w')); |
|
80 | + | assert(!" hello world ".containsAny('W')); |
|
81 | + | assert(" hello world ".containsAny('W', 'e')); |
|
82 | + | assert(" hello world ".containsAny("We")); |
|
83 | + | } |
|
84 | + | ||
85 | + | /// |
|
86 | + | template scanLeftAny(string op = "==") |
|
87 | + | if (op == "==" || op == "!=") |
|
88 | + | { |
|
89 | + | /// |
|
90 | + | inout(C)[] |
|
91 | + | scanLeftAny(C, size_t L) |
|
92 | + | (return scope inout(C)[] str, const C[L] chars...) |
|
93 | + | @trusted pure nothrow @nogc |
|
94 | + | if (isSomeChar!C && L) |
|
95 | + | { |
|
96 | + | enum size_t N = ScanVecSize / C.sizeof; |
|
97 | + | ||
98 | + | alias U = Representation!C; |
|
99 | + | ||
100 | + | // version(none) |
|
101 | + | version (LittleEndian) |
|
102 | + | version (LDC) |
|
103 | + | static if (N <= 8) |
|
104 | + | static if (is(__vector(U[N]))) |
|
105 | + | { |
|
106 | + | import mir.bitop: cttz; |
|
107 | + | ||
108 | + | alias V = __vector(U[N]); |
|
109 | + | pragma(msg, V); |
|
110 | + | V[L] charsv; |
|
111 | + | static foreach (i; 0 .. L) |
|
112 | + | charsv[i] = chars[i]; |
|
113 | + | ||
114 | + | while (str.length >= N) |
|
115 | + | { |
|
116 | + | auto a = cast(V) *cast(const U[N]*) str.ptr; |
|
117 | + | ||
118 | + | import ldc.simd: mask = equalMask; |
|
119 | + | ||
120 | + | V[L] masked; |
|
121 | + | static foreach (i; 0 .. L) |
|
122 | + | masked[i] = mask!(__vector(U[N]))(a, charsv[i]); |
|
123 | + | ||
124 | + | static foreach (i; 0 .. L) |
|
125 | + | static if (i == 0) |
|
126 | + | V m = masked[i]; |
|
127 | + | else |
|
128 | + | m |= masked[i]; |
|
129 | + | ||
130 | + | static if (op == "!=") |
|
131 | + | m = ~m; |
|
132 | + | ||
133 | + | auto words = (cast(__vector(size_t[U[N].sizeof / size_t.sizeof])) m).array; |
|
134 | + | ||
135 | + | static foreach (i; 0 .. words.length) |
|
136 | + | { |
|
137 | + | if (words[i]) |
|
138 | + | { |
|
139 | + | enum p = i * size_t.sizeof / U.sizeof; |
|
140 | + | return str[p + (cttz(words[i]) / (U.sizeof * 8)) .. $]; |
|
141 | + | } |
|
142 | + | } |
|
143 | + | str = str[N .. $]; |
|
144 | + | } |
|
145 | + | } |
|
146 | + | ||
147 | + | Loop: for (; str.length; str = str[1 .. $]) |
|
148 | + | { |
|
149 | + | auto c = str[0]; |
|
150 | + | static foreach (i; 0 .. L) |
|
151 | + | { |
|
152 | + | if (c == chars[i]) |
|
153 | + | { |
|
154 | + | static if (op == "==") |
|
155 | + | break Loop; |
|
156 | + | else |
|
157 | + | continue Loop; |
|
158 | + | } |
|
159 | + | } |
|
160 | + | static if (op == "==") |
|
161 | + | continue Loop; |
|
162 | + | else |
|
163 | + | break Loop; |
|
164 | + | } |
|
165 | + | return str; |
|
166 | + | } |
|
167 | + | } |
|
168 | + | ||
169 | + | /// |
|
170 | + | alias stripLeft = scanLeftAny!"!="; |
|
171 | + | ||
172 | + | /// |
|
173 | + | version(mir_test) |
|
174 | + | @safe pure nothrow @nogc |
|
175 | + | unittest |
|
176 | + | { |
|
177 | + | import mir.test: should; |
|
178 | + | ||
179 | + | " hello world ".stripLeft(' ').should == "hello world "; |
|
180 | + | " hello world ".scanLeftAny('w').should == "world "; |
|
181 | + | " hello world ".scanLeftAny('!').should == ""; |
|
182 | + | "\t\n\thello world\n\t___".stripLeft('\n', '\t').should == "hello world\n\t___"; |
|
183 | + | "hello world".stripLeft(' ').should == "hello world"; |
|
184 | + | "hello world ".stripLeft(' ').should == "hello world "; |
|
185 | + | ||
186 | + | " _____________ hello world " |
|
187 | + | .stripLeft(' ', '_').should == "hello world "; |
|
188 | + | } |
|
189 | + | ||
190 | + | /// |
|
191 | + | template scanRightAny(string op = "==") |
|
192 | + | if (op == "==" || op == "!=") |
|
193 | + | { |
|
194 | + | /// |
|
195 | + | inout(C)[] |
|
196 | + | scanRightAny(C, size_t L) |
|
197 | + | (return scope inout(C)[] str, const C[L] chars...) |
|
198 | + | @trusted pure nothrow @nogc |
|
199 | + | if (isSomeChar!C && L) |
|
200 | + | { |
|
201 | + | enum size_t N = ScanVecSize / C.sizeof; |
|
202 | + | ||
203 | + | alias U = Representation!C; |
|
204 | + | ||
205 | + | // version(none) |
|
206 | + | version (LittleEndian) |
|
207 | + | version (LDC) |
|
208 | + | static if (N <= 8) |
|
209 | + | static if (is(__vector(U[N]))) |
|
210 | + | { |
|
211 | + | import mir.bitop: ctlz; |
|
212 | + | ||
213 | + | alias V = __vector(U[N]); |
|
214 | + | pragma(msg, V); |
|
215 | + | V[L] charsv; |
|
216 | + | static foreach (i; 0 .. L) |
|
217 | + | charsv[i] = chars[i]; |
|
218 | + | ||
219 | + | while (str.length >= N) |
|
220 | + | { |
|
221 | + | auto a = cast(V) *cast(const U[N]*) (str.ptr + str.length - N); |
|
222 | + | ||
223 | + | import ldc.simd: mask = equalMask; |
|
224 | + | ||
225 | + | V[L] masked; |
|
226 | + | static foreach (i; 0 .. L) |
|
227 | + | masked[i] = mask!(__vector(U[N]))(a, charsv[i]); |
|
228 | + | ||
229 | + | static foreach (i; 0 .. L) |
|
230 | + | static if (i == 0) |
|
231 | + | V m = masked[i]; |
|
232 | + | else |
|
233 | + | m |= masked[i]; |
|
234 | + | ||
235 | + | static if (op == "!=") |
|
236 | + | m = ~m; |
|
237 | + | ||
238 | + | auto words = (cast(__vector(size_t[U[N].sizeof / size_t.sizeof])) m).array; |
|
239 | + | ||
240 | + | static foreach (i; 0 .. words.length) |
|
241 | + | { |
|
242 | + | if (words[$ - 1 - i]) |
|
243 | + | { |
|
244 | + | enum p = i * size_t.sizeof / U.sizeof; |
|
245 | + | return str[0 .. $ - (p + (ctlz(words[$ - 1 - i]) / (U.sizeof * 8)))]; |
|
246 | + | } |
|
247 | + | } |
|
248 | + | str = str[0 .. $ - N]; |
|
249 | + | } |
|
250 | + | } |
|
251 | + | ||
252 | + | Loop: for (; str.length; str = str[0 .. $ - 1]) |
|
253 | + | { |
|
254 | + | auto c = str[$ - 1]; |
|
255 | + | static foreach (i; 0 .. L) |
|
256 | + | { |
|
257 | + | if (c == chars[i]) |
|
258 | + | { |
|
259 | + | static if (op == "==") |
|
260 | + | break Loop; |
|
261 | + | else |
|
262 | + | continue Loop; |
|
263 | + | } |
|
264 | + | } |
|
265 | + | static if (op == "==") |
|
266 | + | continue Loop; |
|
267 | + | else |
|
268 | + | break Loop; |
|
269 | + | } |
|
270 | + | return str; |
|
271 | + | } |
|
272 | + | } |
|
273 | + | ||
274 | + | /// |
|
275 | + | alias stripRight = scanRightAny!"!="; |
|
276 | + | ||
277 | + | /// |
|
278 | + | version(mir_test) |
|
279 | + | @safe pure nothrow @nogc |
|
280 | + | unittest |
|
281 | + | { |
|
282 | + | import mir.test: should; |
|
283 | + | ||
284 | + | " hello world ".stripRight(' ').should == " hello world"; |
|
285 | + | " hello world ".scanRightAny('w').should == " hello w"; |
|
286 | + | " hello world ".scanRightAny('!').should == ""; |
|
287 | + | "___\t\n\thello world\n\t".stripRight('\n', '\t').should == "___\t\n\thello world"; |
|
288 | + | "hello world".stripRight(' ').should == "hello world"; |
|
289 | + | " hello world".stripRight(' ').should == " hello world"; |
|
290 | + | ||
291 | + | " hello world _____________ " |
|
292 | + | .stripRight(' ', '_').should == " hello world"; |
|
293 | + | } |
|
294 | + | ||
295 | + | /// |
|
296 | + | inout(C)[] |
|
297 | + | strip(C, size_t L) |
|
298 | + | (return scope inout(C)[] str, const C[L] chars...) |
|
299 | + | @trusted pure nothrow @nogc |
|
300 | + | if (isSomeChar!C && L) |
|
301 | + | { |
|
302 | + | return str.stripLeft(chars).stripRight(chars); |
|
303 | + | } |
|
304 | + | ||
305 | + | /// |
|
306 | + | version(mir_test) |
|
307 | + | @safe pure nothrow @nogc |
|
308 | + | unittest |
|
309 | + | { |
|
310 | + | import mir.test: should; |
|
311 | + | ||
312 | + | " hello world! ".strip(' ') .should == "hello world!"; |
|
313 | + | " hello world!!! ".strip(" !").should == "hello world"; |
|
314 | + | } |
Learn more Showing 1 files with coverage changes found.
source/mir/string.d
Files | Coverage |
---|---|
source/mir | 0.02% 91.67% |
Project Totals (79 files) | 91.67% |
330a682
38b9fb3
4b8bb1d
08da19a