Thread overview
Initializing static arrays without specifying size
Aug 01, 2010
Ziad
Aug 01, 2010
bearophile
Aug 02, 2010
Philippe Sigaud
Aug 02, 2010
bearophile
Aug 02, 2010
BCS
Aug 02, 2010
bearophile
Aug 02, 2010
Ziad Hatahet
Aug 02, 2010
Philippe Sigaud
August 01, 2010
Hi all,

I was wondering how I would go about initializing a static array without explicitly specifying how big it is, given I lay out the contents.

For example, if I do:

int[] a = [1, 2, 3, 4, 5];
auto a = [1, 2, 3, 4, 5];

both statements would result in a heap allocated array (slice). If I
want a static array:

int[5] a = [1, 2, 3, 4, 5];

I'd have to specify the size in advance (5 in this case), which means that adding extra elements later on would require that the size be update.

Is there a way to let the compiler automatically determine the size based on the argument list?
August 01, 2010
Ziad:

> Is there a way to let the compiler automatically determine the size based on the argument list?

I don't know a clean way to do it. See the "related enhancement" here:
http://d.puremagic.com/issues/show_bug.cgi?id=3849
With other people I have proposed the syntax:
int[$] a = [1, 2, 3];

But so far Walter has not shown interest.

Bye,
bearophile
August 02, 2010
On Mon, Aug 2, 2010 at 00:28, Ziad <hatahet@gmail.com> wrote:

>
> If I want a static array:
>
> int[5] a = [1, 2, 3, 4, 5];
>
> I'd have to specify the size in advance (5 in this case), which means that adding extra elements later on would require that the size be update.
>
> Is there a way to let the compiler automatically determine the size based on the argument list?
>

Would a template-based solution be OK?

import std.stdio, std.traits;

CommonType!T[T.length] staticArray(T...)(T vals)
    if ((T.length > 0) && is(CommonType!T))
{
    return [vals];
}

void main()
{
    auto a = staticArray(0,1,2,3,4);
    writeln(typeof(a).stringof); // int[5u]

    auto b = staticArray(3.14);
    writeln(typeof(b).stringof); // double[1u]

    auto mixed = staticArray(0,1,2,3,4, 3.14);
    writeln(typeof(mixed).stringof);  // double[6u]
}


Philippe


August 02, 2010
Philippe Sigaud:

> Would a template-based solution be OK?
> 
> import std.stdio, std.traits;
> 
> CommonType!T[T.length] staticArray(T...)(T vals)
>     if ((T.length > 0) && is(CommonType!T))
> {
>     return [vals];
> }


That's one solution, but code like that is most useful when your arrays liters are long (because if they are little you can just count the items and avoid using staticArray), this is an example (I have used printf to avoid the metric ton of functions and templates used by writeln):


import std.c.stdio: printf;
import std.traits: CommonType;

CommonType!T[T.length] staticArray(T...)(T vals)
  if (T.length && is(CommonType!T)) {
    return [vals];
}

void main() {
    auto a = staticArray(0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120,
                         130, 140, 150, 160, 170, 180, 190, 200, 210, 220, 230,
                         240, 250, 260, 270, 280, 290, 300, 310, 320, 330, 340,
                         350, 360, 370, 380, 390, 400, 410, 420, 430, 440, 450,
                         460, 470, 480, 490, 500, 510, 520, 530, 540, 550, 560,
                         570, 580, 590, 600, 610, 620, 630, 640, 650, 660, 670,
                         680, 690, 700, 710, 720, 730, 740, 750, 760, 770, 780,
                         790, 800, 810, 820, 830, 840, 850, 860, 870, 880, 890,
                         900, 910, 920, 930, 940, 950, 960, 970, 980, 990);
    printf("%d\n", a[2]);
}


This is the asm of the staticArray:

_D5test2217__T11staticArrayTiÉÛÿ€€  €ÀÀ€ÈÈZÖFiiÉÛÿ€€  €¤¤ZG100i   comdat
L0:     push    EAX
        push    ESI
        push    EDI
        push    dword ptr 010h[ESP]
        push    dword ptr 018h[ESP]
        push    dword ptr 020h[ESP]
        push    dword ptr 028h[ESP]
        push    dword ptr 030h[ESP]
        push    dword ptr 038h[ESP]
        push    dword ptr 040h[ESP]
        push    dword ptr 048h[ESP]
        push    dword ptr 050h[ESP]
        push    dword ptr 058h[ESP]
        push    dword ptr 060h[ESP]
        push    dword ptr 068h[ESP]
        push    dword ptr 070h[ESP]
        push    dword ptr 078h[ESP]
        push    dword ptr 080h[ESP]
        push    dword ptr 088h[ESP]
        push    dword ptr 090h[ESP]
        push    dword ptr 098h[ESP]
        push    dword ptr 0A0h[ESP]
        push    dword ptr 0A8h[ESP]
        push    dword ptr 0B0h[ESP]
        push    dword ptr 0B8h[ESP]
        push    dword ptr 0C0h[ESP]
        push    dword ptr 0C8h[ESP]
        push    dword ptr 0D0h[ESP]
        push    dword ptr 0D8h[ESP]
        push    dword ptr 0E0h[ESP]
        push    dword ptr 0E8h[ESP]
        push    dword ptr 0F0h[ESP]
        push    dword ptr 0F8h[ESP]
        push    dword ptr 0100h[ESP]
        push    dword ptr 0108h[ESP]
        push    dword ptr 0110h[ESP]
        push    dword ptr 0118h[ESP]
        push    dword ptr 0120h[ESP]
        push    dword ptr 0128h[ESP]
        push    dword ptr 0130h[ESP]
        push    dword ptr 0138h[ESP]
        push    dword ptr 0140h[ESP]
        push    dword ptr 0148h[ESP]
        push    dword ptr 0150h[ESP]
        push    dword ptr 0158h[ESP]
        push    dword ptr 0160h[ESP]
        push    dword ptr 0168h[ESP]
        push    dword ptr 0170h[ESP]
        push    dword ptr 0178h[ESP]
        push    dword ptr 0180h[ESP]
        push    dword ptr 0188h[ESP]
        push    dword ptr 0190h[ESP]
        push    dword ptr 0198h[ESP]
        push    dword ptr 01A0h[ESP]
        push    dword ptr 01A8h[ESP]
        push    dword ptr 01B0h[ESP]
        push    dword ptr 01B8h[ESP]
        push    dword ptr 01C0h[ESP]
        push    dword ptr 01C8h[ESP]
        push    dword ptr 01D0h[ESP]
        push    dword ptr 01D8h[ESP]
        push    dword ptr 01E0h[ESP]
        push    dword ptr 01E8h[ESP]
        push    dword ptr 01F0h[ESP]
        push    dword ptr 01F8h[ESP]
        push    dword ptr 0200h[ESP]
        push    dword ptr 0208h[ESP]
        push    dword ptr 0210h[ESP]
        push    dword ptr 0218h[ESP]
        push    dword ptr 0220h[ESP]
        push    dword ptr 0228h[ESP]
        push    dword ptr 0230h[ESP]
        push    dword ptr 0238h[ESP]
        push    dword ptr 0240h[ESP]
        push    dword ptr 0248h[ESP]
        push    dword ptr 0250h[ESP]
        push    dword ptr 0258h[ESP]
        push    dword ptr 0260h[ESP]
        push    dword ptr 0268h[ESP]
        push    dword ptr 0270h[ESP]
        push    dword ptr 0278h[ESP]
        push    dword ptr 0280h[ESP]
        push    dword ptr 0288h[ESP]
        mov ECX,offset FLAT:_D14TypeInfo_G100i6__initZ
        push    dword ptr 0290h[ESP]
        push    dword ptr 0298h[ESP]
        push    dword ptr 02A0h[ESP]
        push    dword ptr 02A8h[ESP]
        push    dword ptr 02B0h[ESP]
        push    dword ptr 02B8h[ESP]
        push    dword ptr 02C0h[ESP]
        push    dword ptr 02C8h[ESP]
        push    dword ptr 02D0h[ESP]
        push    dword ptr 02D8h[ESP]
        push    dword ptr 02E0h[ESP]
        push    dword ptr 02E8h[ESP]
        push    dword ptr 02F0h[ESP]
        push    dword ptr 02F8h[ESP]
        push    dword ptr 0300h[ESP]
        push    dword ptr 0308h[ESP]
        push    dword ptr 0310h[ESP]
        push    dword ptr 0318h[ESP]
        push    dword ptr 0320h[ESP]
        push    dword ptr 0328h[ESP]
        push    064h
        push    ECX
        call    near ptr __d_arrayliteralT
        mov ESI,EAX
        mov EDI,01A0h[ESP]
        mov ECX,064h
        rep
        movsd
        add ESP,0198h
        mov EAX,8[ESP]
        pop EDI
        pop ESI
        pop ECX
        ret 0190h



And you essentially have one similar function each time you use staticArray. This is why in my answer I have said I don't know any good solution to this problem and this is why I have proposed the enhancement [$] syntax.

In my code I count the items in some way (with Python, or I assign the literal to a dynamic array, print its length and then modify the code replacing the dynamic array with the printed number).

Bye,
bearophile
August 02, 2010
Hello bearophile,

> Philippe Sigaud:
> 
>> Would a template-based solution be OK?
>> 
>> import std.stdio, std.traits;
>> 
>> CommonType!T[T.length] staticArray(T...)(T vals)
>> if ((T.length > 0) && is(CommonType!T))
>> {
>> return [vals];
>> }
> That's one solution, but code like that is most useful when your
> arrays liters are long (because if they are little you can just count
> the items and avoid using staticArray), this is an example (I have
> used printf to avoid the metric ton of functions and templates used by
> writeln):
> 
> import std.c.stdio: printf;
> import std.traits: CommonType;
> CommonType!T[T.length] staticArray(T...)(T vals)
> if (T.length && is(CommonType!T)) {
> return [vals];
> }
> void main() {
> auto a = staticArray(0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100,
...
> 990);
> printf("%d\n", a[2]);
> }
> This is the asm of the staticArray:
> 
> _D5test2217__T11staticArrayTiÉÛÿ€€  €ÀÀ€ÈÈZÖFiiÉÛÿ€€  €¤¤ZG100i
> comdat
> L0:     push    EAX
> push    ESI
> push    EDI
> push    dword ptr 010h[ESP]
...
> push    dword ptr 0328h[ESP]
> push    064h
> push    ECX
> call    near ptr __d_arrayliteralT
> mov ESI,EAX
> mov EDI,01A0h[ESP]
> mov ECX,064h
> rep
> movsd
> add ESP,0198h
> mov EAX,8[ESP]
> pop EDI
> pop ESI
> pop ECX
> ret 0190h

Is that with or without inline? If that doesn't inline away to a memcopy then it looks like an optimization opportunity to me.

> And you essentially have one similar function each time you use
> staticArray. This is why in my answer I have said I don't know any
> good solution to this problem and this is why I have proposed the
> enhancement [$] syntax.
> 
> In my code I count the items in some way (with Python, or I assign the
> literal to a dynamic array, print its length and then modify the code
> replacing the dynamic array with the printed number).
> 
> Bye,
> bearophile
-- 
... <IXOYE><



August 02, 2010
Thanks for your feedback Philippe and bearophile :)

Cheers,
-- Ziad
August 02, 2010
BCS:
> Is that with or without inline? If that doesn't inline away to a memcopy then it looks like an optimization opportunity to me.

That's with inline, but if you don't use inline the result is the same, because that is the asm of a function, not of its caller (the main), so DMD keeps the not inlined function around anyway even when it inlines it. So in your binary you find all the staticArray() you have instantiated/used.

This is the main (compiled with -O -release -inline, dmd 2.047):

__Dmain comdat
L0:     sub ESP,0194h
        push    0190h
        push    03DEh
        push    03D4h
        push    03CAh
        push    03C0h
        push    03B6h
        push    03ACh
        push    03A2h
        push    0398h
        push    038Eh
        push    0384h
        push    037Ah
        push    0370h
        push    0366h
        push    035Ch
        push    0352h
        push    0348h
        push    033Eh
        push    0334h
        push    032Ah
        push    0320h
        push    0316h
        push    030Ch
        push    0302h
        push    02F8h
        push    02EEh
        push    02E4h
        push    02DAh
        push    02D0h
        push    02C6h
        push    02BCh
        push    02B2h
        push    02A8h
        push    029Eh
        push    0294h
        push    028Ah
        push    0280h
        push    0276h
        push    026Ch
        push    0262h
        push    0258h
        push    024Eh
        push    0244h
        push    023Ah
        push    0230h
        push    0226h
        push    021Ch
        push    0212h
        push    0208h
        push    01FEh
        push    01F4h
        push    01EAh
        push    01E0h
        push    01D6h
        push    01CCh
        push    01C2h
        push    01B8h
        push    01AEh
        push    01A4h
        push    019Ah
        push    0190h
        push    0186h
        push    017Ch
        push    0172h
        push    0168h
        push    015Eh
        push    0154h
        push    014Ah
        push    0140h
        push    0136h
        push    012Ch
        push    0122h
        push    0118h
        push    010Eh
        push    0104h
        push    0FAh
        push    0F0h
        push    0E6h
        push    0DCh
        push    0D2h
        push    0C8h
        push    0BEh
        mov EAX,offset FLAT:_D14TypeInfo_G100i6__initZ
        push    0B4h
        push    0AAh
        push    0A0h
        push    096h
        push    08Ch
        push    082h
        push    078h
        push    06Eh
        push    064h
        push    05Ah
        push    050h
        push    046h
        push    03Ch
        push    032h
        push    028h
        push    01Eh
        push    014h
        push    0Ah
        push    0
        push    064h
        push    EAX
        call    near ptr __d_arrayliteralT
        add ESP,0198h
        push    EAX
        lea ECX,0Ch[ESP]
        push    ECX
        call    near ptr _memcpy
        mov EDX,offset FLAT:_DATA
        push    dword ptr 018h[ESP]
        push    EDX
        call    near ptr _printf
        add ESP,014h
        add ESP,0194h
        xor EAX,EAX
        ret

Bye,
bearophile
August 02, 2010
On Mon, Aug 2, 2010 at 14:15, bearophile <bearophileHUGS@lycos.com> wrote:

>
> That's one solution, but code like that is most useful when your arrays liters are long (because if they are little you can just count the items and avoid using staticArray)


Yes, but as Ziad said:

"If I want a static array (...) I'd have to specify the size in advance (5
in this case), which
means that adding extra elements later on would require that the size be
update."

So small-size arrays _are_ a possibility.


Ziad:
> Thanks for your feedback Philippe and bearophile :)

If you understand the code, very well. If not, say so. I know I'd have been unable to understand it two years ago.

Philippe