Appending to a dynamic array at specific offset

Frits van Bommel fvbommel at REMwOVExCAPSs.nl
Tue Jan 23 03:49:27 PST 2007


Joseph Bell wrote:
> Hi.
> 
> I'm working with D arrays, getting my bearings, and was looking at 
> treating a ubtye array as a formatted message of sorts.
> 
> Consider the first byte is always a message type header.
> The second and third bytes are a length indicator.
> The fourth and subsequent bytes are the actual data this message conveys.
> 
> If I declare a dynamic array:
> 
> ubyte[] msg;
> 
> I can easily write
> 
> msg ~= TYPE; // TYPE is a ubyte value
> msg ~= LEN_HI; // upper byte of 16-bit length
> msg ~= LEN_LOW; // lower byte of 16-bit length
> 
> At this point I can
> 
> msg ~= data; // where data is a ubyte[]
> 
> But if I want to change the data, I'd like to be able to just append the 
> new data at the offset it needs to go at.
> 
> msg[3] ~= data; // doesn't work, msg[3] is a ubyte, can't append ubyte[]
> &msg[3] ~= data; // Doesn't work, perhaps trying to write C there
> 
> This does work
> msg.length = 3;
> msg ~= data; // Effectively resize the array back to 3 and then append
> 
> I don't know how ineffecient the above approach is.
> 
> Also the following doesn't work:
> 
> msg[3..$] = data; // Array sizes don't match for copy
> msg[3..$] ~= data; // Slice is not a modifiable lvalue
> 
> So the upshot:  I have a working solution to the problem, but it looks 
> unnatural to me.  Am I missing a magic syntactical expression for this?

(Assuming your new data is the same length as the old, since you're not 
adjusting the length information)

I think you have three basic options. One is the one you've found:
msg.length = 3;
msg ~= data;

This is actually pretty efficient as long as msg isn't a (non-prefix) 
slice of another array. If that's the case, and as long as the new data 
isn't longer than the old data, it just copies over it without reallocating.

Another option is:
msg = msg[0 .. 3] ~ data;

This is short but unfortunately always reallocates.

A third option is:
msg[3 .. $] = data;

This just plain copies the new data over the old. This should be 
slightly more efficient than the first method since that one adjusts the 
length twice, while this one doesn't touch the length at all.

The first method does have the benefit that it also works if the new 
data is of a different length as the old data, while only reallocating 
if necessary.
The second also has the benefit that it works for any data lengths, but 
always reallocates. That can also be a benefit, however, if you want to 
preserve the old array.



More information about the Digitalmars-d mailing list