November 24, 2015
On 11/23/15 7:29 PM, Ali Çehreli wrote:
> On 11/23/2015 04:03 PM, Steven Schveighoffer wrote:
>  > On 11/23/15 4:29 PM, Jon D wrote:
>
>  >> In the example I gave, what I was really wondering was if there is a
>  >> difference between allocating with 'new' or with 'reserve', or with
>  >> 'length', for that matter. That is, is there a material difference
>  >> between:
>  >>
>  >>      auto x = new int[](n);
>  >>      int[] y; y.length = n;
>  >
>  > There is no difference at all, other than the function that is called
>  > (the former will call an allocation function, the latter will call a
>  > length setting function, which then will determine if more data is
>  > needed, and finding it is, call the allocation function).
>
> Although Jon's example above does not compare reserve, I have to ask:
> How about non-trivial types? Both cases above would set all elements to
> ..init, right? So, I think reserve would be faster if copy() knew how to
> take advantage of capacity. It could emplace elements instead of
> copying, no?

I think the cost of looking up the array metadata is more than the initialization of elements to .init. However, using an Appender would likely fix all these problems.

You could also use https://dlang.org/phobos/std_array.html#uninitializedArray to create the array before copying. There are quite a few options, actually :)

A delegate is also surprisingly considered an output range! Because why not? So you can do this too as a crude substitute for appender (or for testing performance):

import std.range; // for iota
import std.algorithm;

void main()
{
   int[] arr;
   arr.reserve(100);

   iota(100).copy((int a) { arr ~= a;});
}

-Steve
November 24, 2015
On Tuesday, 24 November 2015 at 01:00:40 UTC, Steven Schveighoffer wrote:
> On 11/23/15 7:29 PM, Ali Çehreli wrote:
>> On 11/23/2015 04:03 PM, Steven Schveighoffer wrote:
>>  > On 11/23/15 4:29 PM, Jon D wrote:
>>
>>  >> In the example I gave, what I was really wondering was if there is a
>>  >> difference between allocating with 'new' or with 'reserve', or with
>>  >> 'length', for that matter. That is, is there a material difference
>>  >> between:
>>  >>
>>  >>      auto x = new int[](n);
>>  >>      int[] y; y.length = n;
>>  >
>>  > There is no difference at all, other than the function that is called
>>  > (the former will call an allocation function, the latter will call a
>>  > length setting function, which then will determine if more data is
>>  > needed, and finding it is, call the allocation function).
>>
>> Although Jon's example above does not compare reserve, I have to ask:
>> How about non-trivial types? Both cases above would set all elements to
>> ..init, right? So, I think reserve would be faster if copy() knew how to
>> take advantage of capacity. It could emplace elements instead of
>> copying, no?
>
> I think the cost of looking up the array metadata is more than the initialization of elements to .init. However, using an Appender would likely fix all these problems.
>
> You could also use https://dlang.org/phobos/std_array.html#uninitializedArray to create the array before copying. There are quite a few options, actually :)
>
> A delegate is also surprisingly considered an output range! Because why not? So you can do this too as a crude substitute for appender (or for testing performance):
>
> import std.range; // for iota
> import std.algorithm;
>
> void main()
> {
>    int[] arr;
>    arr.reserve(100);
>
>    iota(100).copy((int a) { arr ~= a;});
> }
>
> -Steve

Thanks. I was also wondering if that initial allocation could be avoided. Code I was writing involved repeatedly using a buffer in a loop. I was trying out taskPool.amap, which needs a random access range. This meant copying from the input range being read. Something like:

    auto input = anInfiniteRange();
    auto bufsize = workPerThread * taskPool.size();
    auto workbuf = new int[](bufsize);
    auto results = new int[](bufsize);
    while (true) {
        input.take(bufsize).copy(workbuf);
        input.popFront(bufsize);
        taskPool.amap!expensiveCalc(workbuf, workPerThread, results);
        results.doSomething();
    }

I'm just writing a toy example, but it is where these questions came from. For this example, the next step would be to allow the buffer size to change while iterating.

--Jon
1 2
Next ›   Last »