www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - opCmp on a struct keyed by an array of bytes

reply Charles Hixson <charleshixsn earthlink.net> writes:
Is there any better way to write the method than:
(cmp doesn't seem to work, and byte arrays don't have an opCmp method.)

  int opCmp(ref const B24 b) const
{    for    (int i = 0;    i < 24;    i++)
       {    if    (bytes[i] < b.bytes[i])    return    -1;
             if    (bytes[i] > b.bytes[i])    return    1;
        }
        return    0;
}    //    opCmp

FWIW, the key is a fixed length array of ubyte, but similar structs have 
differing lengths.   If it's not supported by the system I don't want to 
do something like casting the pieces
to ulongs and comparing those rather than the bytes.  The added 
complexity isn't worth it.

-- 
Charles Hixson
Nov 12 2013
parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 11/12/2013 01:06 PM, Charles Hixson wrote:
 Is there any better way to write the method than:
 (cmp doesn't seem to work, and byte arrays don't have an opCmp method.)

   int opCmp(ref const B24 b) const
 {    for    (int i = 0;    i < 24;    i++)
        {    if    (bytes[i] < b.bytes[i])    return    -1;
              if    (bytes[i] > b.bytes[i])    return    1;
         }
         return    0;
 }    //    opCmp

 FWIW, the key is a fixed length array of ubyte, but similar structs have
 differing lengths.   If it's not supported by the system I don't want to
 do something like casting the pieces
 to ulongs and comparing those rather than the bytes.  The added
 complexity isn't worth it.
There is std.algorithm.cmp: import std.algorithm; struct B24 { byte[24] bytes; int opCmp(ref const B24 b) const { return bytes[].cmp(b.bytes[]); } } void main() { auto a = B24(); auto b = B24(); assert(a == b); a.bytes[23] = 1; assert(a > b); b.bytes[22] = 1; assert(b > a); } Ali
Nov 12 2013
next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Ali Çehreli:

     int opCmp(ref const B24 b) const
     {
         return bytes[].cmp(b.bytes[]);
Few months ago I have written a small rant about that. That little [] at the end of those arrays is not innocuous, it essentially throws away a very precious compile-time amount of information: the static length of the arrays. So for the compiler it becomes much harder to optimize those loops. In my opinion this is an unacceptable part of the design of Phobos (mostly std.algorithm). Bye, bearophile
Nov 12 2013
prev sibling parent reply Charles Hixson <charleshixsn earthlink.net> writes:
On 11/12/2013 01:38 PM, Ali Çehreli wrote:
 On 11/12/2013 01:06 PM, Charles Hixson wrote:
 Is there any better way to write the method than:
 (cmp doesn't seem to work, and byte arrays don't have an opCmp method.)

   int opCmp(ref const B24 b) const
 {    for    (int i = 0;    i < 24;    i++)
        {    if    (bytes[i] < b.bytes[i])    return    -1;
              if    (bytes[i] > b.bytes[i])    return    1;
         }
         return    0;
 }    //    opCmp

 FWIW, the key is a fixed length array of ubyte, but similar structs have
 differing lengths.   If it's not supported by the system I don't want to
 do something like casting the pieces
 to ulongs and comparing those rather than the bytes.  The added
 complexity isn't worth it.
There is std.algorithm.cmp: import std.algorithm; struct B24 { byte[24] bytes; int opCmp(ref const B24 b) const { return bytes[].cmp(b.bytes[]); } } void main() { auto a = B24(); auto b = B24(); assert(a == b); a.bytes[23] = 1; assert(a > b); b.bytes[22] = 1; assert(b > a); } Ali
Thank you. That's exactly the answer I was looking for. ( I had tried "return bytes.cmp(b.bytes);" , but it didn't occur to me that the error meant I should have used a copy? Does this syntax mean that what's being compared is a dynamic array copy of the original static array? Even if it is, that's the answer I wanted. -- Charles Hixson
Nov 12 2013
parent reply "bearophile" <bearophileHUGS lycos.com> writes:
Charles Hixson:

 I had tried "return bytes.cmp(b.bytes);" , but it didn't occur 
 to me that the error meant I should have used a copy?  Does 
 this syntax mean that what's being compared is a dynamic array 
 copy of the original static array?
They are not copies, just slices. In case of doubts take a look at the generated assembly. Bye, bearophile
Nov 12 2013
parent reply Charles Hixson <charleshixsn earthlink.net> writes:
On 11/12/2013 04:47 PM, bearophile wrote:
 Charles Hixson:

 I had tried "return bytes.cmp(b.bytes);" , but it didn't occur to me 
 that the error meant I should have used a copy?  Does this syntax 
 mean that what's being compared is a dynamic array copy of the 
 original static array?
They are not copies, just slices. In case of doubts take a look at the generated assembly. Bye, bearophile
My assembly is pretty bad, the last one I was fluent in was i6502...I was never really fluent in m68000. And those were back when I was using an Apple. OTOH, while slice is a better term for what I meant...generally when one makes a copy of an object, one is only duplicating the pointers to it, and that's what I meant. (Though since the original was a struct, slice is a much better term. Still, on a 64 bit machine the and an 8 byte key, the slice is twice the size of the original. And the only benefit(?) is that if the dup was changed, so would be the original. Which is what the I thought the const at the end of the declaration was supposed to prevent.) -- Charles Hixson
Nov 13 2013
parent =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 11/13/2013 07:46 PM, Charles Hixson wrote:

 On 11/12/2013 04:47 PM, bearophile wrote:
 Charles Hixson:

 I had tried "return bytes.cmp(b.bytes);" , but it didn't occur to me
 that the error meant I should have used a copy?  Does this syntax
 mean that what's being compared is a dynamic array copy of the
 original static array?
They are not copies, just slices. In case of doubts take a look at the generated assembly. Bye, bearophile
My assembly is pretty bad, the last one I was fluent in was i6502...I was never really fluent in m68000. And those were back when I was using an Apple. OTOH, while slice is a better term for what I meant...generally when one makes a copy of an object, one is only duplicating the pointers to it, and that's what I meant. (Though since the original was a struct, slice is a much better term. Still, on a 64 bit machine the and an 8 byte key, the slice is twice the size of the original. And the only benefit(?) is that if the dup was changed, so would be the original. Which is what the I thought the const at the end of the declaration was supposed to prevent.)
I think what we are agreeing here is that there should be a cmp() specialization for fixed-length arrays, both for performance reasons and for convenience. In the absence of that specialization, your for loop works well. std.algorithm.cmp is another option but it requires an InputRange. Since fixed-length arrays do not satisfy the requirements of InputRange (cannot provide popFront()), we must get a slice of all of its elements. Still, I have a feeling that ldc would be able to use the information that the length of the slice is based on a constant expression and produce faster code. (No citation known. :p) Ali
Nov 14 2013