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
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:
  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.
Please explain your purposes a bit better.
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.
Aug 23 2010
prev sibling next sibling parent Philippe Sigaud <philippe.sigaud gmail.com> writes:
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
Aug 25 2010
prev sibling 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 :)
How it would be better for us all if we could always say that :)
 If I understand correctly what you want, you can achieve it with 
 compile-time-evaluable functions:

 Does that work for you?
Yes! Beautiful, thanks! That beats hell out of my clumsy templates :) 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 Philippe Sigaud <philippe.sigaud gmail.com> writes:
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
Aug 26 2010
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 Philippe Sigaud <philippe.sigaud gmail.com> writes:
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.
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