Thread overview
On opCmp
Feb 27, 2015
Nordlöw
Feb 27, 2015
anonymous
Mar 02, 2015
Nordlöw
Feb 27, 2015
Ali Çehreli
February 27, 2015
Is there a more compact way to describe the opCmp function in the following struct

struct Hit
{
    size_t count; // number of walkers that found this node
    NWeight rank; // rank (either minimum distance or maximum strength)

    auto opCmp(const Hit rhs) const
    {
        if      (this.count < rhs.count)
        {
            return -1;
        }
        else if (this.count > rhs.count)
        {
            return +1;
        }
        else
        {
            if      (this.rank < rhs.rank)
            {
                return -1;
            }
            else if (this.rank > rhs.rank)
            {
                return +1;
            }
            else
            {
                return 0;
            }
        }
    }
}

by reusing something like

    auto opCmp(const Hit rhs) const
    {
        if      (this.count < rhs.count)
        {
            return -1;
        }
        else if (this.count > rhs.count)
        {
            return +1;
        }
        else
        {
            return this.rank.standardOpCmp(rhs.rank)
        }
    }
February 27, 2015
On Friday, 27 February 2015 at 11:04:51 UTC, Nordlöw wrote:
> Is there a more compact way to describe the opCmp function in the following struct
>
> struct Hit
> {
>     size_t count; // number of walkers that found this node
>     NWeight rank; // rank (either minimum distance or maximum strength)
>
>     auto opCmp(const Hit rhs) const
>     {
>         if      (this.count < rhs.count)
>         {
>             return -1;
>         }
>         else if (this.count > rhs.count)
>         {
>             return +1;
>         }
>         else
>         {
>             if      (this.rank < rhs.rank)
>             {
>                 return -1;
>             }
>             else if (this.rank > rhs.rank)
>             {
>                 return +1;
>             }
>             else
>             {
>                 return 0;
>             }
>         }
>     }
> }
>
> by reusing something like
>
>     auto opCmp(const Hit rhs) const
>     {
>         if      (this.count < rhs.count)
>         {
>             return -1;
>         }
>         else if (this.count > rhs.count)
>         {
>             return +1;
>         }
>         else
>         {
>             return this.rank.standardOpCmp(rhs.rank)
>         }
>     }

Two things come to mind:

A) std.algorithm.cmp

----
auto opCmp(const Hit rhs) const
{
    import std.algorithm: cmp;
    import std.range: only;
    if(auto c = cmp(only(count), only(rhs.count)))
    {
        return c;
    }
    else /* 'count' values are equal. */
    {
        return cmp(only(rank), only(rhs.rank));
    }
}
----

Maybe there should be a std.algorithm.cmp for non-ranges, too, so that `only` wouldn't be needed here.

B) std.typecons.Tuple has an opCmp that compares all fields in order.

----
auto opCmp(const Hit rhs) const
{
    import std.typecons: tuple;
    return tuple(count, rank).opCmp(tuple(rhs.count, rhs.rank));
}
----

This exact behaviour is not documented, though. So I guess it should not be relied on. Maybe the documentation should be more specific. In the meantime, you could duplicate the functionality in a function of your own:

----
import std.typecons: Tuple;

/** Put a proper, specific description here.
*/
int cmpTuples(Types ...)(Tuple!Types a, Tuple!Types b)
{
    // copied from std.typecons.Tuple.opCmp
    foreach (i, Unused; Types)
    {
        if (a[i] != b[i])
        {
            return a[i] < b[i] ? -1 : 1;
        }
    }
    return 0;
}

struct Hit
{
    size_t count;
    NWeight rank;

    auto opCmp(const Hit rhs) const
    {
        import std.typecons: tuple;
        return cmpTuples(tuple(count, rank), tuple(rhs.count, rhs.rank));
    }
}
----

February 27, 2015
On 2/27/15 6:04 AM, "Nordlöw" wrote:
> Is there a more compact way to describe the opCmp function in the
> following struct
>
> struct Hit
> {
>      size_t count; // number of walkers that found this node
>      NWeight rank; // rank (either minimum distance or maximum strength)
>
>      auto opCmp(const Hit rhs) const
>      {
>          if      (this.count < rhs.count)
>          {
>              return -1;
>          }
>          else if (this.count > rhs.count)
>          {
>              return +1;
>          }
>          else
>          {
>              if      (this.rank < rhs.rank)
>              {
>                  return -1;
>              }
>              else if (this.rank > rhs.rank)
>              {
>                  return +1;
>              }
>              else
>              {
>                  return 0;
>              }
>          }
>      }
> }

Hm... what about:

return count < rhs.count ? -1 : count > rhs.count ? 1 : rank < rhs.rank ? -1 : rank > rhs.rank;

> by reusing something like
>
>      auto opCmp(const Hit rhs) const
>      {
>          if      (this.count < rhs.count)
>          {
>              return -1;
>          }
>          else if (this.count > rhs.count)
>          {
>              return +1;
>          }
>          else
>          {
>              return this.rank.standardOpCmp(rhs.rank)
>          }
>      }

A standard opCmp would be nice. Why wouldn't you use it for count as well?

-Steve

February 27, 2015
On 02/27/2015 03:04 AM, "Nordlöw" wrote:

> Is there a more compact way to describe the opCmp function in the
> following struct

Please see:


http://forum.dlang.org/thread/lnr99a$vvd$1@digitalmars.com#post-lnr99a:24vvd:241:40digitalmars.com

Ali


March 02, 2015
On Friday, 27 February 2015 at 15:00:35 UTC, Steven Schveighoffer wrote:
> Hm... what about:
>
> return count < rhs.count ? -1 : count > rhs.count ? 1 : rank < rhs.rank ? -1 : rank > rhs.rank;

Is this more efficient than my version?
March 02, 2015
On 3/2/15 8:52 AM, "Nordlöw" wrote:
> On Friday, 27 February 2015 at 15:00:35 UTC, Steven Schveighoffer wrote:
>> Hm... what about:
>>
>> return count < rhs.count ? -1 : count > rhs.count ? 1 : rank <
>> rhs.rank ? -1 : rank > rhs.rank;
>
> Is this more efficient than my version?

You said "more compact", not more efficient :)

But I think they are probably the same generated code. I'm not doing anything really different (except for the shortcut for rank > rhs.rank being 1 or 0 based on the conversion to int).

-Steve