Sorry, this became a 3-fold question regarding arrays
I think (dynamic) arrays are truly powerful in D, but the following has been bothering me for a while:
In C++ I could easily allocate an array with designated values, but in D I haven't found a way to do so. Surely the following is no problem:
int[] a = new int[N];
a[] = a0;
But it looks inefficient, since line one will initialize with 0
, and like 2 with a0
. Could something similar to the following be done in D?
int[] a = new int(a0)[N]; // illegal
Another efficiency matter I have when using stride 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)
{
v.x = i;
}
f(stride(s, 3)); // error
return 0;
}
Surely I was naive thinking I could simply use stride to create a new array without copying it's elements? There is no way to do so in D, right?
So I went and simulated as if the array was as stride would return, 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 instead write get(x) using the index operator get[x]
? This way I could statically mixin / include the striding get
function and keep the rest of the function similar. I'd be interested in the approach taken, since a local struct is not allowed to access function scope variables (why not?).
But it looks inefficient, since line one will initialize with 0, and like 2 with a0. Could something similar to the following be done in D?
Use std.array.uninitializedArray
S[] s = uninitializedArray!(S[])(N);
s[] = a0;
Surely I was naive thinking I could simply use stride to create a new array without copying it's elements? There is no way to do so in D, right?
Your function f
has an S[]
as an argument, which is different from what stride
returns. The D way to solve this is to make your f
function accept 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 instead write get(x) using the index operator get[x]? This way I could statically mixin / include the striding get function and keep the rest of the function similar. I'd be interested in the approach taken, since a local struct is not allowed to access function scope variables (why not?).
You can overload the indexing operator in your own struct.
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 is (kind of) the way the actual stride
function works. I'd recommend reading up on Ranges.
you can duplicate (create a copy of) an array with .dup (this will also work with slices) or you can set the elements with the array initializer
int[] a=a0.dup;
int[] b=[e1,e2,e3];
you can make the f generic (stride() returns a struct that you can iterate over, not an array)
void f(Z)(Z s)if(isInputRange!Z){
foreach(elem;s){
//...
}
}
remember that arrays are essentially structs with a pointer field to some memory block and a size field
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With