1 /*******************************************************************************
2 
3     Traits specializing in finding out indirections within compound
4     types.
5 
6     NB: because this module is often used as purely compile-time dependency it
7         used built-in asserts instead of `ocean.core.Test` to reduce amount of
8         cyclic imports. `ocean.meta` modules in general are not supposed to
9         import anything outside of `ocean.meta`.
10 
11     Copyright:
12         Copyright (c) 2017 dunnhumby Germany GmbH.
13         All rights reserved.
14 
15     License:
16         Boost Software License Version 1.0. See LICENSE_BOOST.txt for details.
17         Alternatively, this file may be distributed under the terms of the Tango
18         3-Clause BSD License (see LICENSE_BSD.txt for details).
19 
20 *******************************************************************************/
21 
22 module ocean.meta.traits.Indirections;
23 
24 import ocean.meta.types.ReduceType;
25 import ocean.meta.types.Arrays;
26 import ocean.meta.traits.Basic;
27 
28 version (unittest)
29 {
30     import ocean.meta.types.Qualifiers;
31 }
32 
33 /*******************************************************************************
34 
35     Evaluates to true if a variable of any type in T is a reference type or has
36     members or elements of reference types. References are
37      - dynamic and associative arrays,
38      - pointers (including function pointers) and delegates,
39      - classes.
40 
41     Types that are not suitable to declare a variable, i.e. ``void`` and
42     function types (the base types of function pointers) are not references.
43 
44     If T is empty then the result is false.
45 
46     Params:
47         T = types to check (with no type the result is false)
48 
49 *******************************************************************************/
50 
51 public template hasIndirections ( T... )
52 {
53     static immutable hasIndirections = ReduceType!(T, HasIndirectionsReducer);
54 }
55 
56 ///
57 unittest
58 {
59     static assert (!hasIndirections!(int));
60     static assert ( hasIndirections!(int[int]));
61     static assert (!hasIndirections!(void));
62 
63     static struct S
64     {
65         union
66         {
67             int[] arr;
68             double f;
69         }
70     }
71 
72     static assert ( hasIndirections!(S[5]));
73 }
74 
75 unittest
76 {
77     static struct S1 { }
78 
79     static struct S2
80     {
81         const(S1)[5] a;
82 
83         union
84         {
85             immutable(int)[2][2] x;
86             S1 y;
87         }
88     }
89 
90     static assert (!hasIndirections!(S2));
91 
92     static struct S3
93     {
94         void delegate(int) x;
95     }
96 
97     static assert ( hasIndirections!(S3));
98 
99     static struct S4
100     {
101         immutable(int[])[10] x;
102     }
103 
104     static assert ( hasIndirections!(S4));
105 }
106 
107 private struct HasIndirectionsReducer
108 {
109     alias bool Result;
110 
111     Result visit ( T ) ( )
112     {
113         return isReferenceType!(T);
114     }
115 }
116 
117 /*******************************************************************************
118 
119     Checks if T or any of its subtypes is a multi-dimensional dynamic array.
120 
121     Params:
122         T = type to check
123 
124     Returns:
125         true if T or any of its subtypes is a multi-dimensional dynamic array or
126         false otherwise.
127 
128 *******************************************************************************/
129 
130 public template containsMultiDimensionalDynamicArrays ( T )
131 {
132     static immutable containsMultiDimensionalDynamicArrays =
133         ReduceType!(T, MultiDimArraysReducer);
134 }
135 
136 ///
137 unittest
138 {
139     static assert (!containsMultiDimensionalDynamicArrays!(int));
140     static assert ( containsMultiDimensionalDynamicArrays!(int[][]));
141 
142     static struct S
143     {
144         int[][] arr;
145     }
146 
147     static assert ( containsMultiDimensionalDynamicArrays!(S));
148 }
149 
150 private struct MultiDimArraysReducer
151 {
152     alias bool Result;
153 
154     Result visit ( T ) ( )
155     {
156         static if (isArrayType!(T) == ArrayKind.Dynamic)
157             return isArrayType!(ElementTypeOf!(T)) == ArrayKind.Dynamic;
158         else
159             return false;
160     }
161 }
162 
163 unittest
164 {
165     static assert(!containsMultiDimensionalDynamicArrays!(int));
166     static assert(!containsMultiDimensionalDynamicArrays!(int[ ]));
167     static assert(!containsMultiDimensionalDynamicArrays!(int[3]));
168 
169     static assert( containsMultiDimensionalDynamicArrays!(int[ ][ ]));
170     static assert(!containsMultiDimensionalDynamicArrays!(int[3][ ]));
171     static assert(!containsMultiDimensionalDynamicArrays!(int[ ][3]));
172     static assert(!containsMultiDimensionalDynamicArrays!(int[3][3]));
173 
174     static assert( containsMultiDimensionalDynamicArrays!(int[ ][ ][ ]));
175     static assert( containsMultiDimensionalDynamicArrays!(int[3][ ][ ]));
176     static assert(!containsMultiDimensionalDynamicArrays!(int[ ][3][ ]));
177     static assert(!containsMultiDimensionalDynamicArrays!(int[3][3][ ]));
178     static assert( containsMultiDimensionalDynamicArrays!(int[ ][ ][3]));
179     static assert(!containsMultiDimensionalDynamicArrays!(immutable(int[3])[ ][3]));
180     static assert(!containsMultiDimensionalDynamicArrays!(int[ ][3][3]));
181     static assert(!containsMultiDimensionalDynamicArrays!(int[3][3][3]));
182 
183     static assert(!containsMultiDimensionalDynamicArrays!(void));
184     static assert(!containsMultiDimensionalDynamicArrays!(void[]));
185     static assert( containsMultiDimensionalDynamicArrays!(const(void[])[]));
186     static assert(!containsMultiDimensionalDynamicArrays!(void[][3]));
187 
188     struct A
189     {
190         int x;
191         char[] y;
192         float[][][3][] z;
193     }
194 
195     struct B
196     {
197         A[] a;
198     }
199 
200     static assert(containsMultiDimensionalDynamicArrays!(A));
201 
202     struct C
203     {
204         int x;
205         float[][3][] y;
206         const(char)[] z;
207     }
208 
209     static assert(!containsMultiDimensionalDynamicArrays!(C));
210 }
211 
212 /*******************************************************************************
213 
214     Checks if T or any of its subtypes is a dynamic array.
215 
216     Params:
217         T = type to check
218 
219     Returns:
220         true if T or any of its subtypes is a dynamic array or
221         false otherwise.
222 
223 *******************************************************************************/
224 
225 public template containsDynamicArray ( T )
226 {
227     static immutable containsDynamicArray =
228         ReduceType!(T, DynArrayReducer);
229 }
230 
231 ///
232 unittest
233 {
234     static assert (!containsDynamicArray!(void));
235 
236     static struct S
237     {
238         int[] x;
239     }
240     static assert ( containsDynamicArray!(const(S)));
241 
242     static struct S2
243     {
244         struct Arr { const(int[]) x; }
245         Arr[3][4] arr;
246     }
247 
248     static assert( containsDynamicArray!(immutable(S2)));
249 }
250 
251 private struct DynArrayReducer
252 {
253     alias bool Result;
254 
255     Result visit ( T ) ( )
256     {
257         return isArrayType!(T) == ArrayKind.Dynamic;
258     }
259 }