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 // }