www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Issue with template function

reply "Charles" <csmith.ku2013 gmail.com> writes:
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
next sibling parent "Charles" <csmith.ku2013 gmail.com> writes:
Can I not do this cast because it's immutable?
Feb 06 2015
prev sibling next sibling parent FG <home fgda.pl> writes:
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
prev sibling next sibling parent reply ketmar <ketmar ketmar.no-ip.org> writes:
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
parent "Charles" <csmith.ku2013 gmail.com> writes:
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!
Feb 07 2015
prev sibling parent reply "Nicholas Wilson" <iamthewilsonator hotmail.com> writes:
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
parent reply "Charles" <csmith.ku2013 gmail.com> writes:
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
parent "Nicholas Wilson" <iamthewilsonator hotmail.com> writes:
 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]; }
Feb 07 2015