digitalmars.D.learn - Issue with template function
- Charles (42/42) Feb 06 2015 I'm trying to create a template function that can take in any
- Charles (1/1) Feb 06 2015 Can I not do this cast because it's immutable?
- FG (4/6) Feb 06 2015 That second line makes no sense (you didn't provide an array of strings)...
- ketmar (5/6) Feb 06 2015 if you'll take a look into druntime sources, you'll find that string is=...
- Charles (2/10) Feb 07 2015 Thanks!
- Nicholas Wilson (25/67) Feb 07 2015 Are you wanting to to convert each element in arr to a byte thus
- Charles (26/51) Feb 07 2015 The original code I was using was written in Java, and only had a
- Nicholas Wilson (22/46) Feb 07 2015 thinking about it again this can be done in a single memcpy
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
Feb 06 2015
Can I not do this cast because it's immutable?
Feb 06 2015
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") ?
Feb 06 2015
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=20
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. ;-)=
Feb 06 2015
On Friday, 6 February 2015 at 17:40:31 UTC, ketmar wrote:On Fri, 06 Feb 2015 17:09:28 +0000, Charles wrote:Thanks!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. ;-)
Feb 07 2015
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;
}
?
Feb 07 2015
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;
}
Feb 07 2015
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 =pubyte[] 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]; }
Feb 07 2015









"Charles" <csmith.ku2013 gmail.com> 