Dimensions in compile time

Petar Petar
Mon Feb 8 21:42:07 UTC 2021


On Monday, 8 February 2021 at 13:09:53 UTC, Rumbu wrote:
> On Monday, 8 February 2021 at 12:19:26 UTC, Basile B. wrote:
>> On Monday, 8 February 2021 at 11:42:45 UTC, Vindex wrote:
>>> size_t ndim(A)(A arr) {
>>>     return std.algorithm.count(typeid(A).to!string, '[');
>>> }
>>>
>>> Is there a way to find out the number of dimensions in an 
>>> array at compile time?
>>
>> yeah.
>>
>> ---
>> template dimensionCount(T)
>> {
>>     static if (isArray!T)
>>     {
>>         static if (isMultiDimensionalArray!T)
>>         {
>>             alias DT = typeof(T.init[0]);
>>             enum dimensionCount = dimensionCount!DT + 1;
>>         }
>>         else enum dimensionCount = 1;
>>     }
>>     else enum dimensionCount = 0;
>> }
>> ///
>> unittest
>> {
>>     static assert(dimensionCount!char == 0);
>>     static assert(dimensionCount!(string[]) == 1);
>>     static assert(dimensionCount!(int[]) == 1);
>>     static assert(dimensionCount!(int[][]) == 2);
>>     static assert(dimensionCount!(int[][][]) == 3);
>> }
>> ---
>>
>> that can be rewritten using some phobos traits too I think, 
>> but this piece of code is very old now, more like learner 
>> template.
>
> dimensionCount!string should be 2.
>
> My take without std.traits:
>
> template rank(T: U[], U)
> {
>    enum rank = 1 + rank!U;
> }
>
> template rank(T: U[n], size_t n)
> {
>     enum rank = 1 + rank!U;
> }
>
> template rank(T)
> {
>     enum rank = 0;
> }

Here's the version I actually wanted to write:

---
enum rank(T) = is(T : U[], U) ? 1 + rank!U : 0;
---

But it's not possible, because of 2 language limitations:
1. Ternary operator doesn't allow the different branches to be 
specialized like `static if` even if the condition is a 
compile-time constant.
2. `is()` expressions can only introduce an identifier if inside 
a `static if`.

Otherwise, I'd consider this the "idiomatic" / "typical" D 
solution, since unlike C++, D code rarely (*) overloads and 
specializes templates.

(*) Modern Phobos(-like) code.

---
template rank(T)
{
     static if (is(T : U[], U))
         enum rank = 1 + rank!U;
     else
         enum rank = 0;
}

unittest
{
     static assert( rank!(char) == 0);
     static assert( rank!(char[]) == 1);
     static assert( rank!(string) == 1);
     static assert( rank!(string[]) == 2);
     static assert( rank!(string[][]) == 3);
     static assert( rank!(string[][][]) == 4);
}
---


Otherwise, the shortest and cleanest solution IMO is this one:

---
enum rank(T : U[], U) = is(T : U[], U) ? 1 + rank!U : 0;
enum rank(T) = 0;

unittest
{
     static assert( rank!(char) == 0);
     static assert( rank!(char[]) == 1);
     static assert( rank!(string) == 1);
     static assert( rank!(string[]) == 2);
     static assert( rank!(string[][]) == 3);
     static assert( rank!(string[][][]) == 4);

     static assert( rank!(char) == 0);
     static assert( rank!(char[1]) == 1);
     static assert( rank!(char[1][2]) == 2);
     static assert( rank!(char[1][2][3]) == 3);
     static assert( rank!(char[1][2][3][4]) == 4);
}
---

- Use eponymous template syntax shorthand
- Static arrays are implicitly convertible to dynamic arrays, so 
we can merge the two implementations.


More information about the Digitalmars-d-learn mailing list