Backport NSSortDescriptor fixes.

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/branches/base-1_13_0@24102 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
Richard Frith-MacDonald 2006-11-15 17:44:21 +00:00
parent be0ddb7458
commit 8accb5f56c
2 changed files with 163 additions and 160 deletions

View file

@ -9,6 +9,7 @@
* Source/Additions/GSMime.m:
* Source/NSConnection.m:
* Source/NSIndexSet.m:
* Source/NSSortDescriptor.m:
* Tools/AGSHtml.m:
* Tools/autogsdoc.m:
Backport bugfixes from trunk

View file

@ -30,15 +30,87 @@
#include "Foundation/NSKeyValueCoding.h"
#include "Foundation/NSString.h"
#include "GNUstepBase/GSObjCRuntime.h"
#include "GSPrivate.h"
@implementation NSSortDescriptor
- (BOOL) ascending
{
return _ascending;
}
- (NSComparisonResult) compareObject: (id) object1 toObject: (id) object2
{
NSComparisonResult result;
id comparedKey1 = [object1 valueForKeyPath: _key];
id comparedKey2 = [object2 valueForKeyPath: _key];
result = (NSComparisonResult) [comparedKey1 performSelector: _selector
withObject: comparedKey2];
if (_ascending == NO)
{
if (result == NSOrderedAscending)
{
result = NSOrderedDescending;
}
else if (result == NSOrderedDescending)
{
result = NSOrderedAscending;
}
}
return result;
}
- (id) copyWithZone: (NSZone*)zone
{
if (NSShouldRetainWithZone(self, zone))
{
return RETAIN(self);
}
return [[NSSortDescriptor allocWithZone: zone]
initWithKey: _key ascending: _ascending selector: _selector];
}
- (void) dealloc
{
TEST_RELEASE(_key);
[super dealloc];
}
/* Hash function to hash up to limit bytes from data of specified length.
* If the flag is NO then a result of 0 is mapped to 0xffffffff.
* This is a pretty useful general purpose hash function.
*/
static inline unsigned
GSPrivateHash(const void *data, unsigned length, unsigned limit, BOOL zero)
{
unsigned ret = length;
unsigned l = length;
if (limit < length)
{
l = limit;
}
while (l-- > 0)
{
ret = (ret << 5) + ret + ((const unsigned char*)data)[l];
}
if (ret == 0 && zero == NO)
{
ret = 0xffffffff;
}
return ret;
}
- (unsigned) hash
{
const char *sel = GSNameFromSelector(_selector);
return _ascending + GSPrivateHash(sel, strlen(sel), 16, YES) + [_key hash];
}
- (id) initWithKey: (NSString *) key ascending: (BOOL) ascending
{
return [self initWithKey: key ascending: ascending selector: NULL];
@ -73,9 +145,25 @@
}
}
- (BOOL) ascending
- (BOOL) isEqual: (id)other
{
return _ascending;
if (other == self)
{
return YES;
}
if ([other isKindOfClass: [NSSortDescriptor class]] == NO)
{
return NO;
}
if (((NSSortDescriptor*)other)->_ascending != _ascending)
{
return NO;
}
if (!sel_eq(((NSSortDescriptor*)other)->_selector, _selector))
{
return NO;
}
return [((NSSortDescriptor*)other)->_key isEqualToString: _key];
}
- (NSString *) key
@ -83,35 +171,17 @@
return _key;
}
- (id) reversedSortDescriptor
{
return AUTORELEASE([[NSSortDescriptor alloc]
initWithKey: _key ascending: !_ascending selector: _selector]);
}
- (SEL) selector
{
return _selector;
}
- (NSComparisonResult) compareObject: (id) object1 toObject: (id) object2
{
NSComparisonResult result;
id comparedKey1 = [object1 valueForKeyPath: _key],
comparedKey2 = [object2 valueForKeyPath: _key];
result = (NSComparisonResult) [comparedKey1 performSelector: _selector
withObject: comparedKey2];
if (_ascending != YES)
{
result = -result;
}
return result;
}
- (id) reversedSortDescriptor
{
return [[[NSSortDescriptor alloc]
initWithKey: _key ascending: !_ascending selector: _selector]
autorelease];
}
- (void) encodeWithCoder: (NSCoder *) coder
{
if ([coder allowsKeyedCoding])
@ -129,9 +199,9 @@
}
}
- initWithCoder: (NSCoder *) decoder
- (id) initWithCoder: (NSCoder *)decoder
{
if ([super init])
if ((self = [super init]) != nil)
{
if ([decoder allowsKeyedCoding])
{
@ -146,19 +216,8 @@
[decoder decodeValueOfObjCType: @encode(BOOL) at: &_ascending];
[decoder decodeValueOfObjCType: @encode(SEL) at: &_selector];
}
return self;
}
else
{
return nil;
}
}
- (id) copyWithZone: (NSZone*) zone
{
return [[NSSortDescriptor allocWithZone: zone]
initWithKey: _key ascending: _ascending selector: _selector];
return self;
}
@end
@ -179,15 +238,15 @@ SwapObjects(id * o1, id * o2)
*/
// Quicksort algorithm copied from Wikipedia :-).
static void
SortObjectsWithDescriptor(id * objects,
SortObjectsWithDescriptor(id *objects,
NSRange sortRange,
NSSortDescriptor * sortDescriptor)
NSSortDescriptor *sortDescriptor)
{
if (sortRange.length > 1)
{
id pivot = objects[sortRange.location];
unsigned int left = sortRange.location + 1,
right = NSMaxRange(sortRange);
unsigned int left = sortRange.location + 1;
unsigned int right = NSMaxRange(sortRange);
while (left < right)
{
@ -210,139 +269,82 @@ SortObjectsWithDescriptor(id * objects,
}
}
/**
* Finds all objects in the provided range of the objects array that
* are next to each other and evaluate with the provided sortDescriptor
* as being NSOrderedSame, records their ranges in the provided
* recordedRanges array (enlarging it as necessary) and adjusts the
* numRanges argument to indicate the new size of the range array.
* A pointer to the new location of the array of ranges is returned.
*/
static NSRange *
FindEqualityRanges(id * objects,
NSRange searchRange,
NSSortDescriptor * sortDescriptor,
NSRange * ranges,
unsigned int * numRanges)
{
unsigned int i = searchRange.location,
n = NSMaxRange(searchRange);
if (n > 1)
{
while (i < n - 1)
{
unsigned int j;
for (j=i + 1;
j < n &&
[sortDescriptor compareObject: objects[i] toObject: objects[j]]
== NSOrderedSame;
j++);
if (j - i > 1)
{
(*numRanges)++;
ranges = (NSRange *) objc_realloc(ranges, (*numRanges) *
sizeof(NSRange));
ranges[(*numRanges)-1].location = i;
ranges[(*numRanges)-1].length = j - i;
i = j;
}
else
{
i++;
}
}
}
return ranges;
}
@implementation NSArray (NSSortDescriptorSorting)
- (NSArray *) sortedArrayUsingDescriptors: (NSArray *) sortDescriptors
{
NSMutableArray * sortedArray = [NSMutableArray arrayWithArray: self];
NSMutableArray *sortedArray = [NSMutableArray arrayWithArray: self];
[sortedArray sortUsingDescriptors: sortDescriptors];
return [sortedArray makeImmutableCopyOnFail:NO];
return [sortedArray makeImmutableCopyOnFail: NO];
}
@end
/* Sort the objects in range using the first descriptor and, if there
* are more descriptors, recursively call the function to sort each range
* of adhacent equal objects using the remaining descriptors.
*/
static void
SortRange(id *objects, NSRange range, id *descriptors,
unsigned numDescriptors)
{
NSSortDescriptor *sd = (NSSortDescriptor*)descriptors[0];
SortObjectsWithDescriptor(objects, range, sd);
if (numDescriptors > 1)
{
unsigned start = range.location;
unsigned finish = NSMaxRange(range);
while (start < finish)
{
unsigned pos = start + 1;
/* Find next range of adjacent objects.
*/
while (pos < finish
&& [sd compareObject: objects[start]
toObject: objects[pos]] == NSOrderedSame)
{
pos++;
}
/* Sort the range using remaining descriptors.
*/
if (pos - start > 1)
{
SortRange(objects, NSMakeRange(start, pos - start),
descriptors + 1, numDescriptors - 1);
}
start = pos;
}
}
}
@implementation NSMutableArray (NSSortDescriptorSorting)
/**
* This method works like this: first, it sorts the entire
* contents of the array using the first sort descriptor. Then,
* after each sort-run, it looks whether there are sort
* descriptors left to process, and if yes, looks at the partially
* sorted array, finds all portions in it which are equal
* (evaluate to NSOrderedSame) and applies the following
* descriptor onto them. It repeats this either until all
* descriptors have been applied or there are no more equal
* portions (equality ranges) left in the array.
*/
- (void) sortUsingDescriptors: (NSArray *) sortDescriptors
- (void) sortUsingDescriptors: (NSArray *)sortDescriptors
{
id * objects;
unsigned int count;
unsigned count = [self count];
unsigned numDescriptors = [sortDescriptors count];
NSRange * equalityRanges;
unsigned int numEqualityRanges;
unsigned int i, n;
count = [self count];
objects = (id *) objc_calloc(count, sizeof(id));
[self getObjects: objects];
equalityRanges = (NSRange *) objc_calloc(1, sizeof(NSRange));
equalityRanges[0].location = 0;
equalityRanges[0].length = count;
numEqualityRanges = 1;
for (i=0, n = [sortDescriptors count]; i < n && equalityRanges != NULL; i++)
if (count > 1 && numDescriptors > 0)
{
unsigned int j;
NSSortDescriptor * sortDescriptor = [sortDescriptors objectAtIndex: i];
id descriptors[numDescriptors];
GS_BEGINIDBUF(objects, count);
NSArray *a;
// pass through all equality ranges and sort each of them
for (j=0; j < numEqualityRanges; j++)
{
SortObjectsWithDescriptor(objects, equalityRanges[j],
sortDescriptor);
}
// then, if there are sort descriptors left to process
if (i < n - 1)
// reconstruct the equality ranges anew.
{
NSRange * newRanges = NULL;
unsigned newNumRanges = 0;
// process only contents of old equality ranges
for (j=0; j < numEqualityRanges; j++)
{
newRanges = FindEqualityRanges(objects, equalityRanges[j],
sortDescriptor, newRanges, &newNumRanges);
}
objc_free(equalityRanges);
equalityRanges = newRanges;
numEqualityRanges = newNumRanges;
}
[self getObjects: objects];
[sortDescriptors getObjects: descriptors];
SortRange(objects, NSMakeRange(0, count), descriptors, numDescriptors);
a = [[NSArray alloc] initWithObjects: objects count: count];
[self setArray: a];
RELEASE(a);
GS_ENDIDBUF();
}
objc_free(equalityRanges);
// now, reconstruct our contents according to the sorted object buffer
[self setArray: [NSArray arrayWithObjects: objects count: count]];
objc_free(objects);
}
@end