1 /******************************************************************************* 2 3 Traits for aggregate types - structs, classes, unions. 4 5 Copyright: 6 Copyright (C) 2017 dunnhumby Germany GmbH. All rights reserved. 7 8 License: 9 Boost Software License Version 1.0. See LICENSE_BOOST.txt for details. 10 Alternatively, this file may be distributed under the terms of the Tango 11 3-Clause BSD License (see LICENSE_BSD.txt for details). 12 13 *******************************************************************************/ 14 15 module ocean.meta.traits.Aggregates; 16 17 import ocean.meta.traits.Basic; 18 import ocean.meta.types.Qualifiers; 19 20 /******************************************************************************* 21 22 Checks for presence of method/field with specified name in aggregate. 23 24 In D1 most common idiom is to simply check for `is(typeof(T.something))` but 25 in D2 it can backfire because of UFCS as global names are checked too - thus 26 built-in `__traits(hasMember)` is used instead, which was not available in 27 D1. 28 29 Params: 30 T = aggregate type to check 31 name = method/field name to look for 32 33 Returns: 34 `true` if aggregate T has a method/field with an identifier `name` 35 36 *******************************************************************************/ 37 38 public template hasMember ( T, istring name ) 39 { 40 static assert (isAggregateType!(T)); 41 enum hasMember = __traits(hasMember, T, name); 42 } 43 44 /// 45 unittest 46 { 47 struct S 48 { 49 void foo () { } 50 int x; 51 } 52 53 static assert ( hasMember!(S, "foo")); 54 static assert ( hasMember!(S, "x")); 55 static assert (!hasMember!(S, "bar")); 56 } 57 58 /******************************************************************************* 59 60 Checks for presence of a method with specified name and type for a given 61 aggregate type. 62 63 Params: 64 T = aggregate type to check 65 name = method/field name to look for 66 F = method type (using `function` keyword for static method, `delegate` 67 for non-static ones) 68 69 Returns: 70 `true` if aggregate T has a method/field with an identifier `name` and 71 type `F`. 72 73 *******************************************************************************/ 74 75 public template hasMethod ( T, istring name, F ) 76 { 77 static if (hasMember!(T, name)) 78 { 79 static immutable hasMethod = is(typeof(mixin("&T.init." ~ name)) : F); 80 } 81 else 82 static immutable hasMethod = false; 83 } 84 85 /// 86 unittest 87 { 88 struct S 89 { 90 int foo1 ( double ) { return 0; } 91 static int foo2 ( double ) { return 0; } 92 int delegate(double) foo3; 93 } 94 95 static assert ( hasMethod!(S, "foo1", int delegate(double))); 96 static assert (!hasMethod!(S, "foo1", void delegate(double))); 97 static assert (!hasMethod!(S, "foobar", int delegate(double))); 98 99 static assert ( hasMethod!(S, "foo2", int function(double))); 100 static assert (!hasMethod!(S, "foo3", int delegate(double))); 101 } 102 103 /******************************************************************************* 104 105 Non-recursive aggregate field size calculation 106 107 Returns: 108 sum of individual sizes of all aggregate fields, identical to S.sizeof 109 if `align(1)` is used. 110 111 *******************************************************************************/ 112 113 public template totalMemberSize ( S ) 114 { 115 static assert (isAggregateType!S); 116 117 private size_t calculate ( ) 118 { 119 size_t size; 120 foreach (field; S.init.tupleof) 121 size += typeof(field).sizeof; 122 return size; 123 } 124 125 enum totalMemberSize = calculate(); 126 } 127 128 unittest 129 { 130 struct S { int x; byte[2] y; } 131 static assert (totalMemberSize!S == 6); 132 }