1 /+ 2 The MIT License (MIT) 3 4 Copyright (c) <2013> <Oleg Butko (deviator), Anton Akzhigitov (Akzwar)> 5 6 Permission is hereby granted, free of charge, to any person obtaining a copy 7 of this software and associated documentation files (the "Software"), to deal 8 in the Software without restriction, including without limitation the rights 9 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 copies of the Software, and to permit persons to whom the Software is 11 furnished to do so, subject to the following conditions: 12 13 The above copyright notice and this permission notice shall be included in 14 all copies or substantial portions of the Software. 15 16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 THE SOFTWARE. 23 +/ 24 25 module des.math.util.accessstring; 26 27 import std.string; 28 import std.algorithm; 29 import std.stdio; 30 31 /// construct valid value access strings 32 string arrayAccessStringCtor( string sep1, string sep2, string[][] variants... ) pure 33 in 34 { 35 assert( sep1 != sep2 ); 36 assert( variants.length > 0 ); 37 auto l = variants[0].length; 38 assert( all!(a=>a.length == l)( variants ) ); 39 } 40 body 41 { 42 string[] rr; 43 foreach( var; variants ) 44 rr ~= var.join(sep1); 45 return rr.join(sep2); 46 } 47 48 /// 49 unittest 50 { 51 enum s1 = " ", s2 = "|"; 52 static assert( isCompatibleArrayAccessStrings( 2, arrayAccessStringCtor( s1, s2, ["x","y"], ["alpha","beta"] ), s1, s2 ) ); 53 } 54 55 /// compatible for creating access dispatches 56 pure bool isCompatibleArrayAccessStrings( size_t N, string str, string sep1="", string sep2="|" ) 57 in { assert( sep1 != sep2 ); } body 58 { 59 auto strs = str.split(sep2); 60 foreach( s; strs ) 61 if( !isCompatibleArrayAccessString(N,s,sep1) ) 62 return false; 63 64 string[] fa; 65 foreach( s; strs ) 66 fa ~= s.split(sep1); 67 68 foreach( ref v; fa ) v = strip(v); 69 70 foreach( i, a; fa ) 71 foreach( j, b; fa ) 72 if( i != j && a == b ) return false; 73 74 return true; 75 } 76 77 78 /// compatible for creating access dispatches 79 pure bool isCompatibleArrayAccessString( size_t N, string str, string sep="" ) 80 { return N == getAccessFieldsCount(str,sep) && isArrayAccessString(str,sep); } 81 82 /// 83 pure bool isArrayAccessString( in string as, in string sep="", bool allowDot=false ) 84 { 85 if( as.length == 0 ) return false; 86 auto splt = as.split(sep); 87 foreach( i, val; splt ) 88 if( !isValueAccessString(val,allowDot) || canFind(splt[0..i],val) ) 89 return false; 90 return true; 91 } 92 93 /// 94 pure size_t getAccessFieldsCount( string str, string sep ) 95 { return str.split(sep).length; } 96 97 /// 98 pure ptrdiff_t getIndex( string as, string arg, string sep1="", string sep2="|" ) 99 in { assert( sep1 != sep2 ); } body 100 { 101 foreach( str; as.split(sep2) ) 102 foreach( i, v; str.split(sep1) ) 103 if( arg == v ) return i; 104 return -1; 105 } 106 107 /// 108 pure bool oneOfAccess( string str, string arg, string sep="" ) 109 { 110 auto splt = str.split(sep); 111 return canFind(splt,arg); 112 } 113 114 /// 115 pure bool oneOfAccessAll( string str, string arg, string sep="" ) 116 { 117 auto splt = arg.split(""); 118 return all!(a=>oneOfAccess(str,a,sep))(splt); 119 } 120 121 /// 122 pure bool oneOfAnyAccessAll( string str, string arg, string sep1="", string sep2="|" ) 123 in { assert( sep1 != sep2 ); } body 124 { 125 foreach( s; str.split(sep2) ) 126 if( oneOfAccessAll(s,arg,sep1) ) return true; 127 return false; 128 } 129 130 /// check symbol count for access to field 131 pure bool isOneSymbolPerFieldForAnyAccessString( string str, string sep1="", string sep2="|" ) 132 in { assert( sep1 != sep2 ); } body 133 { 134 foreach( s; str.split(sep2) ) 135 if( isOneSymbolPerFieldAccessString(s,sep1) ) return true; 136 return false; 137 } 138 139 /// check symbol count for access to field 140 pure bool isOneSymbolPerFieldAccessString( string str, string sep="" ) 141 { 142 foreach( s; str.split(sep) ) 143 if( s.length > 1 ) return false; 144 return true; 145 } 146 147 /++ 148 Using all functions 149 +/ 150 unittest 151 { 152 static assert( isValueAccessString( "hello" ) ); 153 static assert( isValueAccessString( "x" ) ); 154 static assert( isValueAccessString( "_ok" ) ); 155 static assert( isValueAccessString( "__ok" ) ); 156 static assert( isValueAccessString( "__o1k" ) ); 157 static assert( isValueAccessString( "_2o1k3" ) ); 158 static assert( !isValueAccessString( "0__ok" ) ); 159 static assert( !isValueAccessString( "__o-k" ) ); 160 static assert( isArrayAccessString( "xyz" ) ); 161 static assert( isArrayAccessString( "x|dx|y|dy", "|" ) ); 162 static assert( isCompatibleArrayAccessString( 4, "x|dx|y|dy", "|" ) ); 163 static assert( isCompatibleArrayAccessString( 3, "xyz" ) ); 164 static assert( !isCompatibleArrayAccessString( 4, "xxxy" ) ); 165 static assert( !isCompatibleArrayAccessString( 3, "xxx" ) ); 166 static assert( isCompatibleArrayAccessStrings( 3, "xyz" ) ); 167 static assert( isCompatibleArrayAccessStrings( 3, "x y z", " " ) ); 168 static assert( isCompatibleArrayAccessStrings( 2, "xy|uv" ) ); 169 static assert( isCompatibleArrayAccessStrings( 3, "abc|efg" ) ); 170 static assert( !isCompatibleArrayAccessStrings( 3, "abc|afg" ) ); 171 static assert( !isCompatibleArrayAccessStrings( 3, "xxy|uv" ) ); 172 static assert( isCompatibleArrayAccessStrings( 3, "x,y,z;u,v,t", ",", ";" ) ); 173 static assert( getIndex( "x y z", "x", " " ) == 0 ); 174 static assert( getIndex( "x y z", "y", " " ) == 1 ); 175 static assert( getIndex( "x y z", "z", " " ) == 2 ); 176 static assert( getIndex( "x|dx|y|dy", "dx", "|", ";" ) == 1 ); 177 static assert( getIndex( "x|dx|y|dy", "1dx", "|", ";" ) == -1 ); 178 179 static assert( oneOfAccessAll("xyz","xy") ); 180 static assert( oneOfAccessAll("xyz","yx") ); 181 static assert( oneOfAccessAll("xyz","xxxxyxyyyz") ); 182 static assert( oneOfAccessAll("x,y,z","xxxxyxyyyz",",") ); 183 static assert( isOneSymbolPerFieldAccessString("xyz") ); 184 static assert( isOneSymbolPerFieldAccessString("x,y,z",",") ); 185 static assert( isOneSymbolPerFieldForAnyAccessString( "xy|uv", "", "|" ) ); 186 static assert( isOneSymbolPerFieldForAnyAccessString( "near far|n f", " ", "|" ) ); 187 188 static assert( !isArrayAccessString("x.y.z","",false) ); 189 static assert( !isArrayAccessString("x.y.z","",true) ); 190 static assert( !isArrayAccessString("x.y.z"," ",false) ); 191 static assert( isArrayAccessString("x.y.z"," ",true) ); 192 static assert( isArrayAccessString("pos.x pos.y pos.z vel.x vel.y vel.z"," ",true) ); 193 194 static assert( isArrayAccessString( "pos vel", " ", true ) ); 195 static assert( isArrayAccessString( "abcd", " ", true ) ); 196 static assert( isArrayAccessString( "a1 a2", " ", true ) ); 197 static assert( isArrayAccessString( "ok.no", " ", true ) ); 198 auto fstr = "pos.x pos.y vel.x vel.y"; 199 assert( isArrayAccessString( fstr, " ", true ) ); 200 assert( !isArrayAccessString( fstr[0 .. $-1], " ", true ) ); 201 assert( !isArrayAccessString( "ok.1", " ", true ) ); 202 assert( !isArrayAccessString( "1abcd", " ", true ) ); 203 assert( !isArrayAccessString( "not 2ok", " ", true ) ); 204 } 205 206 pure 207 { 208 209 bool isValueAccessString( in string as, bool allowDot=false ) 210 { 211 return as.length > 0 && 212 startsWithAllowedChars(as) && 213 (allowDot?(all!(a=>isValueAccessString(a))(as.split("."))):allowedCharsOnly(as)); 214 } 215 216 bool startsWithAllowedChars( in string as ) 217 { 218 switch(as[0]) 219 { 220 case 'a': .. case 'z': goto case; 221 case 'A': .. case 'Z': goto case; 222 case '_': return true; 223 default: return false; 224 } 225 } 226 227 bool allowedCharsOnly( in string as ) 228 { 229 foreach( c; as ) if( !allowedChar(c) ) return false; 230 return true; 231 } 232 233 bool allowedChar( in char c ) 234 { 235 switch(c) 236 { 237 case 'a': .. case 'z': goto case; 238 case 'A': .. case 'Z': goto case; 239 case '0': .. case '9': goto case; 240 case '_': return true; 241 default: return false; 242 } 243 } 244 245 }