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