1 /** 2 * Copyright: © 2014-2015 Anton Gushcha 3 * License: Subject to the terms of the Boost 1.0 license as specified in LICENSE file 4 * Authors: Anton Gushcha <ncrashed@gmail.com> 5 * 6 * Template for aggregates members expection - extension of std.traits; 7 */ 8 module stribog.meta.members; 9 10 import std.traits : isIntegral; 11 import std.typetuple : staticIndexOf; 12 import stribog.meta.base; 13 import stribog.meta.filter; 14 15 /** 16 * More useful version of allMembers trait, that returns only 17 * fields and methods of class/struct/interface/union without 18 * service members like constructors and Object members. 19 * 20 * Note: if Object methods are explicitly override in $(B T) 21 * (not other base class), then the methods are included into 22 * the result. 23 */ 24 template fieldsAndMethods(T) 25 { 26 static if(is(T == class) || is(T == struct) || is(T == interface) || is(T == union)) 27 { 28 /// Getting all inherited members from Object exluding overrided 29 private template derivedFromObject() 30 { 31 alias objectMembers = ExpressionList!(__traits(allMembers, Object)); 32 alias derivedMembers = ExpressionList!(__traits(derivedMembers, T)); 33 34 private template removeDerived(string name) 35 { 36 enum removeDerived = staticIndexOf!(name, derivedMembers); 37 } 38 39 alias derivedFromObject = staticFilter!(removeDerived, objectMembers); 40 } 41 42 /// Filter unrelated symbols like constructors and Object methods 43 private template filterUtil(string name) 44 { 45 static if(name == "this") 46 { 47 enum filterUtil = false; 48 } 49 else 50 { 51 static if(is(T == class)) 52 { 53 enum filterUtil = staticIndexOf!(name, derivedFromObject!()) == -1; 54 } 55 else 56 { 57 enum filterUtil = true; 58 } 59 } 60 } 61 62 alias fieldsAndMethods = staticFilter!(filterUtil, __traits(allMembers, T)); 63 } 64 else 65 { 66 alias fieldsAndMethods = ExpressionList!(); 67 } 68 } 69 /// Example 70 unittest 71 { 72 struct A 73 { 74 string a; 75 float b; 76 void foo(); 77 string bar(float); 78 } 79 80 class B 81 { 82 string a; 83 float b; 84 void foo() {} 85 string bar(float) {return "";} 86 } 87 88 class C 89 { 90 override string toString() const {return "";} 91 } 92 93 static assert(staticEqual!(StrictExpressionList!(fieldsAndMethods!A), StrictExpressionList!("a", "b", "foo", "bar"))); 94 static assert(staticEqual!(StrictExpressionList!(fieldsAndMethods!B), StrictExpressionList!("a", "b", "foo", "bar"))); 95 static assert(staticEqual!(StrictExpressionList!(fieldsAndMethods!C), StrictExpressionList!("toString"))); 96 } 97 98 /// Checks if $(B T1) and $(B T2) have an operator $(B op): T1 op T2 99 template hasOp(T1, T2, string op) 100 { 101 static if(isIntegral!T1 && isIntegral!T2 && op == "/") 102 { 103 enum hasOp = true; // to not fall into 0 divizion 104 } else 105 { 106 enum hasOp = __traits(compiles, mixin("T1.init" ~ op ~ "T2.init")); 107 } 108 } 109 /// 110 unittest 111 { 112 static assert(hasOp!(float, int, "*")); 113 static assert(hasOp!(double, double, "/")); 114 static assert(!hasOp!(double, void, "/")); 115 static assert(hasOp!(int, int, "/")); 116 117 struct B {} 118 119 struct A 120 { 121 void opBinary(string op)(B b) if(op == "*") {} 122 } 123 124 static assert(hasOp!(A, B, "*")); 125 } 126 127 /// Shortcut for trait allMembers 128 template allMembers(T) 129 { 130 alias allMembers = ExpressionList!(__traits(allMembers, T)); 131 } 132 133 // hack to feed up parser a traits alias 134 private template Alias(alias T) 135 { 136 alias Alias = T; 137 } 138 139 /// Shortcut for getMember 140 template getMember(T, string name) 141 { 142 alias getMember = Alias!(__traits(getMember, T, name)); 143 }