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 }