Thread overview
attribute length missing in std.array: Appender
Nov 27, 2014
Andre
Nov 27, 2014
Marc Schütz
Nov 28, 2014
andre
Nov 28, 2014
Ali Çehreli
Nov 28, 2014
bearophile
Nov 29, 2014
Ali Çehreli
Nov 29, 2014
bearophile
November 27, 2014
Hi,

I implement a network protocol and use an Appender!(ubyte[])().
I have following issue. The first three bytes I have to fill,
the following bytes are reserved and must be 0. In this example
the overall header length must be 8.

import std.array: appender;
const HEADER_LENGTH = 8;
	
auto app = appender!(ubyte[])();
app.put(cast(ubyte)40);
app.put(cast(ubyte)5);
app.put(cast(ubyte)234);
// ... add 5 times 0
// variable length body will follow

In case of dynamic array I can simple set the length to 8.
Appender doesn't have a length attribute.

Is there some other nice D functionaliy I can use?
Maybe some functionality in std.array is missing: app.fill(0, HEADER_LENGTH)?
Currently I do a work around with a for loop.

Kind regards
André
November 27, 2014
On Thursday, 27 November 2014 at 16:08:13 UTC, Andre wrote:
> Hi,
>
> I implement a network protocol and use an Appender!(ubyte[])().
> I have following issue. The first three bytes I have to fill,
> the following bytes are reserved and must be 0. In this example
> the overall header length must be 8.
>
> import std.array: appender;
> const HEADER_LENGTH = 8;
> 	
> auto app = appender!(ubyte[])();
> app.put(cast(ubyte)40);
> app.put(cast(ubyte)5);
> app.put(cast(ubyte)234);
> // ... add 5 times 0
> // variable length body will follow
>
> In case of dynamic array I can simple set the length to 8.
> Appender doesn't have a length attribute.
>
> Is there some other nice D functionaliy I can use?
> Maybe some functionality in std.array is missing: app.fill(0, HEADER_LENGTH)?
> Currently I do a work around with a for loop.
>
> Kind regards
> André

You can initialize the appender with an existing array, or put an entire array into it at once:

    import std.array: appender;
    ubyte[] temp;
    temp.reserve(8);  // reserve first, so that only one allocation happens
    temp[0 .. 3] = [40, 5, 234];
    temp.length = 8;
    auto app = appender!(ubyte[])(temp);
    // or:
    app.put(temp);

The array will not be copied when the appender is constructed.
November 28, 2014
Thanks a lot for the help.

Kind regards
André



On Thursday, 27 November 2014 at 17:29:50 UTC, Marc Schütz wrote:
> On Thursday, 27 November 2014 at 16:08:13 UTC, Andre wrote:
>> Hi,
>>
>> I implement a network protocol and use an Appender!(ubyte[])().
>> I have following issue. The first three bytes I have to fill,
>> the following bytes are reserved and must be 0. In this example
>> the overall header length must be 8.
>>
>> import std.array: appender;
>> const HEADER_LENGTH = 8;
>> 	
>> auto app = appender!(ubyte[])();
>> app.put(cast(ubyte)40);
>> app.put(cast(ubyte)5);
>> app.put(cast(ubyte)234);
>> // ... add 5 times 0
>> // variable length body will follow
>>
>> In case of dynamic array I can simple set the length to 8.
>> Appender doesn't have a length attribute.
>>
>> Is there some other nice D functionaliy I can use?
>> Maybe some functionality in std.array is missing: app.fill(0, HEADER_LENGTH)?
>> Currently I do a work around with a for loop.
>>
>> Kind regards
>> André
>
> You can initialize the appender with an existing array, or put an entire array into it at once:
>
>     import std.array: appender;
>     ubyte[] temp;
>     temp.reserve(8);  // reserve first, so that only one allocation happens
>     temp[0 .. 3] = [40, 5, 234];
>     temp.length = 8;
>     auto app = appender!(ubyte[])(temp);
>     // or:
>     app.put(temp);
>
> The array will not be copied when the appender is constructed.

November 28, 2014
On 11/27/2014 08:08 AM, Andre wrote:

> import std.array: appender;
> const HEADER_LENGTH = 8;
>
> auto app = appender!(ubyte[])();
> app.put(cast(ubyte)40);
> app.put(cast(ubyte)5);
> app.put(cast(ubyte)234);
> // ... add 5 times 0

A fancy way: :)

import std.range;

// ...

    app.put(repeat(cast(ubyte)0).take(5));

Ali

November 28, 2014
Ali Çehreli:

>> auto app = appender!(ubyte[])();
>> app.put(cast(ubyte)40);
>> app.put(cast(ubyte)5);
>> app.put(cast(ubyte)234);
>> // ... add 5 times 0
>
> A fancy way: :)
>
> import std.range;
>
> // ...
>
>     app.put(repeat(cast(ubyte)0).take(5));

Now we have a better syntax for implicit casts:

void main() {
    import std.array, std.range;
    Appender!(ubyte[]) app;
    app.put(ubyte(0).repeat.take(5));
}


Single line, but not lazy:

void main() {
    import std.array, std.range;
    Appender!(ubyte[]) app = ubyte(0).repeat.take(5).array;
}


But I have a question too. What's the best way to append several lazy items to a dynamic array? This doesn't work:

void main() {
    import std.array, std.range;
    int[] arr;
    arr.put(only(1, 2, 3));
}

Bye,
bearophile
November 29, 2014
On 11/28/2014 12:44 AM, bearophile wrote:

> Now we have a better syntax for implicit casts:

[...]

>      app.put(ubyte(0).repeat.take(5));

Much better! :)

> But I have a question too. What's the best way to append several lazy
> items to a dynamic array? This doesn't work:
>
> void main() {
>      import std.array, std.range;
>      int[] arr;
>      arr.put(only(1, 2, 3));
> }

I don't think there is a better way in Phobos. (?) The following trivial function would do as long as the array has room at the end, which requires that it is "safe to append":

void expandWith(A, R)(ref A arr, R range)
{
    foreach (e; range) {
        arr ~= e;
    }
}

void main() {
    import std.range;

    int[] arr = [ 42 ];

    // Ensure that there is room for new elements
    arr.reserve(100);
    assumeSafeAppend(arr);

    const oldPlace = arr.ptr;
    arr.expandWith(only(1, 2, 3));
    const newPlace = arr.ptr;

    assert(newPlace == oldPlace);
}

Ali

November 29, 2014
Ali Çehreli:

> void expandWith(A, R)(ref A arr, R range)
> {
>     foreach (e; range) {
>         arr ~= e;
>     }
> }

I'd like a function like that in Phobos (with a little improvement: when the length of the given range is available inside expandWith, it should first extend the capacity to increase performance a little). But I'd call it "extend" as in Python.

Bye,
bearophile