Thread overview | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
February 06, 2015 Issue with template function | ||||
---|---|---|---|---|
| ||||
I'm trying to create a template function that can take in any type of array and convert it to a ubyte array. I'm not concerned with endianness at the moment, but I ran into a roadblock when trying to do this with strings. It already works with ints, chars, etc. Here's the relevant test code: module byteReader; public import std.system : Endian; ubyte[] toBytes(T)(T[] arr) { if (arr == null) { return null; } ubyte[] result = new ubyte[arr.length]; foreach (key, val; arr) { result[key] = cast(ubyte) val; // This is line 16 } return result; } string readString(ubyte[] buffer, uint offset, uint length) { assert( buffer.length >= offset + length ); char[] chars = new char[length]; foreach(key, val; buffer[offset .. offset + length]) { chars[key] = cast(char) val; } return cast(string)chars; } void main() { import std.stdio; readString(toBytes!char(['t','e','s','t']),0,4).writeln; readString(toBytes!string("test"),0,4).writeln; // This is line 39 } Here's the output: byteReader.d(16): Error: cannot cast val of type string to type ubyte byteReader.d(39): Error: template instance byteReader.toBytes!string error instantiating |
February 06, 2015 Re: Issue with template function | ||||
---|---|---|---|---|
| ||||
Posted in reply to Charles | Can I not do this cast because it's immutable? |
February 06, 2015 Re: Issue with template function | ||||
---|---|---|---|---|
| ||||
Posted in reply to Charles | On 2015-02-06 at 18:09, Charles wrote:
> readString(toBytes!char(['t','e','s','t']),0,4).writeln;
> readString(toBytes!string("test"),0,4).writeln; // This is line 39
That second line makes no sense (you didn't provide an array of strings).
Why toBytes!string("test") and not toBytes!char("test") or rather:
toBytes!(immutable char)("test") ?
|
February 06, 2015 Re: Issue with template function | ||||
---|---|---|---|---|
| ||||
Posted in reply to Charles Attachments: | On Fri, 06 Feb 2015 17:09:28 +0000, Charles wrote: > readString(toBytes!string("test"),0,4).writeln; if you'll take a look into druntime sources, you'll find that string is just an alias to `immutable(char)[]`. so you actually doing thing: readString(toBytes!(immutable(char)[])("test"),0,4).writeln; i bet that this is not what you meant. ;-) |
February 07, 2015 Re: Issue with template function | ||||
---|---|---|---|---|
| ||||
Posted in reply to ketmar | On Friday, 6 February 2015 at 17:40:31 UTC, ketmar wrote:
> On Fri, 06 Feb 2015 17:09:28 +0000, Charles wrote:
>
>> readString(toBytes!string("test"),0,4).writeln;
>
> if you'll take a look into druntime sources, you'll find that string is
> just an alias to `immutable(char)[]`. so you actually doing thing:
>
> readString(toBytes!(immutable(char)[])("test"),0,4).writeln;
>
> i bet that this is not what you meant. ;-)
Thanks!
|
February 07, 2015 Re: Issue with template function | ||||
---|---|---|---|---|
| ||||
Posted in reply to Charles | On Friday, 6 February 2015 at 17:09:29 UTC, Charles wrote: > I'm trying to create a template function that can take in any type of array and convert it to a ubyte array. I'm not concerned with endianness at the moment, but I ran into a roadblock when trying to do this with strings. It already works with ints, chars, etc. > > Here's the relevant test code: > > module byteReader; > > public import std.system : Endian; > > ubyte[] toBytes(T)(T[] arr) > { > if (arr == null) > { > return null; > } > > ubyte[] result = new ubyte[arr.length]; > > foreach (key, val; arr) > { > result[key] = cast(ubyte) val; // This is line 16 > } > > return result; > } > > string readString(ubyte[] buffer, uint offset, uint length) > { > assert( buffer.length >= offset + length ); > > char[] chars = new char[length]; > foreach(key, val; buffer[offset .. offset + length]) > { > chars[key] = cast(char) val; > } > > return cast(string)chars; > > } > > void main() { > import std.stdio; > readString(toBytes!char(['t','e','s','t']),0,4).writeln; > readString(toBytes!string("test"),0,4).writeln; // This is line 39 > } > > Here's the output: > byteReader.d(16): Error: cannot cast val of type string to type ubyte > byteReader.d(39): Error: template instance byteReader.toBytes!string error instantiating Are you wanting to to convert each element in arr to a byte thus truncating and losing data (when T.sizeof != 1)? as in toBytes([1,2,3, 42, 500 /*this will be truncated to 244 */]);// T == int here or are you wanting to convert each element to a ubyte array and then concatenate it to the result. as is ubyte[] toBytes(T)(T[] arr) { ubyte[T.sizeof] buf; if (arr is null) { return null; } ubyte[] result = new ubyte[arr.length * T.sizeof]; foreach (i, val; arr) { buf[] = cast(ubyte[T.sizeof])&(arr[i])[0 .. T.sizeof] result ~= buf; } return result; } ? |
February 07, 2015 Re: Issue with template function | ||||
---|---|---|---|---|
| ||||
Posted in reply to Nicholas Wilson | On Saturday, 7 February 2015 at 12:04:12 UTC, Nicholas Wilson wrote: > Are you wanting to to convert each element in arr to a byte thus truncating and losing data (when T.sizeof != 1)? > as in > toBytes([1,2,3, 42, 500 /*this will be truncated to 244 */]);// T == int here > or are you wanting to convert each element to a ubyte array and then concatenate it to the result. > as is > ubyte[] toBytes(T)(T[] arr) > { > ubyte[T.sizeof] buf; > if (arr is null) > { > return null; > } > > ubyte[] result = new ubyte[arr.length * T.sizeof]; > > foreach (i, val; arr) > { > buf[] = cast(ubyte[T.sizeof])&(arr[i])[0 .. T.sizeof] > result ~= buf; > } > > return result; > } > ? The original code I was using was written in Java, and only had a method for strings. This is closer to what I wanted. My unit tests were just going back and forth with readString function, so I was completely missing this for other types. Nice catch! There were a couple issues with your code so I've included the corrected version: ubyte[] toUbytes(T)(T[] arr) { if (arr is null) { return null; } ubyte[T.sizeof] buffer; ubyte[] result = new ubyte[arr.length * T.sizeof]; foreach (i, val; arr) { buffer[] = cast(ubyte[T.sizeof])(&(arr[i]))[0 .. T.sizeof]; // Parenthesis and missing semicolon result[i * T.sizeof .. (i * T.sizeof) + T.sizeof] = buffer; // Specify appropriate slice for buffer to be inserted into } return result; } |
February 08, 2015 Re: Issue with template function | ||||
---|---|---|---|---|
| ||||
Posted in reply to Charles | > The original code I was using was written in Java, and only had a method for strings. This is closer to what I wanted. My unit tests were just going back and forth with readString function, so I was completely missing this for other types. Nice catch! > > There were a couple issues with your code so I've included the corrected version: > That's what I get for replying at 11pm =p > ubyte[] toUbytes(T)(T[] arr) > { > if (arr is null) > { > return null; > } > > ubyte[T.sizeof] buffer; > ubyte[] result = new ubyte[arr.length * T.sizeof]; > > foreach (i, val; arr) > { > buffer[] = cast(ubyte[T.sizeof])(&(arr[i]))[0 .. T.sizeof]; // Parenthesis and missing semicolon > result[i * T.sizeof .. (i * T.sizeof) + T.sizeof] = buffer; // Specify appropriate slice for buffer to be inserted into > } > > return result; > } thinking about it again this can be done in a single memcpy ubyte[] toUbytes(T)(T[] arr) { if (arr is null) { return null; } ubyte[] result = new ubyte[arr.length * T.sizeof]; memcpy(result.ptr, arr.ptr , arr.length * T.sizeof); return result; } and an asUbytes can be done as a cast ubyte[] toUbytes(T)(T[] arr) { if (arr is null) { return null; } return cast(ubyte[]) arr.ptr [0 .. arr.length * T.sizeof]; } |
Copyright © 1999-2021 by the D Language Foundation