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