1 module sily.meta; 2 package(sily) { 3 import std.array; 4 import std.string; 5 import std.algorithm; 6 7 8 // for my sanity or for sanity of anyone who's seeing this 9 // is(typeof(A + B)) is basically a check if two types 10 // are compatible together. 11 // so 0 + "A" will return false, but 0 + true will return true 12 bool isValidOp(string op, T, R, E = T)() pure { 13 mixin(`return is( typeof( mixin("T.init"` ~ op ~ `"R.init" ) ): E );`); 14 } 15 16 /* -------------------------------------------------------------------------- */ 17 /* LOTS OF STUFF IS PULLED FROM HERE: */ 18 /* HTTPS://GITHUB.COM/DEXSET/DESCORE/TREE/MASTER/IMPORT/DES */ 19 /* TBH THIS WHOLE FILE IS FROM THIS REPO EXCEPT ISVALIDOP */ 20 /* BUT IT WORKS AND I DON'T EVEN WANT TO TRY TO UNDERSTAND */ 21 /* WHAT IS GOING ON HERE */ 22 /* -------------------------------------------------------------------------- */ 23 24 25 // used as: 26 // 27 // static if (N == 2 || N == 3 || N == 4) { 28 // static if (N == 2) enum AccessString = "x y|w h|u v"; 29 // else 30 // static if (N == 3) enum AccessString = "x y z|w h d|u v t|r g b"; 31 // else 32 // static if (N == 4) enum AccessString = "x y z w|r g b a"; 33 34 // mixin accessByString!(N, T, "data", AccessString); 35 // } 36 37 mixin template accessByString( T, size_t N, string data, string AS, string VVASES=" ", string VVASVS="|") 38 if( isCompatibleArrayAccessStrings(N,AS,VVASES,VVASVS) ) { 39 pure @property { 40 T opDispatch(string v)() const if( getIndex(AS,v,VVASES,VVASVS) != -1 ) { 41 mixin( format( "return this.%s[%d];", data, getIndex(AS,v,VVASES,VVASVS) ) ); 42 } 43 44 ref T opDispatch(string v)() if( getIndex(AS,v,VVASES,VVASVS) != -1 ) { 45 mixin( format( "return this.%s[%d];", data, getIndex(AS,v,VVASES,VVASVS) ) ); 46 } 47 48 static if( isOneSymbolPerFieldForAnyAccessString(AS,VVASES,VVASVS) ) { 49 auto opDispatch(string v)() const if( v.length > 1 && oneOfAnyAccessAll(AS,v,VVASES,VVASVS) ) { 50 static string gen() { 51 string[] res; 52 foreach( i, sym; v ) 53 res ~= format( "this.%s[%d]", data, getIndex( AS, ""~sym, VVASES, VVASVS ) ); 54 return res.join(","); 55 } 56 57 mixin( `return Vector!(T, v.length)(` ~ gen() ~ `);` ); 58 } 59 60 auto opDispatch(string v,U)( in U b ) 61 if( v.length > 1 && oneOfAnyAccessAll(AS,v,VVASES,VVASVS) && 62 isCompatibleArrayAccessString(v.length,v) && 63 ( isSpecVector!(v.length,T,U) || ( isDynamicVector!U && is(typeof(T(U.datatype.init))) ) ) ) { 64 static if( b.isDynamic ) enforce( v.length == b.length ); 65 66 static string gen() { 67 string[] res; 68 foreach( i, sym; v ) 69 res ~= format( "this.%s[%d] = T( b[%d] );", data, 70 getIndex( AS, ""~sym, VVASES, VVASVS ), i ); 71 return res.join("\n"); 72 } 73 74 mixin( gen() ); 75 return b; 76 } 77 } 78 } 79 } 80 81 /// compatible for creating access dispatches 82 pure bool isCompatibleArrayAccessStrings( size_t N, string str, string sep1="", string sep2="|" ) 83 in { assert( sep1 != sep2 ); } do { 84 auto strs = str.split(sep2); 85 foreach( s; strs ) 86 if( !isCompatibleArrayAccessString(N,s,sep1) ) 87 return false; 88 89 string[] fa; 90 foreach( s; strs ) 91 fa ~= s.split(sep1); 92 93 foreach( ref v; fa ) v = strip(v); 94 95 foreach( i, a; fa ) 96 foreach( j, b; fa ) 97 if( i != j && a == b ) return false; 98 99 return true; 100 } 101 102 103 /// compatible for creating access dispatches 104 pure bool isCompatibleArrayAccessString( size_t N, string str, string sep="" ) { 105 return N == getAccessFieldsCount(str,sep) && isArrayAccessString(str,sep); 106 } 107 108 /// 109 pure bool isArrayAccessString( in string as, in string sep="", bool allowDot=false ) { 110 if( as.length == 0 ) return false; 111 auto splt = as.split(sep); 112 foreach( i, val; splt ) 113 if( !isValueAccessString(val,allowDot) || canFind(splt[0..i],val) ) 114 return false; 115 return true; 116 } 117 118 /// 119 pure size_t getAccessFieldsCount( string str, string sep ) { return str.split(sep).length; } 120 121 /// 122 pure ptrdiff_t getIndex( string as, string arg, string sep1="", string sep2="|" ) 123 in { assert( sep1 != sep2 ); } do 124 { 125 foreach( str; as.split(sep2) ) 126 foreach( i, v; str.split(sep1) ) 127 if( arg == v ) return i; 128 return -1; 129 } 130 131 /// 132 pure bool oneOfAccess( string str, string arg, string sep="" ) { 133 auto splt = str.split(sep); 134 return canFind(splt,arg); 135 } 136 137 /// 138 pure bool oneOfAccessAll( string str, string arg, string sep="" ) { 139 auto splt = arg.split(""); 140 return all!(a=>oneOfAccess(str,a,sep))(splt); 141 } 142 143 /// 144 pure bool oneOfAnyAccessAll( string str, string arg, string sep1="", string sep2="|" ) 145 in { assert( sep1 != sep2 ); } do 146 { 147 foreach( s; str.split(sep2) ) 148 if( oneOfAccessAll(s,arg,sep1) ) return true; 149 return false; 150 } 151 152 /// check symbol count for access to field 153 pure bool isOneSymbolPerFieldForAnyAccessString( string str, string sep1="", string sep2="|" ) 154 in { assert( sep1 != sep2 ); } do 155 { 156 foreach( s; str.split(sep2) ) 157 if( isOneSymbolPerFieldAccessString(s,sep1) ) return true; 158 return false; 159 } 160 161 /// check symbol count for access to field 162 pure bool isOneSymbolPerFieldAccessString( string str, string sep="" ) { 163 foreach( s; str.split(sep) ) 164 if( s.length > 1 ) return false; 165 return true; 166 } 167 168 pure 169 { 170 171 bool isValueAccessString( in string as, bool allowDot=false ) { 172 return as.length > 0 && 173 startsWithAllowedChars(as) && 174 (allowDot?(all!(a=>isValueAccessString(a))(as.split("."))):allowedCharsOnly(as)); 175 } 176 177 bool startsWithAllowedChars( in string as ) { 178 switch(as[0]) { 179 case 'a': .. case 'z': goto case; 180 case 'A': .. case 'Z': goto case; 181 case '_': return true; 182 default: return false; 183 } 184 } 185 186 bool allowedCharsOnly( in string as ) { 187 foreach( c; as ) if( !allowedChar(c) ) return false; 188 return true; 189 } 190 191 bool allowedChar( in char c ) { 192 switch(c) { 193 case 'a': .. case 'z': goto case; 194 case 'A': .. case 'Z': goto case; 195 case '0': .. case '9': goto case; 196 case '_': return true; 197 default: return false; 198 } 199 } 200 201 } 202 }