| Thread overview | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
November 28, 2008 Custom opCmp for struct array sort | ||||
|---|---|---|---|---|
| ||||
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; } | ||||
November 28, 2008 Re: Custom opCmp for struct array sort | ||||
|---|---|---|---|---|
| ||||
Posted in reply to New | New:
> 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.
This may work (D1), I have cleaned up your code some:
import std.string: find, cmp;
import std.stdio: writefln;
struct Path {
string thePath;
int opCmp(Path other) {
int pos;
string a, b;
pos = find(this.thePath, "=");
if (pos > -1)
a = this.thePath[0 .. pos];
else
a = this.thePath;
pos = find(other.thePath, "=");
if (pos > -1)
b = other.thePath[0 .. pos];
else
b = other.thePath;
return cmp(a, b);
}
}
void main() {
string[][Path] contents = [
Path("/002=/other_dir"): ["aa","bb","cc","dd"],
Path("/001"): ["aa","bb","cc","dd"],
Path("/002=/hello") : ["aa","bb","cc","dd"]
];
foreach (item; contents.keys.sort)
writefln(item.thePath);
}
Note that you may not need it, because the part before = is on the left, so just sorting the strings may give you the order you need, without using any opCmp.
For other similar questions the D.learn newsgroup is fitter.
Bye,
bearophile
| |||
November 28, 2008 Re: Custom opCmp for struct array sort | ||||
|---|---|---|---|---|
| ||||
Posted in reply to bearophile | Hello,
Thanks for cleaning up the code, I was getting a bit annoyed with the all the invariants, but I did not know how to get rid of them.
I tried your version but still the opCmp is not called :(
I will try on D.learn
thanks very much
bearophile Wrote:
> New:
> > 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.
>
> This may work (D1), I have cleaned up your code some:
>
> import std.string: find, cmp;
> import std.stdio: writefln;
>
> struct Path {
> string thePath;
>
> int opCmp(Path other) {
> int pos;
> string a, b;
>
> pos = find(this.thePath, "=");
> if (pos > -1)
> a = this.thePath[0 .. pos];
> else
> a = this.thePath;
>
> pos = find(other.thePath, "=");
> if (pos > -1)
> b = other.thePath[0 .. pos];
> else
> b = other.thePath;
>
> return cmp(a, b);
> }
> }
>
> void main() {
> string[][Path] contents = [
> Path("/002=/other_dir"): ["aa","bb","cc","dd"],
> Path("/001"): ["aa","bb","cc","dd"],
> Path("/002=/hello") : ["aa","bb","cc","dd"]
> ];
>
> foreach (item; contents.keys.sort)
> writefln(item.thePath);
> }
>
> Note that you may not need it, because the part before = is on the left, so just sorting the strings may give you the order you need, without using any opCmp.
>
> For other similar questions the D.learn newsgroup is fitter.
>
> Bye,
> bearophile
| |||
November 28, 2008 Re: Custom opCmp for struct array sort | ||||
|---|---|---|---|---|
| ||||
Posted in reply to New | New Wrote: > Thanks for cleaning up the code, I was getting a bit annoyed with the all the invariants, but I did not know how to get rid of them. Note that my code is D1. > I tried your version but still the opCmp is not called :( I don't agree, it's called: http://codepad.org/FLVu8gqQ Bye, bearophile | |||
November 28, 2008 Re: Custom opCmp for struct array sort | ||||
|---|---|---|---|---|
| ||||
Posted in reply to bearophile | I see, sorry about that, I missed the D1 bit in your message and tested on D2, what would I need to do to make it run on D2?
Is D2 production ready?, is it better to use D1?
thanks
bearophile Wrote:
> New Wrote:
>
> > Thanks for cleaning up the code, I was getting a bit annoyed with the all the invariants, but I did not know how to get rid of them.
>
> Note that my code is D1.
>
> > I tried your version but still the opCmp is not called :(
>
> I don't agree, it's called:
> http://codepad.org/FLVu8gqQ
>
> Bye,
> bearophile
| |||
November 28, 2008 Re: Custom opCmp for struct array sort | ||||
|---|---|---|---|---|
| ||||
Posted in reply to New | New Wrote: > what would I need to do to make it run on D2? I don't know, sorry :-) > Is D2 production ready? No, surely D2 isn't "production ready", it's alpha stage. D1 is barely like that, despite being a stable beta. >is it better to use D1? D2 is now mostly for testing, I presume. But you are free to use it, it works. Bye, bearophile | |||
November 28, 2008 Re: Custom opCmp for struct array sort | ||||
|---|---|---|---|---|
| ||||
Posted in reply to bearophile | Reply to bearophile,
> New Wrote:
>
>> is it better to use D1?
>>
> D2 is now mostly for testing, I presume. But you are free to use it,
> it works.
>
I'd say it more of a 1.0 release version. Heck windows was a piece of junk for v1 and v2.</joke>
| |||
December 01, 2008 Re: Custom opCmp for struct array sort | ||||
|---|---|---|---|---|
| ||||
Posted in reply to New | "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 | |||
Copyright © 1999-2021 by the D Language Foundation
Permalink
Reply