Avoid deallocate empty arrays?
Steven Schveighoffer
schveiguy at gmail.com
Fri Dec 18 12:37:58 UTC 2020
On 12/17/20 1:10 PM, IGotD- wrote:
> On Thursday, 17 December 2020 at 17:46:59 UTC, Steven Schveighoffer wrote:
>>
>> This isn’t correct. Can you post the code that led you to believe this?
>>
>> -Steve
>
> Sure.
>
>
> import std.algorithm;
> import std.typecons;
> import std.stdio;
>
>
> struct Buffer
> {
> this(size_t size)
> {
> m_buffer.reserve = size;
> }
>
>
> void add(const void[] arr)
> {
> m_buffer ~= cast(ubyte[])arr;
> }
>
>
> string getSome()
> {
> if(m_buffer.length > 0)
> {
> return cast(string)m_buffer[0..$];
> }
> else
> {
> return "";
> }
> }
>
> void remove(size_t size)
> {
> m_buffer = m_buffer.remove(tuple(0, size));
Here is where your issue is. It looks like you are removing the first
size elements of the array. Which moves all the rest to the front.
However, the array runtime still thinks you have the original number of
elements in the buffer.
You need to add:
m_buffer.assumeSafeAppend;
This tells the runtime "I'm done with all the elements that are beyond
this length."
And then it will work as you expect, no reallocation.
> }
>
> ubyte[] m_buffer;
> }
>
> void main()
> {
> Buffer b = Buffer(16);
>
> b.add("aa");
>
> writeln("b.m_buffer.length ", b.m_buffer.length, ",
> b.m_buffer.capacity ", b.m_buffer.capacity);
>
> string s = b.getSome();
>
> assert(s == "aa");
>
> b.remove(s.length);
>
> writeln("b.m_buffer.length ", b.m_buffer.length, ",
> b.m_buffer.capacity ", b.m_buffer.capacity);
> }
>
> This will print
>
> b.m_buffer.length 2, b.m_buffer.capacity 31
> b.m_buffer.length 0, b.m_buffer.capacity 0
>
> capacity 0, suggests that the array has been deallocated.
This means it has 0 capacity for appending according to the runtime, NOT
that the array was deallocated. This is true of non-GC allocated slices
and slices which don't END at the array end.
For example:
auto arr = [1, 2, 3];
auto arr2 = arr[0 .. 2]; // slice off the last element
assert(arr2.capacity == 0);
assert(arr.capacity != 0);
Does this mean the array is deallocated? No, it means that if you
append, there is no capacity to add to. A capacity of 0 means "will
reallocate if you append".
Why does this happen? Because we don't want to stomp on the existing
data that could still be referenced via another slice (in this case arr)
that still points to the original data.
You can read a bit about the array runtime here:
https://dlang.org/articles/d-array-article.html
-Steve
More information about the Digitalmars-d-learn
mailing list