Issue 8829 - std.algorithm.find fails to take advantage of SortedRange#4907
Issue 8829 - std.algorithm.find fails to take advantage of SortedRange#4907andralex merged 12 commits intodlang:masterfrom
Conversation
andralex
left a comment
There was a problem hiding this comment.
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.
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.
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.
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)) |
std/algorithm/searching.d
Outdated
| // 8829 enhancement | ||
| import std.range; | ||
| static if(is(typeof(haystack) == typeof(needle)) | ||
| && is(typeof(haystack) : 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; |
std/algorithm/searching.d
Outdated
| auto firstElemLen = partitions[1].length; | ||
| int count = 0; | ||
|
|
||
| if(firstElemLen == 0) |
There was a problem hiding this comment.
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.
I made all the changes. Hope it's ok now
andralex
left a comment
There was a problem hiding this comment.
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.
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.
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.
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[$ .. $]) |
std/algorithm/searching.d
Outdated
|
|
||
| if (m[1] == haystack[$ .. $]) | ||
| return haystack[partitions[0].length + partitions[1].length - count .. $]; | ||
| if (m[1] != haystack[$ .. $]) |
| ++count; | ||
|
|
||
| if (count > firstElemLen) | ||
| return haystack[$ .. $]; |
There was a problem hiding this comment.
This line is not covered, please add to the unittest
…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.
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.
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.
@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.
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.
This condition is the complement of the previous one, which if passes will terminate the flow. Remove.
There was a problem hiding this comment.
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: