mirror of
https://github.com/gnustep/libs-base.git
synced 2025-04-23 09:04:13 +00:00
hash tidyups and rewrite of array sorting for better performance.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@23967 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
f03d22e63f
commit
e26157d901
11 changed files with 180 additions and 173 deletions
15
ChangeLog
15
ChangeLog
|
@ -1,3 +1,18 @@
|
|||
2006-10-26 Richard Frith-Macdonald <rfm@gnu.org>
|
||||
|
||||
* Source/NSPropertyList.m: use declaration of GSArray from GSPrivate.h
|
||||
* Source/GSArray.m: ditto
|
||||
* Source/NSArray.m: ditto
|
||||
* Source/NSSerializer.m ditto
|
||||
* Source/NSConcreteNumberTemplate.m: Use private function to get hash.
|
||||
* Source/NSConcreteNumber.m: ditto
|
||||
* Source/NSNumber.m: ditto
|
||||
* Source/GSPrivate.h: Add hash functions.
|
||||
* Headers/Foundation/NSSortDescriptor.h: Add a little documentation.
|
||||
* Source/NSSortDescriptor.m: Implement better hash/isEqual as
|
||||
suggested by David. Complete rewrite of sorting to avoid lots of
|
||||
heap memory operations ... should be much much faster.
|
||||
|
||||
2006-10-25 Richard Frith-Macdonald <rfm@gnu.org>
|
||||
|
||||
* configure.ac: Define HAVE_VISIBILITY_ATTRIBUTE if gcc's visibility
|
||||
|
|
|
@ -63,6 +63,17 @@ extern "C" {
|
|||
|
||||
@interface 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;
|
||||
|
||||
@end
|
||||
|
|
|
@ -36,6 +36,8 @@
|
|||
// For private method _decodeArrayOfObjectsForKey:
|
||||
#include "Foundation/NSKeyedArchiver.h"
|
||||
|
||||
#include "GSPrivate.h"
|
||||
|
||||
static SEL eqSel;
|
||||
static SEL oaiSel;
|
||||
|
||||
|
@ -54,39 +56,10 @@ static Class GSInlineArrayClass;
|
|||
@interface GSArrayEnumeratorReverse : GSArrayEnumerator
|
||||
@end
|
||||
|
||||
|
||||
@interface GSArray : NSArray
|
||||
{
|
||||
@public
|
||||
id *_contents_array;
|
||||
unsigned _count;
|
||||
}
|
||||
@end
|
||||
|
||||
@interface GSInlineArray : GSArray
|
||||
{
|
||||
}
|
||||
@end
|
||||
|
||||
@interface GSMutableArray : NSMutableArray
|
||||
{
|
||||
@public
|
||||
id *_contents_array;
|
||||
unsigned _count;
|
||||
unsigned _capacity;
|
||||
int _grow_factor;
|
||||
}
|
||||
@end
|
||||
|
||||
@interface GSMutableArray (GSArrayBehavior)
|
||||
- (void) _raiseRangeExceptionWithIndex: (unsigned)index from: (SEL)sel;
|
||||
@end
|
||||
|
||||
@interface GSPlaceholderArray : NSArray
|
||||
{
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation GSArray
|
||||
|
||||
- (void) _raiseRangeExceptionWithIndex: (unsigned)index from: (SEL)sel
|
||||
|
|
|
@ -48,6 +48,38 @@
|
|||
|
||||
|
||||
#include "GNUstepBase/GSObjCRuntime.h"
|
||||
|
||||
#include "Foundation/NSArray.h"
|
||||
|
||||
|
||||
@interface GSArray : NSArray
|
||||
{
|
||||
@public
|
||||
id *_contents_array;
|
||||
unsigned _count;
|
||||
}
|
||||
@end
|
||||
|
||||
@interface GSMutableArray : NSMutableArray
|
||||
{
|
||||
@public
|
||||
id *_contents_array;
|
||||
unsigned _count;
|
||||
unsigned _capacity;
|
||||
int _grow_factor;
|
||||
}
|
||||
@end
|
||||
|
||||
@interface GSInlineArray : GSArray
|
||||
{
|
||||
}
|
||||
@end
|
||||
|
||||
@interface GSPlaceholderArray : NSArray
|
||||
{
|
||||
}
|
||||
@end
|
||||
|
||||
#include "Foundation/NSString.h"
|
||||
|
||||
/**
|
||||
|
@ -285,6 +317,34 @@ GSPrivateIsByteEncoding(NSStringEncoding encoding) GS_ATTRIB_PRIVATE;
|
|||
BOOL
|
||||
GSPrivateIsEncodingSupported(NSStringEncoding encoding) GS_ATTRIB_PRIVATE;
|
||||
|
||||
/* 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)
|
||||
__attribute__((unused));
|
||||
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;
|
||||
}
|
||||
|
||||
/* load a module into the runtime
|
||||
*/
|
||||
long
|
||||
|
@ -307,6 +367,11 @@ void GSPrivateNotifyIdle(void) GS_ATTRIB_PRIVATE;
|
|||
*/
|
||||
BOOL GSPrivateNotifyMore(void) GS_ATTRIB_PRIVATE;
|
||||
|
||||
/* Function to return the hash value for a small integer (used by NSNumber).
|
||||
*/
|
||||
unsigned
|
||||
GSPrivateSmallHash(int n) GS_ATTRIB_PRIVATE;
|
||||
|
||||
/* Function to append data to an GSStr
|
||||
*/
|
||||
void
|
||||
|
|
|
@ -79,19 +79,6 @@ extern void GSPropertyListMake(id,NSDictionary*,BOOL,BOOL,unsigned,id*);
|
|||
|
||||
|
||||
|
||||
@class GSArray;
|
||||
@interface GSArray : NSObject // Help the compiler
|
||||
@end
|
||||
@class GSInlineArray;
|
||||
@interface GSInlineArray : NSObject // Help the compiler
|
||||
@end
|
||||
@class GSMutableArray;
|
||||
@interface GSMutableArray : NSObject // Help the compiler
|
||||
@end
|
||||
@class GSPlaceholderArray;
|
||||
@interface GSPlaceholderArray : NSObject // Help the compiler
|
||||
@end
|
||||
|
||||
static Class NSArrayClass;
|
||||
static Class GSArrayClass;
|
||||
static Class GSInlineArrayClass;
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include "Foundation/NSException.h"
|
||||
#include "Foundation/NSCoder.h"
|
||||
#include "NSConcreteNumber.h"
|
||||
#include "GSPrivate.h"
|
||||
|
||||
#define TYPE_ORDER 0
|
||||
#include "NSConcreteNumberTemplate.m"
|
||||
|
|
|
@ -104,7 +104,7 @@
|
|||
if (data <= GS_SMALL)
|
||||
#endif
|
||||
{
|
||||
return GSSmallHash((int)data);
|
||||
return GSPrivateSmallHash((int)data);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
#include "Foundation/NSObjCRuntime.h"
|
||||
|
||||
#include "NSConcreteNumber.h"
|
||||
#include "GSPrivate.h"
|
||||
|
||||
@interface GSCachedBool : NSBoolNumber
|
||||
@end
|
||||
|
@ -152,7 +153,7 @@ GSNumberInfoFromObject(NSNumber *o)
|
|||
}
|
||||
|
||||
unsigned int
|
||||
GSSmallHash(int n)
|
||||
GSPrivateSmallHash(int n)
|
||||
{
|
||||
return smallHashes[n + GS_SMALL];
|
||||
}
|
||||
|
|
|
@ -50,9 +50,6 @@
|
|||
|
||||
extern BOOL GSScanDouble(unichar*, unsigned, double*);
|
||||
|
||||
@class GSMutableArray;
|
||||
@interface GSMutableArray : NSObject // Help the compiler
|
||||
@end
|
||||
@class GSMutableDictionary;
|
||||
@interface GSMutableDictionary : NSObject // Help the compiler
|
||||
@end
|
||||
|
|
|
@ -49,10 +49,6 @@
|
|||
@class NSDataMalloc;
|
||||
@interface NSDataMalloc : NSObject // Help the compiler
|
||||
@end
|
||||
@class GSInlineArray;
|
||||
@class GSMutableArray;
|
||||
@interface GSMutableArray : NSObject // Help the compiler
|
||||
@end
|
||||
|
||||
/*
|
||||
* Setup for inline operation of string map tables.
|
||||
|
|
|
@ -30,6 +30,9 @@
|
|||
#include "Foundation/NSKeyValueCoding.h"
|
||||
#include "Foundation/NSString.h"
|
||||
|
||||
#include "GNUstepBase/GSObjCRuntime.h"
|
||||
#include "GSPrivate.h"
|
||||
|
||||
@implementation NSSortDescriptor
|
||||
|
||||
- (BOOL) ascending
|
||||
|
@ -72,7 +75,9 @@
|
|||
|
||||
- (unsigned) hash
|
||||
{
|
||||
return _ascending + (unsigned)(uintptr_t)_selector + [_key hash];
|
||||
const char *sel = GSNameFromSelector(_selector);
|
||||
|
||||
return _ascending + GSPrivateHash(sel, strlen(sel), 16, YES) + [_key hash];
|
||||
}
|
||||
|
||||
- (id) initWithKey: (NSString *) key ascending: (BOOL) ascending
|
||||
|
@ -123,12 +128,7 @@
|
|||
{
|
||||
return NO;
|
||||
}
|
||||
/* FIXME ... we should use sel_eq to compare selectors, but if we do
|
||||
* our implementation of -hash will be wrong ... so we will need to
|
||||
* store all instances in a set to ensure uniqueness.
|
||||
*/
|
||||
// if (!sel_eq(((NSSortDescriptor*)other)->_selector, _selector))
|
||||
if (((NSSortDescriptor*)other)->_selector != _selector)
|
||||
if (!sel_eq(((NSSortDescriptor*)other)->_selector, _selector))
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
|
@ -238,139 +238,100 @@ 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;
|
||||
unsigned int 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 = [GSMutableArray 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();
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation GSMutableArray (NSSortDescriptorSorting)
|
||||
|
||||
- (void) sortUsingDescriptors: (NSArray *)sortDescriptors
|
||||
{
|
||||
unsigned dCount = [sortDescriptors count];
|
||||
|
||||
if (_count > 1 && dCount > 0)
|
||||
{
|
||||
GS_BEGINIDBUF(descriptors, dCount);
|
||||
|
||||
[sortDescriptors getObjects: descriptors];
|
||||
SortRange(_contents_array, NSMakeRange(0, _count), descriptors, dCount);
|
||||
|
||||
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