www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Ways to initialize static arrays

reply Stanislav Blinov <blinov loniir.ru> writes:
  Hello,

I was wondering if anyone has suggestions on performing arbitrary 
initialization of static arrays, size of which is arbitrary at compile time.

Consider this:

template StaticArray(T,int N,T v) if (N > 0)
{
     static if (N == 1)
     {
         enum T[N] StaticArray = cast(T[N])[v];
     }
     else
     {
         enum T[N] StaticArray = cast(T[N])([v] ~ StaticArray!(T,N-1,v));
     }
}

T[] generateArray(T,int N,string G=q{a[i] = 0})()
{
     T[] a;
     foreach(i;0..N)
     {
         mixin(G ~ ";");
     }
     return a.dup;
}

template GenStaticArray(T,int N,string G=q{a[i] = 0})
{
     enum T[N] GenStaticArray = cast(T[N])generateArray!(T,N,G)();
}

struct Vector(int N,T)
{
     T data_[N];

     static immutable Vector Identity = { StaticArray!(T,N,1) };
     static immutable Vector Zero = { StaticArray!(T,N,0) };
     static immutable Vector UnitX = { GenStaticArray!(T,N,q{a[i] = i ? 
0 : 1}) };
     static immutable Vector UnitY = { GenStaticArray!(T,N,q{a[i] = i != 
1 ? 0 : 1}) };
     static immutable Vector UnitZ = { GenStaticArray!(T,N,q{a[i] = i != 
2 ? 0 : 1}) };
}

I don't like those casts in templates. In fact, I'm not even sure if 
such code is legal. Maybe there is some better way of doing this?

-- 

	
Aug 23 2010
next sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Stanislav Blinov:

 I was wondering if anyone has suggestions on performing arbitrary 
 initialization of static arrays, size of which is arbitrary at compile time.

Please explain your purposes a bit better. Bye, bearophile
Aug 23 2010
next sibling parent Stanislav Blinov <blinov loniir.ru> writes:
  Sorry, I pressed the wrong button so the message was sent to your 
email. Reciting:

  26.08.2010 1:53, Philippe Sigaud wrote:
     I came up with the templates in my initial post. They seem to
     work, but I doubt those are legal solutions.

     .


 If they work, then they are legal :)

 If I understand correctly what you want, you can achieve it with 
 compile-time-evaluable functions:

 Does that work for you?

When I was on the way to my initial solutions I was under strong impression that T[N] func() won't work. Now I see that was because I didn't bother to fully understand how arrays are returned from functions. I got it now, so thanks a lot again!
Aug 26 2010
prev sibling parent reply Stanislav Blinov <stanislav.blinov gmail.com> writes:
Philippe Sigaud wrote:
 
 That beats hell out of my clumsy templates :)
 
 
 Your templates are not clumsy, it's typically the way some other PL 
 would process lists/arrays. I used to write a lot of these. But 6 months 
 ago, CTFE got seven-leagues boots and right now it's much easier on the 
 eye to use CT functions.

Thanks for friendly shoulder tap :) I think I just need to get accustomed with CTFE. I mostly work in C++, and it's templates (much inspired by Andrei's C++ publications as well as Loki, by the way) are telling on me. I constantly tend to forget there are so many constructs in D I can use at compile time without worry.
 
 
     When I was on the way to my initial solutions I was under strong
     impression that T[N] func() won't work. Now I see that was because I
     didn't bother to fully understand how arrays are returned from
     functions. I got it now, so thanks a lot again!
 
 
 There used to be a time, maybe not 18 months ago where returning static 
 arrays from functions was not possible, IIRC.. 

This may have something to do with my assumptions. I haven't tried D much since when shared was introduced (don't remember how long ago it was).
 Right now, I think you 
 can use them with no problem. Maybe someone well-versed in optimization 
 will tell us it's not a good idea, I don't know.

Well, as you've said yourself, if it works... :) PS. I'm not sure as to where to post this, but after I tried your solution I've noticed one interesting (or rather strange) thing: struct S(T,size_t N) { T[N] arr; int foo; // type doesn't seem to matter here, // taking int for clarity static immutable S C1 = { initializeWith!(T,N)(0) 5 }; // Note there is no comma after first initializer ^ } This actually compiles and works, though I have an impression that syntax error is in order. Putting in second array and attempting similar initialization without commas leads to one. I've only tried it with Windows 2.048, though I think the front end would eat this on Linux too. Is this valid, already known or I should report this?
Aug 26 2010
parent reply Stanislav Blinov <stanislav.blinov gmail.com> writes:
Philippe Sigaud wrote:
     I have an impression that
     syntax error is in order. Putting in second array and attempting
     similar initialization without commas leads to one. I've only tried
     it with Windows 2.048, though I think the front end would eat this
     on Linux too. Is this valid, already known or I should report this?
 
 
 Dunno, I never use the = { ... } syntax to create structs. I always do = 
 S(...);
 I even thought the literal syntax was being deprecated. Maybe I'm mistaken.
 
 In any case, please report this.
 

