1 module nxt.ixes;
2
3 import std.algorithm : commonPrefix;
4 import std.meta : allSatisfy;
5 import std.range.primitives : isInputRange, isBidirectionalRange;
6
7 /** Get length of Common Prefix of $(D a) and $(D b).
8 See_Also: http://forum.dlang.org/thread/bmbhovkgqomaidnyakvy@forum.dlang.org#post-bmbhovkgqomaidnyakvy:40forum.dlang.org
9 */
10 auto commonPrefixLength(alias pred = "a == b", Rs...)(Rs rs)
11 if (rs.length >= 2 &&
12 allSatisfy!(isInputRange, Rs))
13 {
14 static if (rs.length == 2)
15 {
16 return commonPrefix!pred(rs[0], rs[1]).length;
17 }
18 else
19 {
20 static assert("TODO");
21 import std.range : zip, StoppingPolicy;
22 import std.algorithm : countUntil, count;
23 const hit = zip(a, b).countUntil!(ab => ab[0] != ab[1]); // TODO if countUntil return zip(a, b).count upon failre...
24 return hit == -1 ? zip(a, b).count!pred : hit; // TODO ..then this would not have been needed
25 }
26 }
27
28 @safe pure unittest
29 {
30 assert(commonPrefixLength(`åäö_`,
31 `åäö-`) == 6);
32 }
33
34 @safe pure nothrow unittest
35 {
36 const x = [1, 2, 3, 10], y = [1, 2, 4, 10];
37 void f() @safe pure nothrow @nogc
38 {
39 assert(commonPrefixLength(x, y) == 2);
40 }
41 f();
42 assert(commonPrefixLength([1, 2, 3, 10],
43 [1, 2, 3]) == 3);
44 assert(commonPrefixLength([1, 2, 3, 0, 4],
45 [1, 2, 3, 9, 4]) == 3);
46 }
47
48 /** Get length of Suffix of $(D a) and $(D b).
49 See_Also: http://forum.dlang.org/thread/bmbhovkgqomaidnyakvy@forum.dlang.org#post-bmbhovkgqomaidnyakvy:40forum.dlang.org
50 */
51 auto commonSuffixLength(Rs...)(Rs rs)
52 if (rs.length == 2 &&
53 allSatisfy!(isBidirectionalRange, Rs))
54 {
55 import std.traits : isNarrowString;
56 import std.range: retro;
57 static if (isNarrowString!(typeof(rs[0])) &&
58 isNarrowString!(typeof(rs[1])))
59 {
60 import std..string: representation;
61 return commonPrefixLength(rs[0].representation.retro,
62 rs[1].representation.retro);
63 }
64 else
65 {
66 return commonPrefixLength(rs[0].retro,
67 rs[1].retro);
68 }
69 }
70
71 @safe pure unittest
72 {
73 const x = [1, 2, 3, 10, 11, 12];
74 const y = [1, 2, 4, 10, 11, 12];
75 void f() @safe pure nothrow @nogc
76 {
77 assert(commonPrefixLength(x, y) == 2);
78 }
79 f();
80 assert(commonSuffixLength(x, y) == 3);
81 assert(commonSuffixLength([10, 1, 2, 3],
82 [1, 2, 3]) == 3);
83 }
84
85 @safe pure unittest
86 {
87 assert(commonSuffixLength(`_åäö`,
88 `-åäö`) == 6);
89 }
90
91 /** Get Count of Prefix of $(D a) and $(D b).
92 See_Also: http://forum.dlang.org/thread/bmbhovkgqomaidnyakvy@forum.dlang.org#post-bmbhovkgqomaidnyakvy:40forum.dlang.org
93 */
94 auto commonPrefixCount(alias pred = "a == b", Rs...)(Rs rs)
95 if (rs.length == 2 &&
96 allSatisfy!(isInputRange, Rs))
97 {
98 import std.algorithm.searching : count;
99 import std.traits : isNarrowString;
100 static if (isNarrowString!(typeof(rs[0])) &&
101 isNarrowString!(typeof(rs[1])))
102 {
103 import std.utf: byDchar;
104 return commonPrefix!pred(rs[0].byDchar,
105 rs[1].byDchar).count;
106 }
107 else
108 {
109 return commonPrefix!pred(rs[0], rs[1]).count;
110 }
111 }
112
113 @safe pure unittest
114 {
115 assert(commonPrefixCount([1, 2, 3, 10],
116 [1, 2, 3]) == 3);
117 assert(commonPrefixCount(`åäö_`,
118 `åäö-`) == 3);
119 }
120
121 /** Get Common Suffix of $(D a) and $(D b).
122 TODO Copy implementation of commonPrefix into commonSuffix to splitter
123 */
124 auto commonSuffix(Rs...)(Rs rs)
125 if (rs.length == 2 &&
126 allSatisfy!(isBidirectionalRange, Rs))
127 {
128 import std.range : retro;
129 import std.conv : to;
130 import std.array : array;
131 return commonPrefix(rs[0].retro,
132 rs[1].retro).array.retro;
133 }
134
135 @safe pure unittest
136 {
137 import std.algorithm.comparison : equal;
138 assert(equal(commonSuffix(`_åäö`,
139 `-åäö`), `åäö`));
140 }
141
142 // @safe pure unittest
143 // {
144 // import std.algorithm.comparison : equal;
145 // import nxt.splitter_ex : splitterASCIIAmong;
146 // import std.range : retro;
147 // import std.range.primitives : ElementType;
148 // import std.array : array;
149 // assert(equal(commonSuffix(`_å-ä-ö`,
150 // `-å-ä-ö`).retro.splitterASCIIAmong!('-').array, // TODO how should this be solved?
151 // [`ö`, `ä`, `å`]));
152 // }
153
154 /** Get Count of Common Suffix of $(D a) and $(D b).
155 See_Also: http://forum.dlang.org/thread/bmbhovkgqomaidnyakvy@forum.dlang.org#post-bmbhovkgqomaidnyakvy:40forum.dlang.org
156 */
157 auto commonSuffixCount(alias pred = "a == b", Rs...)(Rs rs)
158 if (rs.length == 2 &&
159 allSatisfy!(isBidirectionalRange, Rs))
160 {
161 import std.range : retro;
162 return commonPrefixCount!pred(rs[0].retro,
163 rs[1].retro);
164 }
165
166 @safe pure unittest
167 {
168 assert(commonSuffixCount(`_`, `-`) == 0);
169 assert(commonSuffixCount(`_å`, `-å`) == 1);
170 assert(commonSuffixCount(`_åä`, `-åä`) == 2);
171 assert(commonSuffixCount(`_åäö`, `-åäö`) == 3);
172
173 import std.algorithm.comparison : among;
174 assert(commonSuffixCount!((a, b) => (a == b && a == 'ö'))(`_åäö`, `-åäö`) == 1);
175 assert(commonSuffixCount!((a, b) => (a == b && a.among!('ä', 'ö')))(`_åäö`, `-åäö`) == 2);
176 }
177
178 /** Get length of Common Prefix of rs $(D rs).
179 See_Also: http://forum.dlang.org/thread/bmbhovkgqomaidnyakvy@forum.dlang.org#post-bmbhovkgqomaidnyakvy:40forum.dlang.org
180 */
181 // auto commonPrefixLengthN(R...)(R rs) if (rs.length == 2)
182 // {
183 // import std.range: zip;
184 // return zip!((a, b) => a != b)(rs);
185 // }
186
187 // unittest
188 // {
189 // assert(commonPrefixLengthN([1, 2, 3, 10],
190 // [1, 2, 4, 10]) == 2);
191 // }