www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Best way to compare primitive types

reply Jari-Matti =?ISO-8859-1?Q?M=E4kel=E4?= <jmjmak utu.fi.invalid> writes:
Let's say I want to write a wrapper around a primitive type (it could
possibly also be a class or struct, but that isn't necessary now). What's
the best way to do opCmp? I've seen there is TypeInfo.compare there
somewhere, but how does it work? I get

  Error: this for compare needs to be type TypeInfo not type Foo *

Also, if it works, does it have performance problems? I read from the ng
archives that the compiler might not inline it.

Here's the stuff I'm writing:

struct Foo(T) {
        T value;

        // or maybe T opCmp(T other) for reals, floats etc.
        // to handle NaN properly
        int opCmp(T other) {
                // I would like to do something like

                // return builtin.opCmp(value, other.value);

                // because there are so many special cases for
                // the primitive types and it feels a bit stupid
                // to reimplement the comparison in every wrapper
        }
}
May 08 2007
next sibling parent reply Daniel Keep <daniel.keep.lists gmail.com> writes:
Jari-Matti Mäkelä wrote:
 Let's say I want to write a wrapper around a primitive type (it could
 possibly also be a class or struct, but that isn't necessary now). What's
 the best way to do opCmp? I've seen there is TypeInfo.compare there
 somewhere, but how does it work? I get
 
   Error: this for compare needs to be type TypeInfo not type Foo *
 
 Also, if it works, does it have performance problems? I read from the ng
 archives that the compiler might not inline it.
 
 Here's the stuff I'm writing:
 
 struct Foo(T) {
         T value;
 
         // or maybe T opCmp(T other) for reals, floats etc.
         // to handle NaN properly
         int opCmp(T other) {
                 // I would like to do something like
 
                 // return builtin.opCmp(value, other.value);
 
                 // because there are so many special cases for
                 // the primitive types and it feels a bit stupid
                 // to reimplement the comparison in every wrapper
         }
 }

