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