www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Passing a ubyte[] to a function taking a 'ref ubyte[16]'

reply Johannes Pfau <nospam example.com> writes:
I'm working on the new design for std.hash and I hit an interesting
problem:

The OOP interface has to take buffers as slices with unknown length, as
the length differs between hashes and I have to put a common function
declaration in a interface. So I have this:
------------
interface Digest
{
    ubyte[] finish(ubyte[] buf);
}
------------

Now the template API can and should use the correct type, so there
finish is defined like this:
------------
struct MD5
{
    void finish(ref ubyte[16] data);
}
------------

And the interface implementation for MD5 has to call the MD5 structs
finish function:
------------
class MD5Digest : Digest
{
    private MD5 _digest;

    ubyte[] finish(ubyte[] buf)
    {
        enforce(buf.length >= 16);
        _digest.finish(buf); //How to do this?
    }
}
------------

So how to pass a ubyte[] to a function expecting a ref ubyte[16]
without allocating/using any extra memory (Not even stack)?

This seems to work, but it's very ugly:
------------
_digest.finish(*cast(ubyte[16]*)buf.ptr);
------------

I thought this might create a temporary, but it passes all unittests,
so it seems to work?
Jun 23 2012
next sibling parent simendsjo <simendsjo gmail.com> writes:
On Sat, 23 Jun 2012 20:23:26 +0200, Johannes Pfau <nospam example.com>  
wrote:

 So how to pass a ubyte[] to a function expecting a ref ubyte[16]
 without allocating/using any extra memory (Not even stack)?
 This seems to work, but it's very ugly:
 ------------
 _digest.finish(*cast(ubyte[16]*)buf.ptr);
 ------------
 I thought this might create a temporary, but it passes all unittests,
 so it seems to work?

I don't have a clue, but the following seems to work as well :) void sarr(ref ubyte[1] a) { darr(a.ptr[0..a.length]); } void darr(ubyte[] a) { a[0] = 2; } void main() { ubyte[1] a = [1]; sarr(a); assert(a[0] == 2); }
Jun 23 2012
prev sibling next sibling parent simendsjo <simendsjo gmail.com> writes:
On Sat, 23 Jun 2012 20:33:09 +0200, simendsjo <simendsjo gmail.com> wrote:

 On Sat, 23 Jun 2012 20:23:26 +0200, Johannes Pfau <nospam example.com>  
 wrote:

 So how to pass a ubyte[] to a function expecting a ref ubyte[16]
 without allocating/using any extra memory (Not even stack)?
 This seems to work, but it's very ugly:
 ------------
 _digest.finish(*cast(ubyte[16]*)buf.ptr);
 ------------
 I thought this might create a temporary, but it passes all unittests,
 so it seems to work?

I don't have a clue, but the following seems to work as well :) void sarr(ref ubyte[1] a) { darr(a.ptr[0..a.length]); } void darr(ubyte[] a) { a[0] = 2; } void main() { ubyte[1] a = [1]; sarr(a); assert(a[0] == 2); }

Oops.. Just saw it should have been the other way around. Never mind me
Jun 23 2012
prev sibling next sibling parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
On Saturday, June 23, 2012 20:23:26 Johannes Pfau wrote:
 I'm working on the new design for std.hash and I hit an interesting
 problem:
 
 The OOP interface has to take buffers as slices with unknown length, as
 the length differs between hashes and I have to put a common function
 declaration in a interface. So I have this:
 ------------
 interface Digest
 {
     ubyte[] finish(ubyte[] buf);
 }
 ------------

I confess that I'm baffled as to why you'd even be using interfaces for this, given that Phobos always uses structs and templates for this sort of thing.
 Now the template API can and should use the correct type, so there
 finish is defined like this:
 ------------
 struct MD5
 {
     void finish(ref ubyte[16] data);
 }
 ------------
 
 And the interface implementation for MD5 has to call the MD5 structs
 finish function:
 ------------
 class MD5Digest : Digest
 {
     private MD5 _digest;
 
     ubyte[] finish(ubyte[] buf)
     {
         enforce(buf.length >= 16);
         _digest.finish(buf); //How to do this?
     }
 }
 ------------
 
 So how to pass a ubyte[] to a function expecting a ref ubyte[16]
 without allocating/using any extra memory (Not even stack)?
 
 This seems to work, but it's very ugly:
 ------------
 _digest.finish(*cast(ubyte[16]*)buf.ptr);
 ------------
 
 I thought this might create a temporary, but it passes all unittests,
 so it seems to work?

