1 // Some types which are dynamic arrays. 2 static assert( isDynamicArray!(int[])); 3 static assert( isDynamicArray!(const int[])); 4 static assert( isDynamicArray!(inout int[])); 5 static assert( isDynamicArray!(shared(int)[])); 6 static assert( isDynamicArray!string); 7 8 static assert( isDynamicArray!(typeof([1, 2, 3]))); 9 static assert( isDynamicArray!(typeof("dlang"))); 10 11 int[] arr; 12 static assert( isDynamicArray!(typeof(arr))); 13 14 // Some types which aren't dynamic arrays. 15 static assert(!isDynamicArray!int); 16 static assert(!isDynamicArray!(int*)); 17 static assert(!isDynamicArray!real); 18 19 static struct S 20 { 21 int[] arr; 22 } 23 static assert(!isDynamicArray!S); 24 25 // The struct itself isn't considered a dynamic array, 26 // but its member variable is when checked directly. 27 static assert( isDynamicArray!(typeof(S.arr))); 28 29 // Static arrays. 30 static assert(!isDynamicArray!(int[5])); 31 static assert(!isDynamicArray!(const(int)[5])); 32 33 int[2] sArr = [42, 97]; 34 static assert(!isDynamicArray!(typeof(sArr))); 35 36 // While a static array is not a dynamic array, 37 // a slice of a static array is a dynamic array. 38 static assert( isDynamicArray!(typeof(sArr[]))); 39 40 // Dynamic array of static arrays. 41 static assert( isDynamicArray!(long[3][])); 42 43 // Static array of dynamic arrays. 44 static assert(!isDynamicArray!(long[][3])); 45 46 // Associative array. 47 static assert(!isDynamicArray!(int[string])); 48 49 // While typeof(null) gets treated as void[] in some contexts, it is 50 // distinct from void[] and is not considered to be a dynamic array. 51 static assert(!isDynamicArray!(typeof(null))); 52 53 // However, naturally, if null is cast to a dynamic array, it's a 54 // dynamic array, since the cast forces the type. 55 static assert( isDynamicArray!(typeof(cast(int[]) null))); 56 57 enum E : int[] 58 { 59 a = [1, 2, 3], 60 } 61 62 // Enums do not count. 63 static assert(!isDynamicArray!E); 64 65 static struct AliasThis 66 { 67 int[] arr; 68 alias this = arr; 69 } 70 71 // Other implicit conversions do not count. 72 static assert(!isDynamicArray!AliasThis);
Whether the given type is a dynamic array (or what is sometimes referred to as a slice, since a dynamic array in D is a slice of memory).
Note that this does not include implicit conversions or enum types. The type itself must be a dynamic array.
Remember that D's dynamic arrays are essentially:
where ptr points to the first element in the array, and length is the number of elements in the array.
A dynamic array is not a pointer (unlike arrays in C/C++), and its elements do not live inside the dynamic array itself. The dynamic array is simply a slice of memory and does not own or manage its own memory. It can be a slice of any piece of memory, including GC-allocated memory, the stack, malloc-ed memory, etc. (with what kind of memory it is of course being determined by how the dynamic array was created in the first place) - though if you do any operations on it which end up requiring allocation (e.g. appending to it if it doesn't have the capacity to expand in-place, which it won't if it isn't a slice of GC-allocated memory), then that reallocation will result in the dynamic array being a slice of newly allocated, GC-backed memory (regardless of what it was a slice of before), since it's the GC that deals with those allocations.
As long as code just accesses the elements or members of the dynamic array - or reduces its length so that it's a smaller slice - it will continue to point to whatever block of memory it pointed to originally. And because the GC makes sure that appending to a dynamic array does not stomp on the memory of any other dynamic arrays, appending to a dynamic array will not affect any other dynamic array which is a slice of that same block of memory whether a reallocation occurs or not.
Regardless, since what allocated the memory that the dynamic array is a slice of is irrevelant to the type of the dynamic array, whether a given type is a dynamic array has nothing to do with the kind of memory that's backing it. A dynamic array which is a slice of a static array of int is the the same type as a dynamic array of int allocated with new - i.e. both are int[]. So, this trait will not tell you anything about what kind of memory a dynamic array is a slice of. It just tells you whether the type is a dynamic array or not.
If for some reason, it matters for a function what kind of memory backs one of its parameters which is a dynamic array, or it needs to be made clear whether the function will possibly cause that dynamic array to be reallocated, then that needs to be indicated by the documentation and cannot be enforced with a template constraint. A template constraint can enforce that a type used with a template meets certain criteria (e.g. that it's a dynamic array), but it cannot enforce anything about how the template actually uses the type.
However, it is possible to enforce that a function doesn't use any operations on a dynamic array which might cause it to be reallocated by marking that function as @nogc.
In most cases though, code can be written to not care what kind of memory backs a dynamic array, because none of the operations on a dynamic array actually care what kind of memory it's a slice of. It mostly just matters when you need to track the lifetime of the memory, because it wasn't allocated by the GC, or when it matters whether a dynamic array could be reallocated or not (e.g. because the code needs to have that dynamic array continue to point to the same block of memory).