I imagine if you wanted to do it *properly*, you could write a templated compare function that uses static ifs to do comparison of atomic numeric types, arrays of (sometype), aas of (sometype, sometype), structs, classes, typedefs and pointers to (sometype). Or, you could just cheat. int opCmp(T other) { if( other < this ) return -1; else if( this < other ) return 1; else if( this == other ) return 0; else assert(false); // you COULD get here if other is NaN } -- int getRandomNumber() { return 4; // chosen by fair dice roll. // guaranteed to be random. } http://xkcd.com/ v2sw5+8Yhw5ln4+5pr6OFPma8u6+7Lw4Tm6+7l6+7D i28a2Xs3MSr2e4/6+7t4TNSMb6HTOp5en5g6RAHCP http://hackerkey.com/
May 08 2007
parent reply Jari-Matti =?ISO-8859-1?Q?M=E4kel=E4?= <jmjmak utu.fi.invalid> writes:
Daniel Keep wrote:
 Jari-Matti Mäkelä wrote:
 Let's say I want to write a wrapper around a primitive type (it could
 possibly also be a class or struct, but that isn't necessary now). What's
 the best way to do opCmp?


 I imagine if you wanted to do it *properly*, you could write a templated 
 compare function that uses static ifs to do comparison of atomic
 numeric types, arrays of (sometype), aas of (sometype, sometype),
 structs, classes, typedefs and pointers to (sometype).

 Or, you could just cheat.
 
 int opCmp(T other)
 {
     if( other < this ) return -1;
     else if( this < other ) return 1;
     else if( this == other ) return 0;
     else assert(false); // you COULD get here if other is NaN
 }

Thanks for all the answers. Actually this is almost the same I have now. I just created another version of opCmp for types that have a NaN value and made them return NaN, not assert. Ok, I think your reply also answers my question about the builtin comparison functionality. So there isn't currently one. Wouldn't it be useful to get a "properly" done templated version into the "standard library"?
May 08 2007
parent Don Clugston <dac nospam.com.au> writes:
Jari-Matti Mäkelä wrote:
 Daniel Keep wrote:
 Jari-Matti Mäkelä wrote:
 Let's say I want to write a wrapper around a primitive type (it could
 possibly also be a class or struct, but that isn't necessary now). What's
 the best way to do opCmp?


 I imagine if you wanted to do it *properly*, you could write a templated 
 compare function that uses static ifs to do comparison of atomic
 numeric types, arrays of (sometype), aas of (sometype, sometype),
 structs, classes, typedefs and pointers to (sometype).

 Or, you could just cheat.

 int opCmp(T other)
 {
     if( other < this ) return -1;
     else if( this < other ) return 1;
     else if( this == other ) return 0;
     else assert(false); // you COULD get here if other is NaN
 }

Thanks for all the answers. Actually this is almost the same I have now. I just created another version of opCmp for types that have a NaN value and made them return NaN, not assert.

Since there is no opUnordered(), (you can't have !<>= for UDTs) it's hard to know what to do with a NaN -- I don't think it's possible to make it work sensibly. It's inevitable that it will be different to the built-in operators.
 Ok, I think your reply also answers my question about the builtin comparison
 functionality. So there isn't currently one. Wouldn't it be useful to get
 a "properly" done templated version into the "standard library"?

May 08 2007
prev sibling next sibling parent reply Ary Manzana <ary esperanto.org.ar> writes:
Maybe something like this:
---
int opCmp(T other) {
     return this.value > other ? 1 :
         (this.value < other ? -1 : 0);
}
---

Usage:
---
void main() {
	Foo!(int) f1;
	f1.value = 5;
	
	writefln("%s", f1 < 6);
	writefln("%s", f1 > 6);
}
---

Ouputs:
true
false

Note that for equals comparison you need to implement opEquals (I didn't 
know that until I wrote the example... isn't it a bit akward?).

Jari-Matti Mäkelä escribió:
 Let's say I want to write a wrapper around a primitive type (it could
 possibly also be a class or struct, but that isn't necessary now). What's
 the best way to do opCmp? I've seen there is TypeInfo.compare there
 somewhere, but how does it work? I get
 
   Error: this for compare needs to be type TypeInfo not type Foo *
 
 Also, if it works, does it have performance problems? I read from the ng
 archives that the compiler might not inline it.
 
 Here's the stuff I'm writing:
 
 struct Foo(T) {
         T value;
 
         // or maybe T opCmp(T other) for reals, floats etc.
         // to handle NaN properly
         int opCmp(T other) {
                 // I would like to do something like
 
                 // return builtin.opCmp(value, other.value);
 
                 // because there are so many special cases for
                 // the primitive types and it feels a bit stupid
                 // to reimplement the comparison in every wrapper
         }
 }

May 08 2007
parent reply Ary Manzana <ary esperanto.org.ar> writes:
Henning Hasemann escribió:
 On Tue, 08 May 2007 09:43:28 -0300
 Ary Manzana <ary esperanto.org.ar> wrote:
 
 Maybe something like this:
 ---
 int opCmp(T other) {
      return this.value > other ? 1 :
          (this.value < other ? -1 : 0);
 }

I always write this as: return this.value < other ? -1 : this.value > other; Which is more leet (read unreadable) ,-) Henning

Oh... That's because I'm almost always programming in Java (int can be converted to a boolean). :-P
May 08 2007
parent Ary Manzana <ary esperanto.org.ar> writes:
Ary Manzana escribió:
 Henning Hasemann escribió:
 On Tue, 08 May 2007 09:43:28 -0300
 Ary Manzana <ary esperanto.org.ar> wrote:

 Maybe something like this:
 ---
 int opCmp(T other) {
      return this.value > other ? 1 :
          (this.value < other ? -1 : 0);
 }

I always write this as: return this.value < other ? -1 : this.value > other; Which is more leet (read unreadable) ,-) Henning

Oh... That's because I'm almost always programming in Java (int can be converted to a boolean). :-P

Obviously I mistyped the word "can". It should be "can't".
May 08 2007
prev sibling next sibling parent Henning Hasemann <hhasemann web.de> writes:
On Tue, 08 May 2007 09:43:28 -0300
Ary Manzana <ary esperanto.org.ar> wrote:

 Maybe something like this:
 ---
 int opCmp(T other) {
      return this.value > other ? 1 :
          (this.value < other ? -1 : 0);
 }

I always write this as: return this.value < other ? -1 : this.value > other; Which is more leet (read unreadable) ,-) Henning
May 08 2007
prev sibling next sibling parent "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"Jari-Matti Mäkelä" <jmjmak utu.fi.invalid> wrote in message 
news:f1ppgi$262c$1 digitalmars.com...
  Error: this for compare needs to be type TypeInfo not type Foo *

 struct Foo(T) {
        T value;

        // or maybe T opCmp(T other) for reals, floats etc.
        // to handle NaN properly
        int opCmp(T other) {

You can use: return typeid(T).compare(this, &other); But you've still got the NaN issue..
        }
 } 

May 08 2007
prev sibling parent John Ohno <john.ohno gmail.com> writes:
Jari-Matti Mäkelä Wrote:

 Let's say I want to write a wrapper around a primitive type (it could
 possibly also be a class or struct, but that isn't necessary now). What's
 the best way to do opCmp? I've seen there is TypeInfo.compare there
 somewhere, but how does it work? I get
 
   Error: this for compare needs to be type TypeInfo not type Foo *
 
 Also, if it works, does it have performance problems? I read from the ng
 archives that the compiler might not inline it.
 
 Here's the stuff I'm writing:
 
 struct Foo(T) {
         T value;
 
         // or maybe T opCmp(T other) for reals, floats etc.
         // to handle NaN properly
         int opCmp(T other) {
                 // I would like to do something like
 
                 // return builtin.opCmp(value, other.value);
 
                 // because there are so many special cases for
                 // the primitive types and it feels a bit stupid
                 // to reimplement the comparison in every wrapper
         }
 }

This should work: int opCmp!(T)(T o1, T o2) { return ((*(cast(void[]*)(cast(void*)o1)))==(*(cast(void[]*)(cast(void*)o2)))); } It should work for any type, primitive or otherwise.
May 08 2007