digitalmars.D.learn - problems with std.bitmanip.append
- Hugo (24/24) Mar 25 2015 Hi,
- John Colvin (13/37) Mar 25 2015 As per the signature in the docs:
- Hugo (7/20) Mar 25 2015 Hmm... the examples for append in the documentation look very
- Steven Schveighoffer (6/28) Mar 25 2015 An array as an output range writes to the front. You can use
- Hugo (11/18) Mar 26 2015 Hmm... isnt that't what the std.bitmanip.write function is for?
- Steven Schveighoffer (14/27) Mar 26 2015 Quite possibly write and append do the same thing for arrays because of
- Hugo (17/18) Mar 26 2015 OK, I made a simpler test, using an example from the
- John Colvin (8/27) Mar 26 2015 void main() {
- Hugo (9/23) Mar 26 2015 Thanks, although it puzzles me that one has to move the type
- John Colvin (7/31) Mar 27 2015 Think of it as compile-time arguments and run-time arguments.
- Hugo (3/8) Mar 27 2015 I really appreciate this little explanation, now it makes some
Hi, I need to append an uint as an array of ubytes (in little endian) to an existing array of ubytes. I tried to compile this code (with dmd 2.066.1 under Windows 7 x86-64): void main() { ubyte[] buffer = [0x1f, 0x8b, 0x08, 0x00]; import std.system; import std.datetime : Clock, stdTimeToUnixTime; import std.bitmanip : append; buffer.append!ubyte(cast(uint)stdTimeToUnixTime(Clock.currStdTime), Endian.littleEndian); } But it gives me this error: template std.bitmanip.append cannot deduce function from argument types !(ubyte)(ubyte[], uint, Endian) Supposedly append "Takes an integral value, converts it to the given endianness, and appends it to the given range of ubytes (using put) as a sequence of T.sizeof ubytes", so I thought I could use it, but after reading the documentation page for the function and the examples, I honestly can't understand where is the problem is. Please, help! Regards, Hugo
Mar 25 2015
On Wednesday, 25 March 2015 at 15:44:50 UTC, Hugo wrote:Hi, I need to append an uint as an array of ubytes (in little endian) to an existing array of ubytes. I tried to compile this code (with dmd 2.066.1 under Windows 7 x86-64): void main() { ubyte[] buffer = [0x1f, 0x8b, 0x08, 0x00]; import std.system; import std.datetime : Clock, stdTimeToUnixTime; import std.bitmanip : append; buffer.append!ubyte(cast(uint)stdTimeToUnixTime(Clock.currStdTime), Endian.littleEndian); } But it gives me this error: template std.bitmanip.append cannot deduce function from argument types !(ubyte)(ubyte[], uint, Endian) Supposedly append "Takes an integral value, converts it to the given endianness, and appends it to the given range of ubytes (using put) as a sequence of T.sizeof ubytes", so I thought I could use it, but after reading the documentation page for the function and the examples, I honestly can't understand where is the problem is. Please, help! Regards, HugoAs per the signature in the docs: void append(T, Endian endianness = Endian.bigEndian, R)(R range, T value) The endianness is the second template argument. What you need to write is buffer.append!(uint, Endian.littleEndian)(cast(uint)stdTimeToUnixTime(Clock.currStdTime)); or append!(uint, Endian.littleEndian)(buffer, cast(uint)stdTimeToUnixTime(Clock.currStdTime)); Note that you don't need to specify the third template argument, that will be inferred automatically from the type of `buffer`
Mar 25 2015
On Wednesday, 25 March 2015 at 17:09:05 UTC, John Colvin wrote:As per the signature in the docs: void append(T, Endian endianness = Endian.bigEndian, R)(R range, T value) The endianness is the second template argument. What you need to write is buffer.append!(uint, Endian.littleEndian)(cast(uint)stdTimeToUnixTime(Clock.currStdTime)); or append!(uint, Endian.littleEndian)(buffer, cast(uint)stdTimeToUnixTime(Clock.currStdTime)); Note that you don't need to specify the third template argument, that will be inferred automatically from the type of `buffer`Hmm... the examples for append in the documentation look very different from the syntax you have suggested. No wonder. In any case, I have tried the code with the first way you suggested, and append actually does not append to the buffer, but... rewrites the buffer! Since the buffer is not static, shouldn't append actually do that?
Mar 25 2015
On 3/25/15 1:29 PM, Hugo wrote:On Wednesday, 25 March 2015 at 17:09:05 UTC, John Colvin wrote:An array as an output range writes to the front. You can use std.array.Appender to get appending behavior. I know, it's weird. Alternatively, you can add more bytes to the array, and append to the slice, but that may be ugly/hard to do. -SteveAs per the signature in the docs: void append(T, Endian endianness = Endian.bigEndian, R)(R range, T value) The endianness is the second template argument. What you need to write is buffer.append!(uint, Endian.littleEndian)(cast(uint)stdTimeToUnixTime(Clock.currStdTime)); or append!(uint, Endian.littleEndian)(buffer, cast(uint)stdTimeToUnixTime(Clock.currStdTime)); Note that you don't need to specify the third template argument, that will be inferred automatically from the type of `buffer`Hmm... the examples for append in the documentation look very different from the syntax you have suggested. No wonder. In any case, I have tried the code with the first way you suggested, and append actually does not append to the buffer, but... rewrites the buffer! Since the buffer is not static, shouldn't append actually do that?
Mar 25 2015
On Thursday, 26 March 2015 at 02:39:56 UTC, Steven Schveighoffer wrote:An array as an output range writes to the front. You can use std.array.Appender to get appending behavior. I know, it's weird. Alternatively, you can add more bytes to the array, and append to the slice, but that may be ugly/hard to do. -SteveHmm... isnt that't what the std.bitmanip.write function is for? It even provides an index. I could make an 8 byte buffer and then make a slice with the last 4 bytes and use append there, but it would be rather a hack around something that should have worked. Perhaps I have found a bug. Actually I am not sure because I am not yet familiar with the way to use templates, so there is the possibility that I am using incorrect arguments. If only the documentation and/or test units were more clear...
Mar 26 2015
On 3/26/15 6:07 AM, Hugo wrote:On Thursday, 26 March 2015 at 02:39:56 UTC, Steven Schveighoffer wrote:Quite possibly write and append do the same thing for arrays because of the way slices support the output range idiom.An array as an output range writes to the front. You can use std.array.Appender to get appending behavior. I know, it's weird. Alternatively, you can add more bytes to the array, and append to the slice, but that may be ugly/hard to do.Hmm... isnt that't what the std.bitmanip.write function is for? It even provides an index.Perhaps I have found a bug. Actually I am not sure because I am not yet familiar with the way to use templates, so there is the possibility that I am using incorrect arguments.No, it's not a bug. A slice does not support appending in the way you expect as an output range. Think of a slice/array as a buffer in which to put information, maybe it's a stack buffer. If you output to this buffer, you wouldn't expect it to allocate more memory and append to the end would you? Instead, you'd expect to write data starting at the beginning. If you want append behavior, use std.array.Appender, as is described in the example of std.bitmanip.append. I do, however, think that the term "append" is very misleading. If it were named "putInto", that might have been a less confusing term. -Steve
Mar 26 2015
On Thursday, 26 March 2015 at 10:07:07 UTC, Hugo wrote:If only the documentation and/or test units were more clear...OK, I made a simpler test, using an example from the documentation: void main() { import std.stdio, std.array, std.bitmanip; auto buffer = appender!(const ubyte[])(); buffer.append!ushort(261); assert(buffer.data == [1, 5]); writefln("%s", buffer.data); } It seems to work, so apparently one has to explicitly create a buffer with the appender template. Not terribly useful IMHO. Wouldn't it be possible for the append function to automaticaly change the mode of an already existing buffer? Also, can anyone provide a similar example but using little endian order? If only to contrast differences between modes of invocation...
Mar 26 2015
On Thursday, 26 March 2015 at 12:21:23 UTC, Hugo wrote:On Thursday, 26 March 2015 at 10:07:07 UTC, Hugo wrote:void main() { import std.stdio, std.array, std.bitmanip, std.system; auto buffer = appender!(const ubyte[])(); buffer.append!(ushort, Endian.littleEndian)(261); assert(buffer.data == [5, 1]); writefln("%s", buffer.data); }If only the documentation and/or test units were more clear...OK, I made a simpler test, using an example from the documentation: void main() { import std.stdio, std.array, std.bitmanip; auto buffer = appender!(const ubyte[])(); buffer.append!ushort(261); assert(buffer.data == [1, 5]); writefln("%s", buffer.data); } It seems to work, so apparently one has to explicitly create a buffer with the appender template. Not terribly useful IMHO. Wouldn't it be possible for the append function to automaticaly change the mode of an already existing buffer? Also, can anyone provide a similar example but using little endian order? If only to contrast differences between modes of invocation...
Mar 26 2015
On Thursday, 26 March 2015 at 12:29:03 UTC, John Colvin wrote:On Thursday, 26 March 2015 at 12:21:23 UTC, Hugo wrote:Thanks, although it puzzles me that one has to move the type inside the parenthesis and the value after them, otherwise it doesn't compile. It looks quite irregular, at least to someone like me, more used to function than templates. :( I wish one could simply append a buffer using the concatenation operator, which would be the obvious choice, but it doesn't seem to work for ubytes...Also, can anyone provide a similar example but using little endian order? If only to contrast differences between modes of invocation...void main() { import std.stdio, std.array, std.bitmanip, std.system; auto buffer = appender!(const ubyte[])(); buffer.append!(ushort, Endian.littleEndian)(261); assert(buffer.data == [5, 1]); writefln("%s", buffer.data); }
Mar 26 2015
On Friday, 27 March 2015 at 00:50:34 UTC, Hugo wrote:On Thursday, 26 March 2015 at 12:29:03 UTC, John Colvin wrote:Think of it as compile-time arguments and run-time arguments. First set of parenthesis are compile-time, second are run-time. The parenthesis are optional for compile-time arguments iff there's only one of them.On Thursday, 26 March 2015 at 12:21:23 UTC, Hugo wrote:Thanks, although it puzzles me that one has to move the type inside the parenthesis and the value after them, otherwise it doesn't compile. It looks quite irregular, at least to someone like me, more used to function than templates. :(Also, can anyone provide a similar example but using little endian order? If only to contrast differences between modes of invocation...void main() { import std.stdio, std.array, std.bitmanip, std.system; auto buffer = appender!(const ubyte[])(); buffer.append!(ushort, Endian.littleEndian)(261); assert(buffer.data == [5, 1]); writefln("%s", buffer.data); }I wish one could simply append a buffer using the concatenation operator, which would be the obvious choice, but it doesn't seem to work for ubytes...I agree that std.bitmanip often doesn't have the most intuitive interface.
Mar 27 2015
On Friday, 27 March 2015 at 08:43:56 UTC, John Colvin wrote:Think of it as compile-time arguments and run-time arguments. First set of parenthesis are compile-time, second are run-time. The parenthesis are optional for compile-time arguments iff there's only one of them.I really appreciate this little explanation, now it makes some sense.
Mar 27 2015