I believe that that will work, but it's definitely ugly. However, if you do that, you _need_ to put an assertion about the length of buf in there, otherwise, you could be using memory from past the end of buf. - Jonathan M Davis
Jun 23 2012
parent =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 06/23/2012 04:51 PM, Jonathan M Davis wrote:

 This seems to work, but it's very ugly:
 ------------
 _digest.finish(*cast(ubyte[16]*)buf.ptr);
 ------------

 I thought this might create a temporary, but it passes all unittests,
 so it seems to work?

I believe that that will work, but it's definitely ugly. However, if

 that, you _need_ to put an assertion about the length of buf in there,
 otherwise, you could be using memory from past the end of buf.

 - Jonathan M Davis

I had the following function template in a message that did not appear on the newsgroup: ref T[N] asArray(size_t N, T)(ref T[] source) { enforce(source.length >= N); return *cast(T[N]*)source.ptr; } // ... foo(asArray!16(b)); Ali
Jun 23 2012
prev sibling next sibling parent Johannes Pfau <nospam example.com> writes:
Am Sat, 23 Jun 2012 16:51:14 -0700
schrieb Jonathan M Davis <jmdavisProg gmx.com>:

 On Saturday, June 23, 2012 20:23:26 Johannes Pfau wrote:
 I'm working on the new design for std.hash and I hit an interesting
 problem:
 
 The OOP interface has to take buffers as slices with unknown
 length, as the length differs between hashes and I have to put a
 common function declaration in a interface. So I have this:
 ------------
 interface Digest
 {
     ubyte[] finish(ubyte[] buf);
 }
 ------------

I confess that I'm baffled as to why you'd even be using interfaces for this, given that Phobos always uses structs and templates for this sort of thing.

As discussed in the main newsgroup I use both. Interfaces and classes are useful if you want to change the crypto backend (D/OpenSSL/Windows Crypto API) at runtime and without breaking the ABI. Regan Heath who designed the Tango digest module, also said that digets are often used with the factory pattern, which doesn't work with structs / templates.
 
 I believe that that will work, but it's definitely ugly. However, if
 you do that, you _need_ to put an assertion about the length of buf
 in there, otherwise, you could be using memory from past the end of
 buf.
 

enforce(buf.length >= 16);
Jun 24 2012
prev sibling next sibling parent Johannes Pfau <nospam example.com> writes:
Am Sat, 23 Jun 2012 23:39:00 -0700
schrieb Ali =C3=87ehreli <acehreli yahoo.com>:

 On 06/23/2012 04:51 PM, Jonathan M Davis wrote:
=20
  >> This seems to work, but it's very ugly:
  >> ------------
  >> _digest.finish(*cast(ubyte[16]*)buf.ptr);
  >> ------------
  >>
  >> I thought this might create a temporary, but it passes all
  >> unittests, so it seems to work?
  >
  > I believe that that will work, but it's definitely ugly. However,
  > if=20
 you do
  > that, you _need_ to put an assertion about the length of buf in
  > there, otherwise, you could be using memory from past the end of
  > buf.
  >
  > - Jonathan M Davis
=20
 I had the following function template in a message that did not
 appear on the newsgroup:
=20
 ref T[N] asArray(size_t N, T)(ref T[] source)
 {
      enforce(source.length >=3D N);
      return *cast(T[N]*)source.ptr;
 }
=20
 // ...
=20
      foo(asArray!16(b));
=20
 Ali
=20

Yes that's better. Could this be added to phobos, probably std.typecons?
Jun 24 2012
prev sibling parent "Regan Heath" <regan netmail.co.nz> writes:
On Sun, 24 Jun 2012 08:27:00 +0100, Johannes Pfau <nospam example.com>  
wrote:

 Am Sat, 23 Jun 2012 16:51:14 -0700
 schrieb Jonathan M Davis <jmdavisProg gmx.com>:

 On Saturday, June 23, 2012 20:23:26 Johannes Pfau wrote:
 I'm working on the new design for std.hash and I hit an interesting
 problem:

 The OOP interface has to take buffers as slices with unknown
 length, as the length differs between hashes and I have to put a
 common function declaration in a interface. So I have this:
 ------------
 interface Digest
 {
     ubyte[] finish(ubyte[] buf);
 }
 ------------

I confess that I'm baffled as to why you'd even be using interfaces for this, given that Phobos always uses structs and templates for this sort of thing.

As discussed in the main newsgroup I use both. Interfaces and classes are useful if you want to change the crypto backend (D/OpenSSL/Windows Crypto API) at runtime and without breaking the ABI. Regan Heath who designed the Tango digest module, also said that digets are often used with the factory pattern, which doesn't work with structs / templates.

Correction; I supplied some code which became the Tango digest modules, someone else defined the final API and made all my code 'fit'. I think factory pattern is a commonly desired usage pattern for hashing, crypto, compression, etc. R -- Using Opera's revolutionary email client: http://www.opera.com/mail/
Jun 25 2012