std.container.RedBlackTree versus C++ std::set
monarch_dodra
monarchdodra at gmail.com
Fri Feb 15 09:11:55 PST 2013
On Thursday, 14 February 2013 at 20:33:21 UTC, Ivan Kazmenko
wrote:
> Rob T wrote:
>> When I look at the std.container source code, it seems that
>> the payload element is passed by value multiple times
>> unnecessarily, so to minimize copy construction you'll have to
>> implement element as a class and implement a dup function for
>> it.
>
> Thank you all for assistance, I've finally pinned it down!
> It's the default magic "a < b" that devours the most copies of
> my precious structs! Once I change the declaration:
>
> -----
> alias RedBlackTree !(element) container;
> -----
>
> to
>
> -----
> bool lessfun (ref element a, ref element b)
> {
> return a < b;
> }
>
> alias RedBlackTree !(element, lessfun) container;
> -----
>
> ... I get only exactly 3 * LIMIT postblit constructor calls,
> which is 300,000 instead of 11,389,556. While I still want to
> find where the excess 200,000 calls originate from, this is
> definitely asymptotically better than before: O (n) versus O (n
> log n) calls. And it is now less of a bottleneck in my
> original program.
>
> This raises the question to the default behavior of
> std.functional.binaryFun. Sure, for integers, class references
> and small types, the current way is the best. On the other
> hand, for large structs and maybe some other complex objects
> that obey value semantics, it seems it would be beneficial to,
> given a string like "a < b", produce a function taking
> arguments by reference and not by value. Maybe there is some
> simple criterion (size of type greater than size_t - seems bad?
> type is a struct - better?) which can be used with static if to
> generate "(ref a, ref b)" instead of "(a, b)" version by
> default. Of course, all that could only work if there is a
> more detailed hierarchy of binary functions, at least a
> binaryFunConst taking const arguments.
>
> -----
> Ivan Kazmenko.
Also keep in mind that "a < b" is implemented as two calls to
"a.opCmp(b)", and "a.opCmp(b)" is itself usually implemented as
two calls to "something < something else" (!)
as convenient as opCmp is for the implementation implementation,
it is not always the best in terms of raw power.
If you have can write a straight up less(S1, S2) function, such
as "a.i < b.i", then using that can buy you a hefty amount of
time.
More information about the Digitalmars-d-learn
mailing list