Ok, I'll do that once I narrow it down to anything meaningful (I've found that behavior on 2.047 Linux is somewhat different).
Aug 26 2010
parent Stanislav Blinov <stanislav.blinov gmail.com> writes:
Done:

http://d.puremagic.com/issues/show_bug.cgi?id=4745
Aug 28 2010
prev sibling next sibling parent Stanislav Blinov <blinov loniir.ru> writes:
  23.08.2010 16:31, bearophile wrote:
 Stanislav Blinov:

 I was wondering if anyone has suggestions on performing arbitrary
 initialization of static arrays, size of which is arbitrary at compile time.


elements. N is set at compile time via template parameter. S uses static array as storage (T[N]). I need a set of constants of type S which I'd like to be evaluatable at compile time. I can create these constants with the following constructs: static immutable S C1 = { /* initialization of struct fields here */ }; static immutable S C2 = { /* initialization of struct fields here */ }; Hence, I need some way to initialize a field which is T[N]. Later, I could use those constants like this: class Foo { S s1_ = S.C1; S s2_ = S.C2; } I can write a set of initializers for some values of N, but I'd like them to be generic so that I could apply them for arbitrary value of N. E.g. one can do things like T[3] a = [ 1, 2, 3 ], but I'd like to be able to do T[N] = SomeInitializerForArrayOfNElements; What I'm trying to achieve is: 1. Initialize T[N] elements to a specific value. 2. Initialize every element of T[N] to some value deduced at compile time using it's index. I came up with the templates in my initial post. They seem to work, but I doubt those are legal solutions.
Aug 23 2010
prev sibling next sibling parent Philippe Sigaud <philippe.sigaud gmail.com> writes:
--001485f5afa8d4bd35048eace706
Content-Type: text/plain; charset=ISO-8859-1

