1 module des.util.stdext.traits; 2 3 public 4 { 5 import std.traits; 6 import std.typecons; 7 import std.typetuple; 8 } 9 10 /// 11 template hasAttrib(alias S,alias f) 12 { 13 enum hasAttrib = impl!(__traits(getAttributes,f)); 14 15 template impl(Attr...) 16 { 17 static if( Attr.length == 0 ) 18 { 19 version(tracehasattribimpl) pragma(msg, "empty: ",S,"->",Attr ); 20 enum impl=false; 21 } 22 else static if( Attr.length == 1 ) 23 { 24 version(tracehasattribimpl) pragma(msg, "single: ",S,"->",Attr ); 25 static if( __traits(compiles,typeof(S)) && 26 __traits(compiles,typeof(Attr[0])) ) 27 { 28 version(tracehasattribimpl) pragma(msg, " check as values: ",S,"==",Attr[0] ); 29 enum impl = Attr[0] == S; 30 } 31 else static if( __traits(compiles,is(Attr[0]==S)) ) 32 { 33 version(tracehasattribimpl) pragma(msg, " check as types: is(",S,"==",Attr[0],")" ); 34 enum impl = is( Attr[0] == S ); 35 } 36 else 37 { 38 version(tracehasattribimpl) pragma(msg, " no check: false" ); 39 enum impl = false; 40 } 41 } 42 else 43 { 44 version(tracehasattribimpl) 45 { 46 pragma(msg, "many: ",S,"->",Attr ); 47 pragma(msg, " p1: ",Attr[0..$/2] ); 48 pragma(msg, " p2: ",Attr[$/2..$] ); 49 } 50 enum impl = impl!(Attr[0..$/2]) || impl!(Attr[$/2..$]); 51 } 52 } 53 } 54 55 /// 56 unittest 57 { 58 enum clot; 59 size_t zlot(string s){ return s.length; } 60 61 void fnc1() @clot {} 62 void fnc2() @clot @zlot("ok") {} 63 void fnc3() @zlot("abc") {} 64 65 static assert( hasAttrib!(clot,fnc1) ); 66 static assert( hasAttrib!(clot,fnc2) ); 67 static assert( hasAttrib!(2,fnc2) ); 68 static assert( !hasAttrib!(clot,fnc3) ); 69 static assert( hasAttrib!(3,fnc3) ); 70 } 71 72 template isString(alias s) { enum isString = is( typeof(s) == string ); } 73 74 unittest 75 { 76 static assert( isString!"hello" ); 77 } 78 79 /// 80 template staticFilter(alias F, T...) 81 { 82 static if (T.length == 0) 83 { 84 alias staticFilter = TypeTuple!(); 85 } 86 else static if (T.length == 1) 87 { 88 static if( F!(T[0]) ) 89 alias staticFilter = TypeTuple!(T[0]); 90 else alias staticFilter = TypeTuple!(); 91 } 92 else 93 { 94 alias staticFilter = 95 TypeTuple!( 96 staticFilter!(F, T[ 0 .. $/2]), 97 staticFilter!(F, T[$/2 .. $ ])); 98 } 99 } 100 101 /// 102 struct TemplateVarDef( alias string N, Args... ) 103 { 104 alias name = N; 105 alias types = Args; 106 } 107 108 /// 109 template isTemplateVarDef(T) 110 { 111 enum isTemplateVarDef = is( typeof( impl(T.init) ) ); 112 void impl(alias string N, Args...)( TemplateVarDef!(N,Args) x ){} 113 } 114 115 unittest 116 { 117 static assert( !isTemplateVarDef!float ); 118 static assert( isTemplateVarDef!(TemplateVarDef!("hello", string, int)) ); 119 } 120 121 /// 122 mixin template DefineTemplateVars( alias Trg, List... ) 123 if( allSatisfy!( isTemplateVarDef, List ) ) 124 { 125 static if( List.length == 0 ) {} 126 else static if( List.length == 1 ) 127 { 128 mixin( "Trg!(List[0].types) " ~ List[0].name ~ ";" ); 129 } 130 else 131 { 132 mixin DefineTemplateVars!(Trg,List[0..$/2]); 133 mixin DefineTemplateVars!(Trg,List[$/2..$]); 134 } 135 } 136 137 /// 138 unittest 139 { 140 import std..string; 141 142 static struct X(Args...) 143 { 144 void func( Args args ) 145 { 146 static if( Args.length == 1 && is( Args[0] == string ) ) 147 assert( args[0] == "hello" ); 148 else static if( Args.length == 2 && is( Args[0] == float ) && is( Args[1] == int ) ) 149 { 150 import std.math; 151 assert( abs(args[0] - 3.14) < float.epsilon ); 152 assert( args[1] == 12 ); 153 } 154 else static assert(0,"undefined for this unittest"); 155 } 156 } 157 158 static class ZZ 159 { 160 mixin DefineTemplateVars!( X, TemplateVarDef!("ok",string), 161 TemplateVarDef!("da",float,int), 162 ); 163 } 164 165 auto zz = new ZZ; 166 static assert( is( typeof(zz.ok) == X!string ) ); 167 static assert( is( typeof(zz.da) == X!(float,int) ) ); 168 zz.ok.func( "hello" ); 169 zz.da.func( 3.14, 12 ); 170 } 171 172 /// 173 unittest 174 { 175 enum mark; 176 177 static class A 178 { 179 void s1() @mark {} 180 void f2() {} 181 @mark 182 { 183 void s3( int, string ) {} 184 void s4( float x ) {} 185 } 186 } 187 188 template isVoidMarked(T) 189 { 190 alias isVoidMarked = isVoidMarkedFunc; 191 192 template isVoidMarkedFunc(string n) 193 { 194 static if( __traits(compiles,impl!(__traits(getMember,T,n))) ) 195 enum isVoidMarkedFunc = impl!(__traits(getMember,T,n)); 196 else enum isVoidMarkedFunc = false; 197 198 template impl(alias f) 199 { 200 enum impl = isCallable!f && 201 is( ReturnType!f == void ) && 202 hasAttrib!(mark,f); 203 } 204 } 205 } 206 207 template TemplateVarDefFromMethod(T) 208 { 209 template TemplateVarDefFromMethod(string name) 210 { 211 alias TemplateVarDefFromMethod = TemplateVarDef!(name,ParameterTypeTuple!(__traits(getMember,T,name))); 212 } 213 } 214 215 alias tvd = staticMap!( TemplateVarDefFromMethod!A, staticFilter!(isVoidMarked!A,__traits(allMembers,A)) ); 216 static assert( tvd.length == 3 ); 217 alias exp = TypeTuple!( TemplateVarDef!("s1"), TemplateVarDef!("s3",int,string), TemplateVarDef!("s4",float) ); 218 static assert( is(tvd[0] == exp[0]) ); 219 static assert( is(tvd[1] == exp[1]) ); 220 static assert( is(tvd[2] == exp[2]) ); 221 } 222 223 /++ 224 using: 225 226 void func(T)( T v ) 227 if( isPseudoInterface(Interface,T) ) 228 { 229 } 230 +/ 231 bool isPseudoInterface(I,T, bool _assert=true, string FILE=__FILE__, int LINE=__LINE__ )() 232 { 233 import std..string; 234 import std.conv; 235 bool fail(Args...)( string fmt, Args args ) 236 { 237 if( _assert ) assert( 0, FILE ~ "(" ~ to!string(LINE) ~ ") " ~ format( fmt, args ) ); 238 else return false; 239 } 240 bool checkMembers( I, T, mem... )() 241 { 242 static if( is(typeof(mem[0]) == string ) && mem.length > 1 ) 243 return checkMembers!(I,T,mem[0])() && checkMembers!(I,T,mem[1 .. $])(); 244 else 245 { 246 static if( is( typeof( __traits(getMember, I, mem ) ) ) ) 247 { 248 alias typeof( __traits(getMember, I, mem ) ) i; 249 250 static if( !isCallable!i ) return true; 251 252 static if( __traits(compiles, __traits(getMember, T, mem) ) ) 253 { 254 alias typeof(__traits(getMember, T, mem )) t; 255 256 static if( !isCallable!t ) 257 return fail( "member %s in class %s is not cllable", mem, T.stringof ); 258 else 259 static if( !is( ReturnType!i == ReturnType!t ) ) 260 return fail( "return type of %s in %s must be %s (not %s)", 261 mem, typeid(T), typeid(ReturnType!i), typeid(ReturnType!t) ); 262 else 263 static if( !is( ParameterTypeTuple!i == ParameterTypeTuple!t ) ) 264 return fail( "parameter type tuple of %s in %s must be %s (not %s)", 265 mem, typeid(T), typeid(ParameterTypeTuple!i), typeid(ParameterTypeTuple!t) ); 266 else 267 static if( [ParameterStorageClassTuple!i] != [ParameterStorageClassTuple!t] ) 268 return fail( "parameter storage class tuple of %s in %s must be %s (not %s)", 269 mem, typeid(T), to!string(ParameterStorageClassTuple!i), 270 to!string(ParameterStorageClassTuple!t) ); 271 else 272 return true; 273 } 274 else return fail( "member %s not found in class %s", mem, typeid(T) ); 275 } 276 else return true; 277 } 278 } 279 return checkMembers!(I,T,__traits(allMembers,I))(); 280 } 281 282 /// 283 unittest 284 { 285 interface IFace 286 { 287 void func1( int ); 288 size_t func2( string ); 289 } 290 291 struct Afunc1 { void opCall( int ){} } 292 struct Afunc2 { size_t opCall( string ){ return 0; } } 293 294 class A 295 { 296 Afunc1 func1; 297 Afunc2 func2; 298 } 299 300 struct B 301 { 302 void func1( int ) { } 303 size_t func2( string str ) { return 0; } 304 } 305 306 class C 307 { 308 void func1( int ) { } 309 size_t func2( string str ) { return 0; } 310 } 311 312 class D: A 313 { 314 void func1( int ) { } 315 size_t func2( string str ) { return 0; } 316 } 317 318 class E 319 { 320 int func1; 321 size_t func2( string str ){ return 0; } 322 } 323 324 class F 325 { 326 void func1() { } 327 size_t func2( string str ){ return 0; } 328 } 329 330 class G 331 { 332 void func1( in int ){} 333 size_t func2( string str ){ return 0; } 334 } 335 336 static assert( isPseudoInterface!( IFace,A,false ) ); 337 static assert( isPseudoInterface!( IFace,B,false ) ); 338 static assert( isPseudoInterface!( IFace,C,false ) ); 339 static assert( isPseudoInterface!( IFace,D,false ) ); 340 341 static assert( isPseudoInterface!(A,C,false) ); 342 343 static assert( !isPseudoInterface!( IFace,E,false ) ); 344 static assert( !isPseudoInterface!( IFace,F,false ) ); 345 static assert( !isPseudoInterface!( IFace,G,false ) ); 346 } 347 348 unittest 349 { 350 interface A 351 { 352 void func1( int ); 353 } 354 355 class B : A 356 { 357 void func1( int ) {} 358 int func2( string ){ return 0; } 359 } 360 361 struct Cfunc1 { void opCall( int ) { } } 362 363 interface iB: A 364 { 365 int func2( string ); 366 } 367 368 struct C 369 { 370 Cfunc1 func1; 371 int func2( string ){ return 0; } 372 } 373 374 assert( !isPseudoInterface!( B, C,false ) ); 375 assert( isPseudoInterface!( iB, C,false ) ); 376 }