1 /++ Algorithms that either improve or complement std.algorithm.mutation.`
2  +/
3 module nxt.algorithm.mutation;
4 
5 /** Array-specialization of `stripLeft` with default predicate.
6  *
7  * See_Also: https://forum.dlang.org/post/dhxwgtaubzbmjaqjmnmq@forum.dlang.org
8  */
9 inout(T)[] stripLeft(T)(scope return inout(T)[] haystack, scope const T needle) @trusted {
10 	static if (is(T : const(char)))
11 		assert(needle < 128); // See_Also: https://forum.dlang.org/post/sjirukypxmmcgdmqbcpe@forum.dlang.org
12 	size_t offset = 0;
13 	while (offset != haystack.length &&
14 		   haystack.ptr[offset] == needle) /+ TODO: elide range-check +/
15 		offset += 1;
16 	return haystack.ptr[offset .. haystack.length];
17 }
18 /// ditto
19 inout(char)[] stripLeft()(scope return inout(char)[] haystack) pure nothrow @safe @nogc /*tlm*/ {
20 	return haystack.stripLeft(' ');
21 }
22 ///
23 pure nothrow @safe @nogc unittest {
24 	assert("beta".stripLeft(' ') == "beta");
25 	assert(" beta".stripLeft(' ') == "beta");
26 	assert("  beta".stripLeft(' ') == "beta");
27 	assert("   beta".stripLeft(' ') == "beta");
28 	assert("   beta".stripLeft() == "beta");
29 	assert(" _ beta _ ".stripLeft(' ') == "_ beta _ ");
30 	assert(" _  beta _ ".stripLeft(' ') == "_  beta _ ");
31 	version (unittest) {
32 		static char[] f()() @safe pure nothrow { char[1] x = "_"; return x[].stripLeft(' '); }
33 		static if (hasPreviewDIP1000) static assert(!__traits(compiles, { auto _ = f(); }));
34 	}
35 }
36 
37 /** Array-specialization of `stripRight` with default predicate.
38  *
39  * See_Also: https://forum.dlang.org/post/dhxwgtaubzbmjaqjmnmq@forum.dlang.org
40  */
41 inout(T)[] stripRight(T)(scope return inout(T)[] haystack, scope const T needle) @trusted {
42 	static if (is(T : const(char)))
43 		assert(needle < 128); // See_Also: https://forum.dlang.org/post/sjirukypxmmcgdmqbcpe@forum.dlang.org
44 	size_t offset = haystack.length;
45 	while (offset != 0 &&
46 		   haystack.ptr[offset - 1] == needle) /+ TODO: elide range-check +/
47 		offset -= 1;
48 	return haystack.ptr[0 .. offset];
49 }
50 /// ditto
51 inout(T)[] stripRight(T)(scope return inout(T)[] haystack, scope const T[] needles) @trusted {
52 	import nxt.algorithm.searching : canFind;
53 	static if (is(T : const(char)))
54 		foreach (needle; needles)
55 			assert(needle < 128); // See_Also: https://forum.dlang.org/post/sjirukypxmmcgdmqbcpe@forum.dlang.org
56 	size_t offset = haystack.length;
57 	while (offset != 0 &&
58 		   needles.canFind(haystack.ptr[offset - 1])) /+ TODO: elide range-check +/
59 		offset -= 1;
60 	return haystack.ptr[0 .. offset];
61 }
62 /// ditto
63 inout(char)[] stripRight()(scope return inout(char)[] haystack) pure nothrow @safe @nogc /*tlm*/ {
64 	return haystack.stripRight([' ', '\t', '\r', '\n']); /+ TODO: `std.ascii.iswhite` instead +/
65 }
66 ///
67 pure nothrow @safe @nogc unittest {
68 	assert("beta".stripRight(' ') == "beta");
69 	assert("beta ".stripRight(' ') == "beta");
70 	assert("beta  ".stripRight(' ') == "beta");
71 	assert("beta	".stripRight('	') == "beta");
72 	assert("beta	".stripRight() == "beta");
73 	assert(" _ beta _ ".stripRight(' ') == " _ beta _");
74 	assert(" _  beta _ ".stripRight(' ') == " _  beta _");
75 	version (unittest) {
76 		static char[] f()() @safe pure nothrow { char[1] x = "_"; return x[].stripRight(' '); }
77 		static if (hasPreviewDIP1000) static assert(!__traits(compiles, { auto _ = f(); }));
78 	}
79 }
80 
81 /** Array-specialization of `strip` with default predicate.
82  *
83  * See_Also: https://forum.dlang.org/post/dhxwgtaubzbmjaqjmnmq@forum.dlang.org
84  */
85 inout(T)[] strip(T)(scope return inout(T)[] haystack, scope const T needle) @trusted {
86 	static if (is(T : const(char)))
87 		assert(needle < 128); // See_Also: https://forum.dlang.org/post/sjirukypxmmcgdmqbcpe@forum.dlang.org
88 	size_t leftOffset = 0;
89 	while (leftOffset != haystack.length &&
90 		   haystack.ptr[leftOffset] == needle) /+ TODO: elide range-check +/
91 		leftOffset += 1;
92 	size_t rightOffset = haystack.length;
93 	while (rightOffset != leftOffset &&
94 		   haystack.ptr[rightOffset - 1] == needle) /+ TODO: elide range-check +/
95 		rightOffset -= 1;
96 	return haystack.ptr[leftOffset .. rightOffset];
97 }
98 /// ditto
99 inout(char)[] strip()(scope return inout(char)[] haystack) pure nothrow @safe @nogc /*tlm*/ {
100 	return haystack.strip(' ');
101 }
102 ///
103 pure nothrow @safe @nogc unittest {
104 	assert("beta".strip(' ') == "beta");
105 	assert(" beta ".strip(' ') == "beta");
106 	assert("  beta  ".strip(' ') == "beta");
107 	assert("   beta   ".strip(' ') == "beta");
108 	assert(" _ beta _ ".strip(' ') == "_ beta _");
109 	assert(" _  beta _ ".strip(' ') == "_  beta _");
110 	version (unittest) {
111 		static char[] f()() @safe pure nothrow { char[1] x = "_"; return x[].strip(' '); }
112 		static if (hasPreviewDIP1000) static assert(!__traits(compiles, { auto _ = f(); }));
113 	}
114 }
115 ///
116 pure nothrow @safe @nogc unittest {
117 	const ubyte[3] x = [0, 42, 0];
118 	assert(x.strip(0) == x[1 .. 2]);
119 }
120 
121 version (unittest) {
122 	import nxt.dip_traits : hasPreviewDIP1000;
123 }