2010/8/23 Stanislav Blinov <blinov loniir.ru>

 I have a struct template (let's call it S) that wraps an array of N
 elements. N is set at compile time via template parameter. S uses static
 array as storage (T[N]). I need a set of constants of type S which I'd like
 to be evaluatable at compile time. I can create these constants with the
 following constructs:

 static immutable S C1 = { /* initialization of struct fields here */ };
 static immutable S C2 = { /* initialization of struct fields here */ };

 Hence, I need some way to initialize a field which is T[N].

 Later, I could use those constants like this:

 class Foo
 {
    S s1_ = S.C1;
    S s2_ = S.C2;
 }

 I can write a set of initializers for some values of N, but I'd like them
 to be generic so that I could apply them for arbitrary value of N.
 E.g. one can do things like T[3] a = [ 1, 2, 3 ], but I'd like to be able
 to do T[N] = SomeInitializerForArrayOfNElements;

 What I'm trying to achieve is:

 1. Initialize T[N] elements to a specific value.
 2. Initialize every element of T[N] to some value deduced at compile time
 using it's index.

 I came up with the templates in my initial post. They seem to work, but I
 doubt those are legal solutions.

If they work, then they are legal :) If I understand correctly what you want, you can achieve it with compile-time-evaluable functions: module main; import std.stdio; /** return a T[N] with all elements equal to t. */ T[N] initializeWith(T, size_t N)(T t) if (N>0) { T[N] result; foreach(i, _; result) { result[i] = t; } return result; } /** Returns a T[N] with all elements equal to foo(index) */ T[N] initializeWith(alias fun, T, size_t N)() if (N>0) { T[N] result; foreach(i, _; result) { result[i] = fun(i); } return result; } int foo(int i) { return i*i;} struct S { static immutable int[10] arr = initializeWith!(foo, int, 10); } void main() { auto a = initializeWith!(int,10)(8); writeln(a); a = initializeWith!(foo,int,10); writeln(a); S s; writeln(s.arr); } Does that work for you? Philippe --001485f5afa8d4bd35048eace706 Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable <div class=3D"gmail_quote">2010/8/23 Stanislav Blinov <span dir=3D"ltr">&lt= ;<a href=3D"mailto:blinov loniir.ru">blinov loniir.ru</a>&gt;</span><br><bl= ockquote class=3D"gmail_quote" style=3D"margin: 0pt 0pt 0pt 0.8ex; border-l= eft: 1px solid rgb(204, 204, 204); padding-left: 1ex;"> <div><div></div>I have a struct template (let&#39;s call it S) that wraps a= n array of N elements. N is set at compile time via template parameter. S u= ses static array as storage (T[N]). I need a set of constants of type S whi= ch I&#39;d like to be evaluatable at compile time. I can create these const= ants with the following constructs:<br> </div> <br> static immutable S C1 =3D { /* initialization of struct fields here */ };<b= r> static immutable S C2 =3D { /* initialization of struct fields here */ };<b= r> <br> Hence, I need some way to initialize a field which is T[N].<br> <br> Later, I could use those constants like this:<br> <br> class Foo<br> {<br> =A0 =A0S s1_ =3D S.C1;<br> =A0 =A0S s2_ =3D S.C2;<br> }<br> <br> I can write a set of initializers for some values of N, but I&#39;d like th= em to be generic so that I could apply them for arbitrary value of N.<br> E.g. one can do things like T[3] a =3D [ 1, 2, 3 ], but I&#39;d like to be = able to do T[N] =3D SomeInitializerForArrayOfNElements;<br> <br> What I&#39;m trying to achieve is:<br> <br> 1. Initialize T[N] elements to a specific value.<br> 2. Initialize every element of T[N] to some value deduced at compile time u= sing it&#39;s index.<br> <br> I came up with the templates in my initial post. They seem to work, but I d= oubt those are legal solutions.<br> </blockquote></div><br>If they work, then they are legal :)<br><br>If I und= erstand correctly what you want, you can achieve it with compile-time-evalu= able functions:<br><br>module main;<br>import std.stdio;<br><br>/**<br> return a T[N] with all elements equal to t.<br>*/<br>T[N] initializeWith(T,= size_t N)(T t) if (N&gt;0)<br>{<br>=A0=A0=A0 T[N] result;<br>=A0=A0=A0 for= each(i, _; result)<br>=A0=A0=A0 {<br>=A0=A0=A0=A0=A0=A0=A0 result[i] =3D t;= <br>=A0=A0=A0 }<br>=A0=A0=A0 return result;<br> }<br><br>/**<br>Returns a T[N] with all elements equal to foo(index)<br>*/<= br>T[N] initializeWith(alias fun, T, size_t N)() if (N&gt;0)<br>{<br>=A0=A0= =A0 T[N] result;<br>=A0=A0=A0 foreach(i, _; result)<br>=A0=A0=A0 {<br>=A0= =A0=A0=A0=A0=A0=A0 result[i] =3D fun(i);<br> =A0=A0=A0 }<br>=A0=A0=A0 return result;<br>}<br><br>int foo(int i) { return= i*i;}<br><br>struct S<br>{<br>=A0=A0=A0 static immutable int[10] arr =3D i= nitializeWith!(foo, int, 10);<br>}<br><br>void main()<br>{<br>=A0=A0=A0 aut= o a =3D initializeWith!(int,10)(8);<br> <br>=A0=A0=A0 writeln(a);<br>=A0=A0=A0 a =3D initializeWith!(foo,int,10);<b= r>=A0=A0=A0 writeln(a);<br>=A0=A0=A0 S s;<br>=A0=A0=A0 writeln(s.arr);<br>}= <br><br>Does that work for you? <br><br>Philippe<br><br> --001485f5afa8d4bd35048eace706--
Aug 25 2010
prev sibling next sibling parent Philippe Sigaud <philippe.sigaud gmail.com> writes:
--0015175cd138e2dce7048ec06e5d
Content-Type: text/plain; charset=ISO-8859-1

On Thu, Aug 26, 2010 at 14:11, Stanislav Blinov <blinov loniir.ru> wrote:

  Sorry, I pressed the wrong button so the message was sent to your email.
 Reciting:


 Does that work for you?
  Yes! Beautiful, thanks! That beats hell out of my clumsy templates :)


Your templates are not clumsy, it's typically the way some other PL would process lists/arrays. I used to write a lot of these. But 6 months ago, CTFE got seven-leagues boots and right now it's much easier on the eye to use CT functions.
 When I was on the way to my initial solutions I was under strong impression
 that T[N] func() won't work. Now I see that was because I didn't bother to
 fully understand how arrays are returned from functions. I got it now, so
 thanks a lot again!

