Thread overview |
---|
February 08, 2021 Dimensions in compile time | ||||
---|---|---|---|---|
| ||||
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? |
February 08, 2021 Re: Dimensions in compile time | ||||
---|---|---|---|---|
| ||||
Posted in reply to Vindex | 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. |
February 08, 2021 Re: Dimensions in compile time | ||||
---|---|---|---|---|
| ||||
Posted in reply to Basile B. | 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:
>> [...]
>
> 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.
well I didn't realize but static array are not handled. I think this is because in first place this was made for a specific usage that was a serializer.
|
February 08, 2021 Re: Dimensions in compile time | ||||
---|---|---|---|---|
| ||||
Posted in reply to Basile B. | 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;
}
|
February 08, 2021 Re: Dimensions in compile time | ||||
---|---|---|---|---|
| ||||
Posted in reply to Rumbu | 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:
>> [...]
>
> 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;
> }
yeah you're right, strings were a special case (I remember now) so that stuff could be stored as literals.
|
February 08, 2021 Re: Dimensions in compile time | ||||
---|---|---|---|---|
| ||||
Posted in reply to Basile B. | On Monday, 8 February 2021 at 13:13:33 UTC, Basile B. wrote:
> 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:
>>> [...]
>>
>> 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;
>> }
>
> yeah you're right, strings were a special case (I remember now) so that stuff could be stored as literals.
well to OP just dont use my dimensionCount template ^^. it should have been declared with the "package" protection in first place; not public.
|
February 08, 2021 Re: Dimensions in compile time | ||||
---|---|---|---|---|
| ||||
Posted in reply to Basile B. | Thanks everyone! The solution that works for me now looks like this: template ndim(T) { static if (std.traits.isArray!T) { static if (is(typeof(T.init[0]))) { alias SubArrayType = typeof(T.init[0]); enum ndim = ndim!SubArrayType + 1; } else enum ndim = 1; } else enum ndim = 0; } unittest { assert(ndim!(int[]) == 1); assert(ndim!(int[][]) == 2); assert(ndim!(int[4][3]) == 2); assert(ndim!(int[][2][]) == 3); assert(ndim!(string) == 1); } |
February 08, 2021 Re: Dimensions in compile time | ||||
---|---|---|---|---|
| ||||
Posted in reply to Vindex | On Monday, 8 February 2021 at 13:27:14 UTC, Vindex wrote:
> Thanks everyone!
>
> The solution that works for me now looks like this:
>
>
> template ndim(T) {
> static if (std.traits.isArray!T) {
> static if (is(typeof(T.init[0]))) {
> alias SubArrayType = typeof(T.init[0]);
> enum ndim = ndim!SubArrayType + 1;
> }
> else enum ndim = 1;
> }
> else enum ndim = 0;
> }
> unittest {
> assert(ndim!(int[]) == 1);
> assert(ndim!(int[][]) == 2);
> assert(ndim!(int[4][3]) == 2);
> assert(ndim!(int[][2][]) == 3);
> assert(ndim!(string) == 1);
> }
Nice. You should look at Rumbu solution too. It possibly has a better behavior toward the recursive expansion. Also interesting to learn the more advanced use of "is".
|
February 08, 2021 Re: Dimensions in compile time | ||||
---|---|---|---|---|
| ||||
Posted in reply to Rumbu | 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.
|
Copyright © 1999-2021 by the D Language Foundation