Custom opCmp for struct array sort

Steven Schveighoffer schveiguy at yahoo.com
Mon Dec 1 07:56:21 PST 2008


"New" wrote
> Hello,
>
> I am new with D and am stuck with something I hope somebody can help me 
> with it.
> I am trying sort an array of paths which can take the two following forms:
>
> /usr                      ---> normal path
> /bin=/other/bin     ---> a symlink
>
> When I sort these paths, in the case of symlinks I want to ignore the 
> right hand side and I just use the path before the "=" sign.
>
> The array docs for DMD 2.0, say that can create a structure and create a 
> opCmp function to cutomise the way sort works. I have tried this but 
> calling .sort does not seem to pick-up my custom opCmp.
>
> Any help would be very appreciated. I am including the code below
>
> Thanks a lot
> --------------------------------------------------------------------
>
> struct Path {
>  invariant(char) [] thePath;
>
>  int opCmp(Path p) {
>    int pos;
>    invariant(char) [] a;
>    invariant(char) [] b;
>    if( (pos=find(this.thePath, RegExp("="))) > -1 ) {
>      a = this.thePath[0 .. pos];
>    } else {
>      a = this.thePath;
>    }
>    if( (pos=find(p.thePath, RegExp("="))) > -1 ) {
>      b = p.thePath[0 .. pos];
>    } else {
>      b = p.thePath;
>    }
>    int cosa = std.string.cmp(a, b);
>    writefln( a, " comp ", b, "=", cosa);
>    return std.string.cmp(a, b);
>  }
> }
>
> int main(char[][] args) {
>  char[][][Path] contents;
>
>  Path one;
>  one.thePath = "/002=/other_dir";
>  contents[one] = cast(char[][])["aa","bb","cc","dd"];
>
>  Path two;
>  two.thePath = "/001";
>  contents[two] = cast(char[][])["aa","bb","cc","dd"];
>
>  foreach(item; contents.keys.sort) {
>    writefln( item.thePath );
>  }
>
>  return 0;
> }

The problem is the opCmp function signature.

One of the undocumented (as far as I know) features of the compiler is that 
for a struct, if there is an opCmp of a certain signature, the compiler 
saves a function pointer to that opCmp in that struct's typeinfo as 'the' 
opCmp to use when comparing two of those structs.  This is used in 
associative arrays and with sort.

the appropriate signature for D2 (as of 2.019) is:

struct S
{
   int opCmp(const S *s) const;
}

So in order for your code to be used during sort in D 2, you need to change 
your signature to:

>  int opCmp(const Path * p) const {

Then it should work.  If it's different in D 2.021 (and it probably should 
be given the advent of 'SafeD' requiring no pointers), then I don't know 
what it might be, but I'd guess you'd replace 'const Path *p' with 'ref 
const Path p'.

I think these 'special' features should be documented, probably in the 
operators page.  I'll file a bugzilla request.

-Steve 





More information about the Digitalmars-d mailing list