1 /// Contains mixing for easy swizzling 2 module godot.util.swizzle; 3 4 import std.array; 5 import std.string; 6 import std.algorithm; 7 8 // used as: 9 // 10 // static if (N == 2 || N == 3 || N == 4) { 11 // static if (N == 2) enum AccessString = "x y|w h|u v"; 12 // else 13 // static if (N == 3) enum AccessString = "x y z|w h d|u v t|r g b"; 14 // else 15 // static if (N == 4) enum AccessString = "x y z w|r g b a"; 16 17 // mixin accessByString!(N, T, "data", AccessString); 18 // } 19 20 mixin template accessByString( T, size_t N, string data, string AS, string VVASES=" ", string VVASVS="|") 21 if( isCompatibleArrayAccessStrings(N,AS,VVASES,VVASVS) ) { 22 pure @property { 23 T opDispatch(string v)() const if( getIndex(AS,v,VVASES,VVASVS) != -1 ) { 24 mixin( format( "return this.%s[%d];", data, getIndex(AS,v,VVASES,VVASVS) ) ); 25 } 26 27 ref T opDispatch(string v)() if( getIndex(AS,v,VVASES,VVASVS) != -1 ) { 28 mixin( format( "return this.%s[%d];", data, getIndex(AS,v,VVASES,VVASVS) ) ); 29 } 30 31 static if( isOneSymbolPerFieldForAnyAccessString(AS,VVASES,VVASVS) ) { 32 auto opDispatch(string v)() const if( v.length > 1 && oneOfAnyAccessAll(AS,v,VVASES,VVASVS) ) { 33 static string gen() { 34 string[] res; 35 foreach( i, sym; v ) 36 res ~= format( "this.%s[%d]", data, getIndex( AS, ""~sym, VVASES, VVASVS ) ); 37 return res.join(","); 38 } 39 40 mixin( `return Vector!(T, v.length)(` ~ gen() ~ `);` ); 41 } 42 43 auto opDispatch(string v,U)( in U b ) 44 if( v.length > 1 && oneOfAnyAccessAll(AS,v,VVASES,VVASVS) && 45 isCompatibleArrayAccessString(v.length,v) && 46 ( isSpecVector!(v.length,T,U) || ( isDynamicVector!U && is(typeof(T(U.datatype.init))) ) ) ) { 47 static if( b.isDynamic ) enforce( v.length == b.length ); 48 49 static string gen() { 50 string[] res; 51 foreach( i, sym; v ) 52 res ~= format( "this.%s[%d] = T( b[%d] );", data, 53 getIndex( AS, ""~sym, VVASES, VVASVS ), i ); 54 return res.join("\n"); 55 } 56 57 mixin( gen() ); 58 return b; 59 } 60 } 61 } 62 } 63 64 /// compatible for creating access dispatches 65 pure bool isCompatibleArrayAccessStrings( size_t N, string str, string sep1="", string sep2="|" ) 66 in { assert( sep1 != sep2 ); } do { 67 auto strs = str.split(sep2); 68 foreach( s; strs ) 69 if( !isCompatibleArrayAccessString(N,s,sep1) ) 70 return false; 71 72 string[] fa; 73 foreach( s; strs ) 74 fa ~= s.split(sep1); 75 76 foreach( ref v; fa ) v = strip(v); 77 78 foreach( i, a; fa ) 79 foreach( j, b; fa ) 80 if( i != j && a == b ) return false; 81 82 return true; 83 } 84 85 86 /// compatible for creating access dispatches 87 pure bool isCompatibleArrayAccessString( size_t N, string str, string sep="" ) { 88 return N == getAccessFieldsCount(str,sep) && isArrayAccessString(str,sep); 89 } 90 91 /// 92 pure bool isArrayAccessString( in string as, in string sep="", bool allowDot=false ) { 93 if( as.length == 0 ) return false; 94 auto splt = as.split(sep); 95 foreach( i, val; splt ) 96 if( !isValueAccessString(val,allowDot) || canFind(splt[0..i],val) ) 97 return false; 98 return true; 99 } 100 101 /// 102 pure size_t getAccessFieldsCount( string str, string sep ) { return str.split(sep).length; } 103 104 /// 105 pure ptrdiff_t getIndex( string as, string arg, string sep1="", string sep2="|" ) 106 in { assert( sep1 != sep2 ); } do 107 { 108 foreach( str; as.split(sep2) ) 109 foreach( i, v; str.split(sep1) ) 110 if( arg == v ) return i; 111 return -1; 112 } 113 114 /// 115 pure bool oneOfAccess( string str, string arg, string sep="" ) { 116 auto splt = str.split(sep); 117 return canFind(splt,arg); 118 } 119 120 /// 121 pure bool oneOfAccessAll( string str, string arg, string sep="" ) { 122 auto splt = arg.split(""); 123 return all!(a=>oneOfAccess(str,a,sep))(splt); 124 } 125 126 /// 127 pure bool oneOfAnyAccessAll( string str, string arg, string sep1="", string sep2="|" ) 128 in { assert( sep1 != sep2 ); } do 129 { 130 foreach( s; str.split(sep2) ) 131 if( oneOfAccessAll(s,arg,sep1) ) return true; 132 return false; 133 } 134 135 /// check symbol count for access to field 136 pure bool isOneSymbolPerFieldForAnyAccessString( string str, string sep1="", string sep2="|" ) 137 in { assert( sep1 != sep2 ); } do 138 { 139 foreach( s; str.split(sep2) ) 140 if( isOneSymbolPerFieldAccessString(s,sep1) ) return true; 141 return false; 142 } 143 144 /// check symbol count for access to field 145 pure bool isOneSymbolPerFieldAccessString( string str, string sep="" ) { 146 foreach( s; str.split(sep) ) 147 if( s.length > 1 ) return false; 148 return true; 149 } 150 151 pure 152 { 153 154 bool isValueAccessString( in string as, bool allowDot=false ) { 155 return as.length > 0 && 156 startsWithAllowedChars(as) && 157 (allowDot?(all!(a=>isValueAccessString(a))(as.split("."))):allowedCharsOnly(as)); 158 } 159 160 bool startsWithAllowedChars( in string as ) { 161 switch(as[0]) { 162 case 'a': .. case 'z': goto case; 163 case 'A': .. case 'Z': goto case; 164 case '_': return true; 165 default: return false; 166 } 167 } 168 169 bool allowedCharsOnly( in string as ) { 170 foreach( c; as ) if( !allowedChar(c) ) return false; 171 return true; 172 } 173 174 bool allowedChar( in char c ) { 175 switch(c) { 176 case 'a': .. case 'z': goto case; 177 case 'A': .. case 'Z': goto case; 178 case '0': .. case '9': goto case; 179 case '_': return true; 180 default: return false; 181 } 182 } 183 184 }