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:
Richard Frith-MacDonald 2006-10-26 08:33:40 +00:00
parent f03d22e63f
commit e26157d901
11 changed files with 180 additions and 173 deletions

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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;

View file

@ -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"

View file

@ -104,7 +104,7 @@
if (data <= GS_SMALL)
#endif
{
return GSSmallHash((int)data);
return GSPrivateSmallHash((int)data);
}
#endif

View file

@ -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];
}

View file

@ -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

View file

@ -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.

View file

@ -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