-
-
Notifications
You must be signed in to change notification settings - Fork 747
Issue 8829 - std.algorithm.find fails to take advantage of SortedRange #4907
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
andralex
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good going, thanks for this work.
std/algorithm/searching.d
Outdated
| // Works only for the default find predicate and any SortedRange predicate. | ||
| // 8829 enhancement | ||
| import std.range: SortedRange; | ||
| static if(is(typeof(haystack) : SortedRange!TT, TT) && isDefaultPred) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
space after if
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You already have the type of haystack: static if (is(InputRange : SortedRange!TT, TT) && isDefaultPred)
std/algorithm/searching.d
Outdated
| static if(is(typeof(haystack) : SortedRange!TT, TT) && isDefaultPred) | ||
| { | ||
| auto partitions = haystack.trisect(needle); | ||
| if(partitions[1].length == 0) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
space after if (throughout please)
std/algorithm/searching.d
Outdated
| import std.range: SortedRange; | ||
| static if(is(typeof(haystack) : SortedRange!TT, TT) && isDefaultPred) | ||
| { | ||
| auto partitions = haystack.trisect(needle); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
trisect does a bit more work than lower/upperBound, could you use one of those instead? Probably lowerBound because you want to find the first occurrence.
std/algorithm/searching.d
Outdated
| // When it is found O(walklength(needle)) steps are performed. | ||
| // 8829 enhancement | ||
| import std.range; | ||
| static if(is(typeof(haystack) == typeof(needle)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is(R1 == R2)
std/algorithm/searching.d
Outdated
| // 8829 enhancement | ||
| import std.range; | ||
| static if(is(typeof(haystack) == typeof(needle)) | ||
| && is(typeof(haystack) : SortedRange!TT, TT) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is(R1 : SortedRange!TT, TT)
std/algorithm/searching.d
Outdated
| auto needleFirstElem = needle[0]; | ||
| auto partitions = haystack.trisect(needleFirstElem); | ||
| auto firstElemLen = partitions[1].length; | ||
| int count = 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
size_t
std/algorithm/searching.d
Outdated
| auto firstElemLen = partitions[1].length; | ||
| int count = 0; | ||
|
|
||
| if(firstElemLen == 0) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Replace most of the code below with a call to mismatch: https://dlang.org/library/std/algorithm/comparison/mismatch.html
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I made all the changes. Hope it's ok now
andralex
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, I think these are the right algorithms to use. Please make a pass for the potential bugs. Thx!
std/algorithm/searching.d
Outdated
| static if (is(InputRange : SortedRange!TT, TT) && isDefaultPred) | ||
| { | ||
| auto lb = haystack.lowerBound(needle); | ||
| if (lb.length == 0 || lb.length == haystack.length || haystack[lb.length] != needle) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do you have lb.length == 0 there? It means there is no element less than the needle in the haystack, so the haystack may actually start with the needle. No?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, that case has eluded me. The condition was for the case when the needle has a value which is smaller then the smallest value in the range. I added an additional condition which rules out the case you mentioned (lb.length == 0 && haystack[0] != needle).
std/algorithm/searching.d
Outdated
|
|
||
| while (needle.front() == needleFirstElem) | ||
| { | ||
| auto elem = needle.front(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do you need elem?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't. I used it in a previous version and forgot about it.
std/algorithm/searching.d
Outdated
|
|
||
| auto m = mismatch(partitions[2], needle); | ||
|
|
||
| if (m[1] == haystack[$ .. $]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if (m[1].empty)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
std/algorithm/searching.d
Outdated
|
|
||
| if (m[1] == haystack[$ .. $]) | ||
| return haystack[partitions[0].length + partitions[1].length - count .. $]; | ||
| if (m[1] != haystack[$ .. $]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if (m[1].empty)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
| ++count; | ||
|
|
||
| if (count > firstElemLen) | ||
| return haystack[$ .. $]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This line is not covered, please add to the unittest
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
…support the raw reading of integer types
…support the raw reading of integer types
…support the raw reading of integer types
| auto lb = haystack.lowerBound(needle); | ||
| if ((lb.length == 0 && haystack[0] != needle) || lb.length == haystack.length | ||
| || haystack[lb.length] != needle) | ||
| return haystack[$ .. $]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Odd alignment - first, there's one character difference which is definitely a problem (all indentation levels should be a multiple of 4). Second, code is (approximately) at the same level as an unrelated expression continuation, which can't be right.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This expression is convoluted:
(lb.length == 0 && haystack[0] != needle) || lb.length == haystack.length
|| haystack[lb.length] != needleSimplified:
(x == 0 && haystack[x] != needle) || x == y || haystack[x] != needleReordered:
x == y || (x == 0 && haystack[x] != needle) || haystack[x] != needleAnd this exposes the redundancy:
x == y || haystack[x] != needleIn fact the more complicated condition had a bug - you're accessing haystack[0] without protection so you'll have a bounds check failure if the haystack is empty.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@wilzbach can you add to the style checker that we detect all indents that are not a multiple of 4?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done. Thanks. Indeed, the code is much cleaner now.
std/algorithm/searching.d
Outdated
|
|
||
| if (m[1].empty) | ||
| return haystack[partitions[0].length + partitions[1].length - count .. $]; | ||
| if (!m[1].empty) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This condition is the complement of the previous one, which if passes will terminate the flow. Remove.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did it because I had some problems in the past with static ifs (the code which followd my block was declared unreachable), but I solved now. Thanks
|
Here are some more algorithms that should be specialized: #3534 The algorithms |
|
This should have been squashed before pulling. |
|
@schuetzm can we do it postmortem? cc @CyberShadow |
Nope rebasing the git history is no option, but maybe we can at least learn from these events? :) |
|
No, we can't. Don't worry about it. Most of the problems of not squishing commits are when some changes are done in one commit and then undone in another, as that creates noise for |
|
OK thank you all! |
|
FYI this uses string comparisons to check whether a range isSorted: static if (is(typeof(pred == "a == b")))
enum isDefaultPred = pred == "a == b";
else
enum isDefaultPred = false;
...
static if (is(InputRange : SortedRange!TT, TT) && isDefaultPred)So:
I opened a bug for using string comparisons and another for propagating sortedness, s.t. it's not forgotten :/ |
|
@wilzbach cool - the better solution is to use overloads that detect "no lambda has been passed" |
Added functionality so that find can take advantage of SortedRange's functions when: