More timsort bugfixes (seems to work much better now)

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@35583 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
Niels Grewe 2012-09-20 18:54:15 +00:00
parent be1f5c5c15
commit 679dc66bbf
2 changed files with 43 additions and 28 deletions

View file

@ -1,3 +1,7 @@
2012-09-20 Niels Grewe <niels.grewe@halbordnung.de>
* Source/GSTimSort.m: A few more timsort bugfixes.
2012-09-20 Niels Grewe <niels.grewe@halbordnung.de> 2012-09-20 Niels Grewe <niels.grewe@halbordnung.de>
* Source/GSTimSort.m: Fix bugs in the timsort implementation. * Source/GSTimSort.m: Fix bugs in the timsort implementation.

View file

@ -234,7 +234,7 @@ gallopLeft(id key, id *buf, NSRange r, NSUInteger hint, id descOrComp,
/* In an ascending order, we gallop to the right until the key /* In an ascending order, we gallop to the right until the key
* is no longer greater than the element from the range * is no longer greater than the element from the range
*/ */
NSInteger maxOffset = r.length - hint; NSInteger maxOffset = (r.length - hint);
while (offset < maxOffset) while (offset < maxOffset)
{ {
if (NSOrderedAscending if (NSOrderedAscending
@ -274,7 +274,6 @@ gallopLeft(id key, id *buf, NSRange r, NSUInteger hint, id descOrComp,
* until the key is no longer less than the element from the range * until the key is no longer less than the element from the range
*/ */
NSInteger maxOffset = hint + 1; NSInteger maxOffset = hint + 1;
while (offset < maxOffset) while (offset < maxOffset)
{ {
if (NSOrderedAscending if (NSOrderedAscending
@ -298,11 +297,16 @@ gallopLeft(id key, id *buf, NSRange r, NSUInteger hint, id descOrComp,
// Restore base address: // Restore base address:
buf -= (hint + r.location); buf -= (hint + r.location);
/* We are now sure that we need to insert key somewhere between offset and /*
* lastOffset. So do a binary search with a vastly diminished search space. * We are now sure that we need to insert key somewhere between offset and
* lastOffset, though the stride might have been to large for the range.
* Fix the range and do a binary search with a vastly diminished search space.
*/ */
offset = MIN(offset, NSMaxRange(r));
lastOffset++; if (lastOffset < (NSInteger)r.location)
{
lastOffset = (NSInteger)r.location;
}
while (lastOffset < offset) while (lastOffset < offset)
{ {
NSInteger midPoint = lastOffset + ((offset - lastOffset) >> 1); NSInteger midPoint = lastOffset + ((offset - lastOffset) >> 1);
@ -363,10 +367,6 @@ gallopRight(id key, id *buf, NSRange r, NSUInteger hint,
{ {
offset = maxOffset; offset = maxOffset;
} }
else if (offset < r.location)
{
offset = r.location;
}
// Translation to positive offsets against the base address. // Translation to positive offsets against the base address.
k = lastOffset; k = lastOffset;
lastOffset = (r.location + hint) - offset; lastOffset = (r.location + hint) - offset;
@ -376,7 +376,7 @@ gallopRight(id key, id *buf, NSRange r, NSUInteger hint,
{ {
// In descending (or equal) order, we gallop to the right // In descending (or equal) order, we gallop to the right
NSInteger maxOffset = r.length - hint; NSInteger maxOffset = (r.length - hint);
while (offset < maxOffset) while (offset < maxOffset)
{ {
if (NSOrderedAscending if (NSOrderedAscending
@ -399,14 +399,21 @@ gallopRight(id key, id *buf, NSRange r, NSUInteger hint,
// Restore base address: // Restore base address:
buf -= (hint + r.location); buf -= (hint + r.location);
/* We are now sure that we need to insert key somewhere between offset and /*
* lastOffset. So do a binary search with a vastly diminished search space. * We are now sure that we need to insert key somewhere between offset and
* lastOffset, though the stride might have been to large for the range.
* Fix the range and do a binary search with a vastly diminished search space.
*/ */
lastOffset++; lastOffset++;
offset = MIN(offset, NSMaxRange(r));
if (lastOffset < (NSInteger)r.location)
{
lastOffset = (NSInteger)r.location;
}
while (lastOffset < offset) while (lastOffset < offset)
{ {
NSInteger midPoint = lastOffset + ((offset - lastOffset) >> 1); NSInteger midPoint = lastOffset + ((offset - lastOffset) >> 1);
if (NSOrderedAscending if (NSOrderedAscending
== GSCompareUsingDescriptorOrComparator(key, buf[midPoint], == GSCompareUsingDescriptorOrComparator(key, buf[midPoint],
descOrComp, type, context)) descOrComp, type, context))
@ -606,7 +613,7 @@ descriptorOrComparator: (id)descriptorOrComparator
{ {
runStack[stackSize] = r; runStack[stackSize] = r;
stackSize++; stackSize++;
NSDebugMLLog(@"GSTimSort", @"Pushing run: %@\n", NSStringFromRange(r)); NSDebugMLLog(@"GSTimSort", @"Pushing run: %@", NSStringFromRange(r));
} }
- (void) suggestMerge - (void) suggestMerge
@ -632,11 +639,15 @@ descriptorOrComparator: (id)descriptorOrComparator
{ {
GS_TIMSORT_MERGE_AT_INDEX(self, n); GS_TIMSORT_MERGE_AT_INDEX(self, n);
} }
else
{
break;
}
} }
else else
{ {
break; break;
} }
} }
} }
@ -1015,7 +1026,7 @@ descriptorOrComparator: (id)descriptorOrComparator
r1 = runStack[i]; r1 = runStack[i];
r2 = runStack[i+1]; r2 = runStack[i+1];
NSDebugMLLog(@"GSTimSort", @"Merging from stack location %lu of %lu (%@ with %@)\n", i, NSDebugMLLog(@"GSTimSort", @"Merging stack location %lu (stack size: %lu, run %@ with %@)", i,
stackSize, NSStringFromRange(r1), NSStringFromRange(r2)); stackSize, NSStringFromRange(r1), NSStringFromRange(r2));
/* Do some housekeeping on the stack: We combine the two runs /* Do some housekeeping on the stack: We combine the two runs
@ -1036,19 +1047,19 @@ descriptorOrComparator: (id)descriptorOrComparator
sortDescriptorOrComparator, comparisonType, functionContext); sortDescriptorOrComparator, comparisonType, functionContext);
r1.length = r1.length - (insert - r1.location); r1.length = r1.length - (insert - r1.location);
r1.location = insert; r1.location = insert;
NSDebugMLLog(@"GSTimSort", @"Insertion point for r2 in r1: %lu.\nr1 for the merge is now %@.\n",
insert, NSStringFromRange(r1));
if (r1.length == 0) if (r1.length == 0)
{ {
// The entire run r2 lies after r1, just return. // The entire run r2 lies after r1, just return.
return; return;
} }
NSDebugMLLog(@"GSTimSort", @"Insertion point for r2 in r1: %lu, r1 for the merge is now %@.",
insert, NSStringFromRange(r1));
// Find an insertion point for the last element of r1 into r2. Subtracting the // Find an insertion point for the last element of r1 into r2. Subtracting the
// location from that point gives us the length of the subrange we need to // location from that point gives us the length of the subrange we need to
// merge. // merge.
r2.length = (gallopLeft(objects[NSMaxRange(r1) - 1], objects, r2, r2.length = (gallopLeft(objects[NSMaxRange(r1) - 1], objects, r2,
(r2.length - 1), (r2.length - 2),
sortDescriptorOrComparator, comparisonType, functionContext) sortDescriptorOrComparator, comparisonType, functionContext)
- r2.location); - r2.location);
if (r2.length == 0) if (r2.length == 0)
@ -1131,7 +1142,7 @@ _GSTimSort(id *objects,
/* If the run is too short, coerce it up to minimalRunLen /* If the run is too short, coerce it up to minimalRunLen
* or the end of the sortRange. * or the end of the sortRange.
*/ */
if (runLen < MAX(sortLen, minimalRunLen)) if (runLen < MIN(sortLen, minimalRunLen))
{ {
NSUInteger coercionLen; NSUInteger coercionLen;