-
-
Notifications
You must be signed in to change notification settings - Fork 705
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
RedBlackTree excessively copies structs by value #9598
Labels
Comments
bearophile_hugs commented on 2013-02-14T15:17:57ZThe second program gives me:
temp.d(28): Error: template instance RedBlackTree!(element, lessfun) RedBlackTree!(element, lessfun) does not match template declaration RedBlackTree(T, alias less = "a < b", bool allowDuplicates = false) if (is(typeof(binaryFun!(less)(T.init, T.init)))) |
gassa commented on 2013-02-14T15:26:07ZOriginal forum discussion thread:
http://forum.dlang.org/thread/qhlsrpqajuwstvlspimf@forum.dlang.org
First, being fixable from user side, this is not that big of an issue. However, it is counter-intuitive that we should use a custom but still rather idiomatic comparison function (lessfun in the modified example) to have asymptotically fewer copy operations: O(1) versus O(log(n)) per insertion.
As for the proposed solution, I don't have an obviously right one at hand. Still, below are a few attempts to guess what could possibly be done.
As I see it, the problem is in counter-intuitive behavior of the default "a < b" predicate. One approach is changing that behavior to accept arguments by reference and not by value. Such a change will perhaps break too much working code, and worse, it will actually reduce performance in case of integers and class references and the like.
A better idea would be to change "a < b" only for structs, but then again, there are small structs with no postblit constructor, and all they get from such change is an extra indirection.
A more conservative approach would be to fix stuff only for the RedBlackTree container by specifying a custom version of the default instead of "a < b".
And if everything fails, at least there should be a visible note in the documentation on how to properly use RedBlackTree with large structs. |
gassa commented on 2013-02-14T16:21:09Z(In reply to comment #1)
> The second program gives me:
>
> temp.d(28): Error: template instance RedBlackTree!(element, lessfun)
> RedBlackTree!(element, lessfun) does not match template declaration
> RedBlackTree(T, alias less = "a < b", bool allowDuplicates = false) if
> (is(typeof(binaryFun!(less)(T.init, T.init))))
Hmm, I just tried with the current release, DMD 2.061, and it gives me the same error. However, DMD 2.059 works with no complaint.
The problem arises from the constraint in RedBlackTree declaration:
-----
final class RedBlackTree(T, alias less = "a < b", bool allowDuplicates = false)
if(is(typeof(binaryFun!less(T.init, T.init))))
-----
The function taking ref arguments can not work for T.init and T.init since ref implies lvalue.
Currently, I found two work-arounds, more or less clumsy.
The first one is to define the second function to avoid the check:
-----
// old one
bool lessfun (ref element a, ref element b)
{
return a < b;
}
// new one
bool lessfun (element a, element b)
{
return a < b;
}
-----
Obviously, this way, we need four identical functions to cover all possible cases.
The second one is to use template and auto ref:
-----
bool lessfun (T) (auto ref T a, auto ref T b)
{
return a < b;
}
-----
This works fine. And this could be a suitable solution for the original problem. That is, implementing "a < b" in a similar way as the default predicate for the RedBlackTree!(AnyStructType) container may be not that bad. But that makes me wonder: under the hood, does it still create the four identical functions? |
gassa commented on 2013-02-14T17:04:46ZCreated attachment 1186
Example with excessive copying |
gassa commented on 2013-02-14T17:05:27ZCreated attachment 1187
Solution 1: two redundant functions |
gassa commented on 2013-02-14T17:06:11ZCreated attachment 1188
Solution 2: template with auto ref |
schveiguy (@schveiguy) commented on 2013-02-15T06:58:45Z(In reply to comment #3)
> (In reply to comment #1)
> > The second program gives me:
> >
> > temp.d(28): Error: template instance RedBlackTree!(element, lessfun)
> > RedBlackTree!(element, lessfun) does not match template declaration
> > RedBlackTree(T, alias less = "a < b", bool allowDuplicates = false) if
> > (is(typeof(binaryFun!(less)(T.init, T.init))))
>
> The function taking ref arguments can not work for T.init and T.init since ref
> implies lvalue.
Yes, this was recently more strictly enforced. However, the function will only ever be called on lvalues inside the class
We should change the if statement to something like this:
if(is(typeof({T t; bool x = binaryFun!less(t, t);})))
That should fix the issue. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
gassa (@GassaFM) reported this on 2013-02-14T15:06:12Z
Transfered from https://issues.dlang.org/show_bug.cgi?id=9513
CC List
Description
!!!There are attachements in the bugzilla issue that have not been copied over!!!
The text was updated successfully, but these errors were encountered: