Sort algorithms should always be built, and be selectable at runtime

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@39998 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
Richard Frith-MacDonald 2016-07-15 11:30:07 +00:00
parent f56e1bdd0c
commit 39cc09e2ca
12 changed files with 100 additions and 108 deletions

View file

@ -35,7 +35,6 @@
* Sorts the provided object array's sortRange according to sortDescriptor.
*/
// Quicksort algorithm copied from Wikipedia :-).
#if GS_USE_QUICKSORT
static inline void
SwapObjects(id * o1, id * o2)
@ -84,12 +83,12 @@ _GSQuickSort(id *objects,
}
@interface GSQuickSortPlaceHolder : NSObject
+ (void) setUnstable;
@end
@implementation GSQuickSortPlaceHolder
+ (void) load
+ (void) setUnstable
{
_GSSortUnstable = _GSQuickSort;
}
@end
#endif

View file

@ -30,7 +30,6 @@
#import "Foundation/NSObjCRuntime.h"
#import "GSSorting.h"
#if GS_USE_SHELLSORT
void
_GSShellSort(id *objects,
NSRange sortRange,
@ -114,13 +113,13 @@ _GSShellSort(id *objects,
@interface GSShellSortPlaceHolder : NSObject
+ (void) setUnstable;
@end
@implementation GSShellSortPlaceHolder
+ (void) load
+ (void) setUnstable
{
_GSSortUnstable = _GSShellSort;
}
@end
#endif

View file

@ -30,7 +30,7 @@
enum
{
GSComparisonTypeSortDescriptor = 0, /** Comparison using an NSSortDescriptor */
GSComparisonTypeSortDescriptor = 0, /** Comparison using NSSortDescriptor */
GSComparisonTypeComparatorBlock, /** Comparison using an NSComparator */
GSComparisonTypeFunction, /** Comparison using a comparison function of type
* NSInteger(*)(id,id,void*) */
@ -130,7 +130,7 @@ GSRightInsertionPointForKeyInSortedRange(id key, id *buffer,
* This function is provided using the implementation of the timsort algorithm.
*/
NSUInteger
GSLeftInsertionPointForKeyInSortedRange(id key, id* buffer,
GSLeftInsertionPointForKeyInSortedRange(id key, id *buffer,
NSRange range, NSComparator comparator);
/**
@ -139,7 +139,7 @@ GSLeftInsertionPointForKeyInSortedRange(id key, id* buffer,
*/
static inline NSComparisonResult
GSCompareUsingDescriptorOrComparator(id first, id second, id descOrComp,
GSComparisonType cmprType, void* context)
GSComparisonType cmprType, void *context)
{
switch (cmprType)

View file

@ -295,8 +295,6 @@ NSRange range, NSComparator cmptr)
GSComparisonTypeComparatorBlock, NULL);
}
#if GS_USE_TIMSORT
static inline void
reverseRange(id *buffer, NSRange r)
{
@ -476,7 +474,7 @@ static IMP mergeLowImp;
static IMP mergeHighImp;
static IMP ensureCapImp;
@interface GSTimSortDescriptor : NSObject
@interface GSTimSortPlaceHolder : NSObject
{
id *objects;
NSRange sortRange;
@ -511,7 +509,7 @@ _GSTimSort(id *objects,
GSComparisonType comparisonType,
void *context);
@implementation GSTimSortDescriptor
@implementation GSTimSortPlaceHolder
+ (void) load
{
_GSSortStable = _GSTimSort;
@ -519,7 +517,7 @@ _GSTimSort(id *objects,
+ (void) initialize
{
if ([GSTimSortDescriptor class] == [self class])
if ([GSTimSortPlaceHolder class] == [self class])
{
// We need to be fast, so we cache a lot of IMPs
pushRunImp =
@ -539,6 +537,11 @@ _GSTimSort(id *objects,
}
}
+ (void) setUnstable
{
_GSSortUnstable = _GSTimSort; // Use for unstable even though we are stable
}
- (id) initWithObjects: (id*)theObjects
sortRange: (NSRange)theSortRange
descriptorOrComparator: (id)descriptorOrComparator
@ -552,7 +555,7 @@ descriptorOrComparator: (id)descriptorOrComparator
{
return nil;
}
/* GSTimSortDescriptors are ephemeral objects that just track state, so we
/* GSTimSortPlaceHolders are ephemeral objects that just track state, so we
* don't bother making sure that the objects don't go away.
*/
objects = theObjects;
@ -1107,7 +1110,7 @@ _GSTimSort(id *objects,
NSUInteger sortEnd = NSMaxRange(sortRange);
NSUInteger sortLen = sortRange.length;
NSUInteger minimalRunLen = 0;
GSTimSortDescriptor *desc = nil;
GSTimSortPlaceHolder *desc = nil;
if (sortLen < 2)
{
// Don't sort anything that doesn't contain at least two elements.
@ -1116,16 +1119,17 @@ _GSTimSort(id *objects,
if (sortLen < GS_MIN_MERGE)
{
miniTimSort(objects, sortRange, sortDescriptorOrComparator, comparisonType, context);
miniTimSort(objects, sortRange,
sortDescriptorOrComparator, comparisonType, context);
return;
}
// Now we need a timsort descriptor for state-tracking.
desc = [[GSTimSortDescriptor alloc] initWithObjects: objects
sortRange: sortRange
descriptorOrComparator: sortDescriptorOrComparator
comparisonType: comparisonType
functionContext: context];
desc = [[GSTimSortPlaceHolder alloc] initWithObjects: objects
sortRange: sortRange
descriptorOrComparator: sortDescriptorOrComparator
comparisonType: comparisonType
functionContext: context];
NS_DURING
{
@ -1172,4 +1176,3 @@ _GSTimSort(id *objects,
[desc release];
}
#endif

View file

@ -30,6 +30,8 @@
#import "Foundation/NSCoder.h"
#import "Foundation/NSException.h"
#import "Foundation/NSKeyValueCoding.h"
#import "Foundation/NSNotification.h"
#import "Foundation/NSUserDefaults.h"
#import "GNUstepBase/GSObjCRuntime.h"
#import "GSPrivate.h"
@ -41,34 +43,61 @@ static BOOL initialized = NO;
#pragma clang diagnostic ignored "-Wreceiver-forward-class"
#endif
#if GS_USE_TIMSORT
@interface GSTimSortDescriptor : NSObject
@interface GSTimSortPlaceHolder : NSObject
+ (void) setUnstable;
@end
#endif
#if GS_USE_QUICKSORT
@interface GSQuickSortPlaceHolder : NSObject
+ (void) setUnstable;
@end
#endif
#if GS_USE_SHELLSORT
@interface GSShellSortPlaceHolder : NSObject
+ (void) setUnstable;
@end
#endif
@implementation NSSortDescriptor
+ (void) defaultsChanged: (NSNotification*)n
{
NSUserDefaults *defs = (NSUserDefaults*)[n object];
NSString *algorithm;
algorithm = [defs stringForKey: @"GSSortAlgorithm"];
if ([algorithm isEqual: @"QuickSort"])
{
[GSQuickSortPlaceHolder setUnstable];
}
else if ([algorithm isEqual: @"ShellSort"])
{
[GSShellSortPlaceHolder setUnstable];
}
else if ([algorithm isEqual: @"TimSort"])
{
[GSTimSortPlaceHolder setUnstable];
}
else
{
[GSTimSortPlaceHolder setUnstable];
if (nil != algorithm)
{
NSLog(@"GSSortAlgorithm default unknown value (%@)", algorithm);
}
}
}
+ (void) initialize
{
if (NO == initialized)
{
#if GS_USE_TIMSORT
[GSTimSortDescriptor class];
#endif
#if GS_USE_QUICKSORT
[GSQuickSortPlaceHolder class];
#endif
#if GS_USE_SHELLSORT
[GSShellSortPlaceHolder class];
#endif
NSNotificationCenter *nc;
NSUserDefaults *defs;
[GSTimSortPlaceHolder class]; // default stable sort
nc = [NSNotificationCenter defaultCenter];
defs = [NSUserDefaults standardUserDefaults];
[nc addObserver: self
selector: @selector(defaultsChanged:)
name: NSUserDefaultsDidChangeNotification
object: defs];
[self defaultsChanged: nil]; // set unstable sort
initialized = YES;
}
}