1 module des.math.util.accessstring; 2 3 import std..string; 4 import std.algorithm; 5 import std.stdio; 6 7 /// construct valid value access strings 8 string arrayAccessStringCtor( string sep1, string sep2, string[][] variants... ) pure 9 in 10 { 11 assert( sep1 != sep2 ); 12 assert( variants.length > 0 ); 13 auto l = variants[0].length; 14 assert( all!(a=>a.length == l)( variants ) ); 15 } 16 body 17 { 18 string[] rr; 19 foreach( var; variants ) 20 rr ~= var.join(sep1); 21 return rr.join(sep2); 22 } 23 24 /// 25 unittest 26 { 27 enum s1 = " ", s2 = "|"; 28 static assert( isCompatibleArrayAccessStrings( 2, arrayAccessStringCtor( s1, s2, ["x","y"], ["alpha","beta"] ), s1, s2 ) ); 29 } 30 31 /// compatible for creating access dispatches 32 pure bool isCompatibleArrayAccessStrings( size_t N, string str, string sep1="", string sep2="|" ) 33 in { assert( sep1 != sep2 ); } body 34 { 35 auto strs = str.split(sep2); 36 foreach( s; strs ) 37 if( !isCompatibleArrayAccessString(N,s,sep1) ) 38 return false; 39 40 string[] fa; 41 foreach( s; strs ) 42 fa ~= s.split(sep1); 43 44 foreach( ref v; fa ) v = strip(v); 45 46 foreach( i, a; fa ) 47 foreach( j, b; fa ) 48 if( i != j && a == b ) return false; 49 50 return true; 51 } 52 53 54 /// compatible for creating access dispatches 55 pure bool isCompatibleArrayAccessString( size_t N, string str, string sep="" ) 56 { return N == getAccessFieldsCount(str,sep) && isArrayAccessString(str,sep); } 57 58 /// 59 pure bool isArrayAccessString( in string as, in string sep="", bool allowDot=false ) 60 { 61 if( as.length == 0 ) return false; 62 auto splt = as.split(sep); 63 foreach( i, val; splt ) 64 if( !isValueAccessString(val,allowDot) || canFind(splt[0..i],val) ) 65 return false; 66 return true; 67 } 68 69 /// 70 pure size_t getAccessFieldsCount( string str, string sep ) 71 { return str.split(sep).length; } 72 73 /// 74 pure ptrdiff_t getIndex( string as, string arg, string sep1="", string sep2="|" ) 75 in { assert( sep1 != sep2 ); } body 76 { 77 foreach( str; as.split(sep2) ) 78 foreach( i, v; str.split(sep1) ) 79 if( arg == v ) return i; 80 return -1; 81 } 82 83 /// 84 pure bool oneOfAccess( string str, string arg, string sep="" ) 85 { 86 auto splt = str.split(sep); 87 return canFind(splt,arg); 88 } 89 90 /// 91 pure bool oneOfAccessAll( string str, string arg, string sep="" ) 92 { 93 auto splt = arg.split(""); 94 return all!(a=>oneOfAccess(str,a,sep))(splt); 95 } 96 97 /// 98 pure bool oneOfAnyAccessAll( string str, string arg, string sep1="", string sep2="|" ) 99 in { assert( sep1 != sep2 ); } body 100 { 101 foreach( s; str.split(sep2) ) 102 if( oneOfAccessAll(s,arg,sep1) ) return true; 103 return false; 104 } 105 106 /// check symbol count for access to field 107 pure bool isOneSymbolPerFieldForAnyAccessString( string str, string sep1="", string sep2="|" ) 108 in { assert( sep1 != sep2 ); } body 109 { 110 foreach( s; str.split(sep2) ) 111 if( isOneSymbolPerFieldAccessString(s,sep1) ) return true; 112 return false; 113 } 114 115 /// check symbol count for access to field 116 pure bool isOneSymbolPerFieldAccessString( string str, string sep="" ) 117 { 118 foreach( s; str.split(sep) ) 119 if( s.length > 1 ) return false; 120 return true; 121 } 122 123 /++ 124 Using all functions 125 +/ 126 unittest 127 { 128 static assert( isValueAccessString( "hello" ) ); 129 static assert( isValueAccessString( "x" ) ); 130 static assert( isValueAccessString( "_ok" ) ); 131 static assert( isValueAccessString( "__ok" ) ); 132 static assert( isValueAccessString( "__o1k" ) ); 133 static assert( isValueAccessString( "_2o1k3" ) ); 134 static assert( !isValueAccessString( "0__ok" ) ); 135 static assert( !isValueAccessString( "__o-k" ) ); 136 static assert( isArrayAccessString( "xyz" ) ); 137 static assert( isArrayAccessString( "x|dx|y|dy", "|" ) ); 138 static assert( isCompatibleArrayAccessString( 4, "x|dx|y|dy", "|" ) ); 139 static assert( isCompatibleArrayAccessString( 3, "xyz" ) ); 140 static assert( !isCompatibleArrayAccessString( 4, "xxxy" ) ); 141 static assert( !isCompatibleArrayAccessString( 3, "xxx" ) ); 142 static assert( isCompatibleArrayAccessStrings( 3, "xyz" ) ); 143 static assert( isCompatibleArrayAccessStrings( 3, "x y z", " " ) ); 144 static assert( isCompatibleArrayAccessStrings( 2, "xy|uv" ) ); 145 static assert( isCompatibleArrayAccessStrings( 3, "abc|efg" ) ); 146 static assert( !isCompatibleArrayAccessStrings( 3, "abc|afg" ) ); 147 static assert( !isCompatibleArrayAccessStrings( 3, "xxy|uv" ) ); 148 static assert( isCompatibleArrayAccessStrings( 3, "x,y,z;u,v,t", ",", ";" ) ); 149 static assert( getIndex( "x y z", "x", " " ) == 0 ); 150 static assert( getIndex( "x y z", "y", " " ) == 1 ); 151 static assert( getIndex( "x y z", "z", " " ) == 2 ); 152 static assert( getIndex( "x|dx|y|dy", "dx", "|", ";" ) == 1 ); 153 static assert( getIndex( "x|dx|y|dy", "1dx", "|", ";" ) == -1 ); 154 155 static assert( oneOfAccessAll("xyz","xy") ); 156 static assert( oneOfAccessAll("xyz","yx") ); 157 static assert( oneOfAccessAll("xyz","xxxxyxyyyz") ); 158 static assert( oneOfAccessAll("x,y,z","xxxxyxyyyz",",") ); 159 static assert( isOneSymbolPerFieldAccessString("xyz") ); 160 static assert( isOneSymbolPerFieldAccessString("x,y,z",",") ); 161 static assert( isOneSymbolPerFieldForAnyAccessString( "xy|uv", "", "|" ) ); 162 static assert( isOneSymbolPerFieldForAnyAccessString( "near far|n f", " ", "|" ) ); 163 164 static assert( !isArrayAccessString("x.y.z","",false) ); 165 static assert( !isArrayAccessString("x.y.z","",true) ); 166 static assert( !isArrayAccessString("x.y.z"," ",false) ); 167 static assert( isArrayAccessString("x.y.z"," ",true) ); 168 static assert( isArrayAccessString("pos.x pos.y pos.z vel.x vel.y vel.z"," ",true) ); 169 170 static assert( isArrayAccessString( "pos vel", " ", true ) ); 171 static assert( isArrayAccessString( "abcd", " ", true ) ); 172 static assert( isArrayAccessString( "a1 a2", " ", true ) ); 173 static assert( isArrayAccessString( "ok.no", " ", true ) ); 174 auto fstr = "pos.x pos.y vel.x vel.y"; 175 assert( isArrayAccessString( fstr, " ", true ) ); 176 assert( !isArrayAccessString( fstr[0 .. $-1], " ", true ) ); 177 assert( !isArrayAccessString( "ok.1", " ", true ) ); 178 assert( !isArrayAccessString( "1abcd", " ", true ) ); 179 assert( !isArrayAccessString( "not 2ok", " ", true ) ); 180 } 181 182 pure 183 { 184 185 bool isValueAccessString( in string as, bool allowDot=false ) 186 { 187 return as.length > 0 && 188 startsWithAllowedChars(as) && 189 (allowDot?(all!(a=>isValueAccessString(a))(as.split("."))):allowedCharsOnly(as)); 190 } 191 192 bool startsWithAllowedChars( in string as ) 193 { 194 switch(as[0]) 195 { 196 case 'a': .. case 'z': goto case; 197 case 'A': .. case 'Z': goto case; 198 case '_': return true; 199 default: return false; 200 } 201 } 202 203 bool allowedCharsOnly( in string as ) 204 { 205 foreach( c; as ) if( !allowedChar(c) ) return false; 206 return true; 207 } 208 209 bool allowedChar( in char c ) 210 { 211 switch(c) 212 { 213 case 'a': .. case 'z': goto case; 214 case 'A': .. case 'Z': goto case; 215 case '0': .. case '9': goto case; 216 case '_': return true; 217 default: return false; 218 } 219 } 220 221 }