mirror of
https://github.com/gnustep/libs-base.git
synced 2025-04-22 16:33:29 +00:00
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:
parent
be0ddb7458
commit
8accb5f56c
2 changed files with 163 additions and 160 deletions
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Loading…
Reference in a new issue