Skip to content

Commit 04158ca

Browse files
committed
Fix performance issues and bugs in TTree
1 parent 526ddb4 commit 04158ca

File tree

1 file changed

+73
-5
lines changed

1 file changed

+73
-5
lines changed

src/containers/ttree.d

Lines changed: 73 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,8 @@ struct TTree(T, bool allowDuplicates = false, alias less = "a < b",
9797
return retVal;
9898
}
9999

100+
alias put = insert;
101+
100102
/**
101103
* Removes a value from the tree.
102104
* Params:
@@ -233,27 +235,72 @@ struct TTree(T, bool allowDuplicates = false, alias less = "a < b",
233235
current = current.left;
234236
}
235237

238+
void currentToLeastContaining(inout T val)
239+
{
240+
if (current is null)
241+
return;
242+
while (current !is null)
243+
{
244+
assert(current.registry != 0);
245+
auto first = current.values[0];
246+
auto last = current.values[current.nextAvailableIndex - 1];
247+
immutable bool valLessFirst = _less(val, first);
248+
immutable bool valLessLast = _less(val, last);
249+
immutable bool firstLessVal = _less(first, val);
250+
immutable bool lastLessVal = _less(last, val);
251+
if (firstLessVal && valLessLast)
252+
return;
253+
else if (valLessFirst)
254+
current = current.left;
255+
else if (lastLessVal)
256+
current = current.right;
257+
else
258+
{
259+
static if (allowDuplicates)
260+
{
261+
if (!valLessFirst && !firstLessVal)
262+
{
263+
auto c = current;
264+
current = current.left;
265+
currentToLeastContaining(val);
266+
if (current is null)
267+
current = c;
268+
return;
269+
}
270+
else
271+
return;
272+
}
273+
else
274+
return;
275+
}
276+
277+
}
278+
}
279+
236280
this(inout(Node)* n, RangeType type, inout T val)
237281
{
238282
current = n;
239283
this.type = type;
240284
this.val = val;
241-
currentToLeftmost();
242285
with (RangeType) final switch(type)
243286
{
244287
case all:
288+
currentToLeftmost();
245289
break;
246290
case lower:
291+
currentToLeftmost();
247292
if (_less(val, front()))
248293
current = null;
249294
break;
250295
case equal:
296+
currentToLeastContaining(val);
251297
while (current !is null && _less(front(), val))
252298
_popFront();
253299
if (current is null || _less(front(), val) || _less(val, front()))
254300
current = null;
255301
break;
256302
case upper:
303+
currentToLeastContaining(val);
257304
while (current !is null && !_less(val, front()))
258305
_popFront();
259306
break;
@@ -798,7 +845,7 @@ private:
798845
unittest
799846
{
800847
import core.memory : GC;
801-
import std.algorithm : equal, sort, map, filter;
848+
import std.algorithm : equal, sort, map, filter, each;
802849
import std.array : array;
803850
import std.range : iota, walkLength, isInputRange;
804851
import std.string : format;
@@ -905,9 +952,10 @@ unittest
905952
assert (strings.insert("d"));
906953
assert (strings.insert("d"));
907954
assert (strings.length == 5);
908-
assert (equal(strings.equalRange("d"), ["d", "d"]));
909-
assert (equal(strings.lowerBound("d"), ["a", "b", "c"]));
910-
assert (equal(strings.upperBound("c"), ["d", "d"]));
955+
assert (equal(strings.equalRange("d"), ["d", "d"]), format("%s", strings.equalRange("d")));
956+
assert (equal(strings.equalRange("a"), ["a"]), format("%s", strings.equalRange("a")));
957+
assert (equal(strings.lowerBound("d"), ["a", "b", "c"]), format("%s", strings.lowerBound("d")));
958+
assert (equal(strings.upperBound("c"), ["d", "d"]), format("%s", strings.upperBound("c")));
911959
}
912960

913961
{
@@ -1026,4 +1074,24 @@ unittest
10261074
assert(tree.equalRange(ABC(15)).walkLength() == 4,
10271075
format("Actual length = %d", tree.equalRange(ABC(15)).walkLength()));
10281076
}
1077+
1078+
{
1079+
TTree!int ints2;
1080+
iota(0, 1_000_000).each!(a => ints2.insert(a));
1081+
assert(equal(iota(0, 1_000_000), ints2[]));
1082+
assert(ints2.length == 1_000_000);
1083+
foreach (i; 0 .. 1_000_000)
1084+
assert(!ints2.equalRange(i).empty, format("Could not find %d", i));
1085+
}
1086+
1087+
{
1088+
TTree!int ints3;
1089+
foreach (i; iota(0, 1_000_000).filter!(a => a % 2 == 0))
1090+
ints3.insert(i);
1091+
assert(ints3.length == 500_000);
1092+
foreach (i; iota(0, 1_000_000).filter!(a => a % 2 == 0))
1093+
assert(!ints3.equalRange(i).empty);
1094+
foreach (i; iota(0, 1_000_000).filter!(a => a % 2 == 1))
1095+
assert(ints3.equalRange(i).empty);
1096+
}
10291097
}

0 commit comments

Comments
 (0)