There used to be a time, maybe not 18 months ago where returning static arrays from functions was not possible, IIRC. Right now, I think you can use them with no problem. Maybe someone well-versed in optimization will tell us it's not a good idea, I don't know. Philippe --0015175cd138e2dce7048ec06e5d Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable <div class=3D"gmail_quote">On Thu, Aug 26, 2010 at 14:11, Stanislav Blinov = <span dir=3D"ltr">&lt;<a href=3D"mailto:blinov loniir.ru">blinov loniir.ru<= /a>&gt;</span> wrote:<br><blockquote class=3D"gmail_quote" style=3D"margin:= 0pt 0pt 0pt 0.8ex; border-left: 1px solid rgb(204, 204, 204); padding-left= : 1ex;"> =A0Sorry, I pressed the wrong button so the message was sent to your email.= Reciting:<div class=3D"im"><br> <br></div><blockquote class=3D"gmail_quote" style=3D"margin: 0pt 0pt 0pt 0.= 8ex; border-left: 1px solid rgb(204, 204, 204); padding-left: 1ex;"><div cl= ass=3D"im"> Does that work for you?<br> <br> </div></blockquote><div><div></div><div class=3D"h5"> Yes! Beautiful, thanks! That beats hell out of my clumsy templates :)<br></= div></div></blockquote><div><br>Your templates are not clumsy, it&#39;s typ= ically the way some other PL would process lists/arrays. I used to write a = lot of these. But 6 months ago, CTFE got seven-leagues boots and right now = it&#39;s much easier on the eye to use CT functions.<br> =A0</div><blockquote class=3D"gmail_quote" style=3D"margin: 0pt 0pt 0pt 0.8= ex; border-left: 1px solid rgb(204, 204, 204); padding-left: 1ex;"><div><di= v class=3D"h5"> <br> When I was on the way to my initial solutions I was under strong impression= that T[N] func() won&#39;t work. Now I see that was because I didn&#39;t b= other to fully understand how arrays are returned from functions. I got it = now, so thanks a lot again!<br> </div></div></blockquote><div><br>There used to be a time, maybe not 18 mon= ths ago where returning static arrays from functions was not possible, IIRC= . Right now, I think you can use them with no problem. Maybe someone well-v= ersed in optimization will tell us it&#39;s not a good idea, I don&#39;t kn= ow.<br> <br><br>Philippe<br>=A0<br></div></div><br> --0015175cd138e2dce7048ec06e5d--
Aug 26 2010
prev sibling parent Philippe Sigaud <philippe.sigaud gmail.com> writes:
--001636c5ab91252ff8048ec1759a
Content-Type: text/plain; charset=ISO-8859-1

On Thu, Aug 26, 2010 at 23:49, Stanislav Blinov
<stanislav.blinov gmail.com>wrote:

 struct S(T,size_t N)
 {
        T[N] arr;
        int foo;        // type doesn't seem to matter here,
                        // taking int for clarity

        static immutable S C1   =   { initializeWith!(T,N)(0) 5 };
        // Note there is no comma after first initializer    ^
 }

 This actually compiles and works, though I have an impression that syntax
 error is in order. Putting in second array and attempting similar
 initialization without commas leads to one. I've only tried it with Windows
 2.048, though I think the front end would eat this on Linux too. Is this
 valid, already known or I should report this?

Dunno, I never use the = { ... } syntax to create structs. I always do = S(...); I even thought the literal syntax was being deprecated. Maybe I'm mistaken. In any case, please report this. --001636c5ab91252ff8048ec1759a Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable <div class=3D"gmail_quote">On Thu, Aug 26, 2010 at 23:49, Stanislav Blinov = <span dir=3D"ltr">&lt;<a href=3D"mailto:stanislav.blinov gmail.com">stanisl= av.blinov gmail.com</a>&gt;</span> wrote:<br><blockquote class=3D"gmail_quo= te" style=3D"margin: 0pt 0pt 0pt 0.8ex; border-left: 1px solid rgb(204, 204= , 204); padding-left: 1ex;"> struct S(T,size_t N)<br> {<br> =A0 =A0 =A0 =A0T[N] arr;<br> =A0 =A0 =A0 =A0int foo; =A0 =A0 =A0 =A0// type doesn&#39;t seem to matter = here,<br> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0// taking int for clarity<b= r> <br> =A0 =A0 =A0 =A0static immutable S C1 =A0 =3D =A0 { initializeWith!(T,N)(0)= 5 };<br> =A0 =A0 =A0 =A0// Note there is no comma after first initializer =A0 =A0^<= br> }<br> <br> This actually compiles and works, though I have an impression that syntax e= rror is in order. Putting in second array and attempting similar initializa= tion without commas leads to one. I&#39;ve only tried it with Windows 2.048= , though I think the front end would eat this on Linux too. Is this valid, = already known or I should report this?<br> </blockquote></div><br>Dunno, I never use the =3D { ... } syntax to create = structs. I always do =3D S(...);<br>I even thought the literal syntax was b= eing deprecated. Maybe I&#39;m mistaken.<br><br>In any case, please report = this.<br> <br><br> --001636c5ab91252ff8048ec1759a--
Aug 26 2010