Inability to dup/~ for const arrays of class objects

Steven Schveighoffer schveiguy at yahoo.com
Mon Jun 3 18:56:01 PDT 2013


On Mon, 03 Jun 2013 20:06:14 -0400, Peter Williams
<pwil3058 at bigpond.net.au> wrote:

> On 04/06/13 00:57, Steven Schveighoffer wrote:
>> On Fri, 31 May 2013 21:04:47 -0400, Peter Williams
>> <pwil3058 at bigpond.net.au> wrote:
>>> I do like the idea that "~=" is generally cheap as it potentially
>>> makes building lists easy (is there any need for the singly linked
>>> list in D?) and I may modify some of my code.  I've been allocating
>>> arrays using "new array[size]" where I know that "size" will be the
>>> max needed but that it may be too much (i.e. throwing away duplicates)
>>> inserting into the array and then adjusting "length" to whatever I
>>> used.  In the case, where it's highly likely that the whole array will
>>> fit in a page I might as well allocate an empty array and use "+=".
>>> NB there's only one copy of the array.
>>
>> You can .reserve the space that you need ahead of time.  Then appending
>> will always deterministically go into the reserved block, and won't
>> reallocate.  This should be relatively quick.  It's not as quick as
>> pre-allocating the entire array and then writing the data directly --
>> you still need calls into the runtime for appending.
>
> That's great news.  When I tried to implement what I described above it  
> didn't go as well as planned (because I'd misunderstood how much gets  
> allocated) and I was thinking that what's needed is a way to tell the  
> compiler how much to allocate at the start.  And now you tell me there  
> is a way.
>
> This is one of the things I like about learning D.  Almost every time I  
> say to myself "I wish there was an easier way to do this" it turns out  
> that there is :-).  Some of them are easier to discover than others,  
> though.

I added the capacity, reserve, and assumeSafeAppend array methods when I  
updated the append code, it's been there for a while now, since the  
beginning of 2010.  It was cited in the article mentioned earlier too.   
You might want to re-read that part (it's near the end).

>> The appending feature of D arrays/slices is intended to be "good enough"
>> for most usages, not horrendously slow, but also not super-optimized for
>> specific purposes.
>>
>> And yes, we still need linked lists, arrays are good for appending, but
>> not inserting :)
>
> I use a = a[0..i] ~ v ~ a[i..$] for insertion into a sorted array as I'm  
> willing to pay the cost of allocation for the convenience of array  
> notation.  One advantage is that finding i is O(log(a.length)) instead  
> of O(a.length()).  I also reasoned that the compiler can use memcopy()  
> (or whatever its name is) to do the reallocation and therefore it should  
> be fairly quick.

ugh.  Sorry, the performance miser in me must object :)

There are better ways to do this, using range operations.  I'm pretty sure  
you could do it with std.algorithm.copy.

> I also do a = a[0..i] ~ a[i + 1..$] to remove an item but am starting to  
> suspect this isn't as good an idea as for the insert.  Maybe something  
> like:
>
> auto tmp = a[i + 1..$];
> a.length = i;
> a ~= tmp;
>
> would be more efficient?

No, because that will also reallocate, just like your original.  This one  
is REALLY easy to get right, because it can be done in place (assuming a  
is not const/immutable).

You can even do:

memmove(&a[i], &a[i + 1], a.length - i - 1);
a.length--;

For some reason, D doesn't support overlapping moves, otherwise, this  
would work:

a[i..$-1] = a[i + 1..$];
a.length--;

I think std.algorithm.remove can do the same thing in one line.

-Steve


More information about the Digitalmars-d mailing list