D dynamic array initialization, step and index operation

Sorry, this has become a 3x question regarding arrays

I think the (dynamic) arrays are really efficient in D, but the following bothered me for a while:

In C ++, I could easily allocate an array with the assigned values, but in D I did not find a way to do this. This is undoubtedly not a problem:

int[] a = new int[N]; a[] = a0; 

But it looks inefficient, since the first line will be initialized with 0 and like 2 with a0 . Could something like this do in D?

 int[] a = new int(a0)[N]; // illegal 

Another efficiency value that I have when using a step in std.range:

 import std.stdio; import std.range; struct S { int x; this(this) { writeln("copy ", x); } } void f(S[] s) { } int main() { S[] s = new S[10]; foreach (i, ref v; s) { vx = i; } f(stride(s, 3)); // error return 0; } 

Of course, I naively thought I could just use the step to create a new array without copying its elements? Is there no way in D to do this?


So, I went and modeled as if the array was like a step back, and implemented f as:

 f(s, 3); void f(S[] s, uint stride) { ref S get(uint i) { assert (i * stride < s.length); return s[i * stride]; } for (uint x ... ) { get(x) = ...; } } 

Would there be a way to write get (x) instead using the get[x] index operator? That way I could statically mix / include the get step function and keep the rest of the function similar. I would be interested in the approach, since the local structure was not allowed to access the variables of the function domain (why not?).

+4
source share
2 answers

But it looks inefficient, since the first line will be initialized with 0 and is similar to 2 with a0. Could something like this do in D?

Use std.array.uninitializedArray

 S[] s = uninitializedArray!(S[])(N); s[] = a0; 

Of course, I naively thought I could just use the step to create a new array without copying its elements? Is there no way in D to do this?

Your f function has S[] as an argument, which is different from what stride returns. Method D, to solve this problem, is to make your function f acceptable for any range by making it a template:

 void f(Range)(Range s) { foreach (item; s) // use item } S[] s = new S[10]; f(s); // works f(stride(s, 3)); // works too 

Alternatively, you can copy the array:

 f(array(stride(s, 3))); 

But you probably want to avoid copying the entire array if it is large.


Would there be a way to write get (x) instead using the index get [x] statement? That way, I could statically mix / enable the geting get function and keep the rest of the function similar. I would be interested in the approach, since the local structure was not allowed to access the variables of the function domain (why not?).

You can overload the index operator in your own structure.

 struct StrideArray { this(S[] s, uint stride) { m_array = s; m_stride = stride; } S opIndex(size_t i) { return s[i * m_stride]; } void opIndexAssign(size_t i, S value) { s[i * m_stride] = value; } private S[] m_array; private uint m_stride; } 

This (view) how the actual stride function works. I recommend reading on Ranges .

+7
source

you can duplicate (create a copy) an array with .dup (this will also work with slices) or you can set elements with an array initializer

 int[] a=a0.dup; int[] b=[e1,e2,e3]; 

you can do f generic (stride () returns a structure that you can iterate over, not an array)

 void f(Z)(Z s)if(isInputRange!Z){ foreach(elem;s){ //... } } 

remember that arrays are essentially structured with a pointer field to some memory block and a size field

+1
source

Source: https://habr.com/ru/post/904822/


All Articles