From dcb71438312de960458a0c3232874281ef65f633 Mon Sep 17 00:00:00 2001 From: rfm Date: Wed, 27 Sep 2006 10:46:47 +0000 Subject: [PATCH] Some tidyups git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/performance/trunk@23634 72102866-910b-0410-8b05-ffd578937521 --- ChangeLog | 11 +++ GNUmakefile | 1 - GSIndexedSkipList.m | 23 ++++--- GSSkipMutableArray.h | 73 ++++++++++++-------- GSSkipMutableArray.m | 159 ++++++++++++++++++++++++++++++------------- 5 files changed, 182 insertions(+), 85 deletions(-) diff --git a/ChangeLog b/ChangeLog index c331cce..e0ecb9e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +2006-09-27 Richard Frith-Macdonald + + * GNUmakefile: + * GSIndexedSkipList.m: + * GSSkipMutableArray.h: + * GSSkipMutableArray.m: + Minor fix to (hopefully) build on windows. + Hide implementation details. + Add convenience method (to create skiplist) to NSMutableArray. + Some reformatting for coding standards. + 2006-09-27 Matt Rice * GSSkipMutableArray.[hm]: New NSMutableArray subclass. diff --git a/GNUmakefile b/GNUmakefile index 5187ca7..397f7a0 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -26,7 +26,6 @@ Performance_HEADER_FILES += \ GSCache.h \ GSThroughput.h \ GSTicker.h \ - GSIndexedSkipList.h \ GSSkipMutableArray.h \ diff --git a/GSIndexedSkipList.m b/GSIndexedSkipList.m index dacff69..a4f2daf 100644 --- a/GSIndexedSkipList.m +++ b/GSIndexedSkipList.m @@ -28,6 +28,10 @@ #include #include "GSIndexedSkipList.h" +#if defined(__MINGW32__) +#include /* declares rand() */ +#endif + #define PrettyErr(x) do { fprintf(stderr, "%s:%i: %s\n",__FILE__, __LINE__, x); exit(EXIT_FAILURE); } while (0) GSISLNode GSISLNil; @@ -107,6 +111,7 @@ int GSISLRandomLevel() { int level = 0; static int p = RAND_MAX / 4; + while (rand() < p && level < GSISLMaxLevel) { level++; @@ -141,7 +146,7 @@ void GSISLInsertItemAtIndex(GSISList l, GSISLValueType value, do { while (q = p->forward[k].next, - q != GSISLNil && depth + p->forward[k].delta < index + 1) + q != GSISLNil && depth + p->forward[k].delta < index + 1) { depth += p->forward[k].delta; p = q; @@ -234,7 +239,7 @@ GSISLValueType GSISLRemoveItemAtIndex(GSISList l, unsigned index) do { while (q = p->forward[k].next, - q != GSISLNil && depth + p->forward[k].delta < index + 1) + q != GSISLNil && depth + p->forward[k].delta < index + 1) { depth += p->forward[k].delta; p = q; @@ -252,9 +257,9 @@ GSISLValueType GSISLRemoveItemAtIndex(GSISList l, unsigned index) #endif if (p->forward[k].next == q) { - p->forward[k].delta = (q->forward[k].next == GSISLNil) - ? 0 - : p->forward[k].delta + q->forward[k].delta - 1; + p->forward[k].delta + = (q->forward[k].next == GSISLNil) ? 0 + : p->forward[k].delta + q->forward[k].delta - 1; p->forward[k].next = q->forward[k].next; } @@ -305,7 +310,8 @@ GSISLValueType GSISLItemAtIndex(GSISList l, unsigned index) do { - while (q = p->forward[k].next, q != GSISLNil && depth + p->forward[k].delta < index + 1) + while (q = p->forward[k].next, + q != GSISLNil && depth + p->forward[k].delta < index + 1) { depth += p->forward[k].delta; p = q; @@ -319,7 +325,8 @@ GSISLValueType GSISLItemAtIndex(GSISList l, unsigned index) return(q->value); } -GSISLValueType GSISLReplaceItemAtIndex(GSISList l, GSISLValueType newVal, unsigned index) +GSISLValueType +GSISLReplaceItemAtIndex(GSISList l, GSISLValueType newVal, unsigned index) { int k; unsigned depth = 0; @@ -345,7 +352,7 @@ GSISLValueType GSISLReplaceItemAtIndex(GSISList l, GSISLValueType newVal, unsign do { while (q = p->forward[k].next, - q != GSISLNil && depth + p->forward[k].delta < index + 1) + q != GSISLNil && depth + p->forward[k].delta < index + 1) { depth += p->forward[k].delta; p = q; diff --git a/GSSkipMutableArray.h b/GSSkipMutableArray.h index b72fc8a..3567d7e 100644 --- a/GSSkipMutableArray.h +++ b/GSSkipMutableArray.h @@ -21,49 +21,64 @@ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ #include -#include /** -

A NSMutableArray subclass which uses a skip list variant for it's underlying - data structure.

- -

while a skip list is typically sorted and represents a dictionary. +

An NSMutableArray subclass which uses a skip list variant for + it's underlying data structure. +

+

While a skip list is typically sorted and represents a dictionary. the indexed skip list is sorted by index and maintains deltas to represent - the distance between linked nodes.

- -

the underlying data structure looks much like the figure below:
-index -> HEAD 1 2 3 4 5 6 TAIL
- 5| ---------------------> # ------> #
- 3| -----------> 2 ------> # ------> #
- 1| -> 1 -> 1 -> 1 -> 1 -> 1 -> # -> #

+ the distance between linked nodes. +

+

The underlying data structure looks much like the figure below: +

+ +index -> HEAD 1 2 3 4 5 6 TAIL + 5| ---------------------> # ------> # + 3| -----------> 2 ------> # ------> # + 1| -> 1 -> 1 -> 1 -> 1 -> 1 -> # -> # + -

where the numbers represent how many indexes it is to the next node +

Where the numbers represent how many indexes it is to the next node of the appropriate level. The bottom level always points to the next node.

-

finding a specific index starts at the top level, until the current +

Finding a specific index starts at the top level, until the current depth + the next nodes delta is larger than wanted index, then it goes down - 1 level, and repeats until it finds the wanted index.

+ 1 level, and repeats until it finds the wanted index. +

-

addition and removal of indexes requires an update of the deltas of nodes +

Addition and removal of indexes requires an update of the deltas of nodes which begin before, and end after the wanted index, - these are the places where it goes down a level.

+ these are the places where it goes down a level. +

-

the rationale behind it was where a linked list based mutable array will +

The rationale behind it was where a linked list based mutable array will quickly add and remove elements, it may perform poorly at accessing any - random index (because it must traverse the entire list to get to the index).

+ random index (because it must traverse the entire list to get to the index). +

-

and while a c array based mutable array will perform good at random index +

While a C array based mutable array will perform good at random index access it may perform poorly at adding and removing indexes - (because it must move all items after the altered index).

+ (because it must move all items after the altered index). +

-

so while a SkipMutableArray may not outperform a linked list or a c array - mutable array at their specific strengths, it attempts to not suffer from - either of their weaknesses, at the cost of additional memory overhead..

+

While a GSSkipMutableArray may not outperform a linked list or a + C array based mutable array at their specific strengths, it attempts + to not suffer from either of their weaknesses, at the cost of additional + memory overhead. +

*/ -@interface SkipMutableArray : NSMutableArray -{ - GSISList l; -} - +@interface GSSkipMutableArray : NSMutableArray +@end + +/** + * This category just provides a simpole convenience method to obtain + * a GSSkipMutableArray instance; + */ +@interface NSMutableArray (GSSkipMutableArray) +/** + * Creates and returns an autoreleased GSSkipMutableArray. + */ ++ (GSSkipMutableArray*) skipArray; @end diff --git a/GSSkipMutableArray.m b/GSSkipMutableArray.m index 158865b..3fc54f3 100644 --- a/GSSkipMutableArray.m +++ b/GSSkipMutableArray.m @@ -21,43 +21,76 @@ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ -#include "GSSkipMutableArray.h" #include #include #include -@interface SkipMutableArray(Private) +#include "GSSkipMutableArray.h" +#include "GSIndexedSkipList.h" + +static Class abstractClass = 0; +static Class concreteClass = 0; + +@interface GSConcreteSkipArray : GSSkipMutableArray +{ + GSISList l; +} - (GSISList) _list; @end -@implementation SkipMutableArray(Private) -- (GSISList) _list +@implementation NSMutableArray (GSSkipMutableArray) ++ (GSSkipMutableArray*) skipArray { - return l; + return [GSSkipMutableArray array]; } @end -@interface SkipMutableArrayEnumerator : NSEnumerator +@implementation GSSkipMutableArray ++ (id) allocWithZone: (NSZone*)z +{ + if (self == abstractClass) + { + return [concreteClass allocWithZone: z]; + } + return [super allocWithZone: z]; +} + ++ (void) initialize +{ + if (abstractClass == 0) + { + abstractClass = [GSSkipMutableArray class]; + concreteClass = [GSConcreteSkipArray class]; + } +} + +@end + + +@interface GSConcreteSkipArrayEnumerator : NSEnumerator { GSISLNode node; } @end -@implementation SkipMutableArrayEnumerator -- (id) initWithArray:(NSArray *)arr +@implementation GSConcreteSkipArrayEnumerator +- (id) initWithArray: (NSArray *)arr { - if (![arr isKindOfClass:[SkipMutableArray class]]) - { - [[NSException exceptionWithName:NSInternalInconsistencyException reason:@"not a SkipMutableArray" userInfo:nil] raise]; - } + if (![arr isKindOfClass: [GSConcreteSkipArray class]]) + { + [[NSException exceptionWithName: NSInternalInconsistencyException + reason: @"not a GSConcreteSkipArray" + userInfo: nil] raise]; + } self = [super init]; - node = [(SkipMutableArray *)arr _list]->header->forward[0].next; + node = [(GSConcreteSkipArray *)arr _list]->header->forward[0].next; return self; } - (id) nextObject { id foo = node->value; + if (node == GSISLNil) return nil; node = node->forward[0].next; @@ -65,7 +98,13 @@ } @end -@implementation SkipMutableArray : NSMutableArray +@implementation GSConcreteSkipArray + +- (GSISList) _list +{ + return l; +} + - (void) _raiseRangeExceptionWithIndex: (unsigned)index from: (SEL)sel { NSDictionary *info; @@ -90,8 +129,7 @@ GSISLInitialize(); } - -- (id) initWithObjects:(id *)objects count:(unsigned) count +- (id) initWithObjects: (id *)objects count: (unsigned) count { int i; self = [super init]; @@ -101,9 +139,9 @@ l = GSISLInitList([self zone]); for (i = 0; i < count; i++) - { - GSISLInsertItemAtIndex(l, RETAIN(objects[i]), i); - } + { + GSISLInsertItemAtIndex(l, RETAIN(objects[i]), i); + } return self; } @@ -132,9 +170,10 @@ } while (p != GSISLNil); NSZoneFree(l->zone, l->header); NSZoneFree(l->zone, l); + [super dealloc]; } -- (void) insertObject:(id)object atIndex:(unsigned)index +- (void) insertObject: (id)object atIndex: (unsigned)index { if (index > l->count) { @@ -144,7 +183,7 @@ GSISLInsertItemAtIndex(l, RETAIN(object), index); } -- (id) objectAtIndex:(unsigned)index +- (id) objectAtIndex: (unsigned)index { if (index >= l->count) { @@ -154,7 +193,7 @@ return GSISLItemAtIndex(l, index); } -- (void) removeObjectAtIndex:(unsigned) index +- (void) removeObjectAtIndex: (unsigned) index { if (index >= l->count) { @@ -164,7 +203,7 @@ RELEASE(GSISLRemoveItemAtIndex(l, index)); } -- (void) addObject:(id)obj +- (void) addObject: (id)obj { GSISLInsertItemAtIndex(l, RETAIN(obj), l->count); } @@ -174,7 +213,7 @@ return l->count; } -- (void) replaceObjectAtIndex:(unsigned)index withObject:(id)obj +- (void) replaceObjectAtIndex: (unsigned)index withObject: (id)obj { RELEASE(GSISLReplaceItemAtIndex(l, RETAIN(obj), index)); } @@ -183,50 +222,77 @@ { id e; - e = [SkipMutableArrayEnumerator allocWithZone: NSDefaultMallocZone()]; + e = [GSConcreteSkipArrayEnumerator + allocWithZone: NSDefaultMallocZone()]; e = [e initWithArray: self]; return AUTORELEASE(e); } + /* returns an in an NSString suitable for running through graphviz, * with the graph named 'graphName' */ -- (NSString *) _makeGraphOfInternalLayoutNamed:(NSString *)graphName +- (NSString *) _makeGraphOfInternalLayoutNamed: (NSString *)graphName { GSISLNode p; unsigned k, i; + NSMutableDictionary *values; + NSMutableArray *edges; + NSMutableString *graph; + NSArray *tmp; p = l->header; k = l->level; - NSMutableString *graph = [[NSMutableString alloc] init]; - [graph appendString:[NSString stringWithFormat:@"digraph %@ {\n", graphName]]; - [graph appendString:@"graph [rankdir = LR];\n"]; - [graph appendString:@"node [shape = record];\n"]; - NSMutableDictionary *values = [[NSMutableDictionary alloc] init]; - NSMutableArray *edges = [[NSMutableArray alloc] init]; - NSArray *tmp; - [values setObject:[NSMutableString stringWithFormat:@"\"%p\" [label = \"%p (NIL) |{ 0 | }",GSISLNil, GSISLNil] forKey:[NSString stringWithFormat:@"%p", GSISLNil]]; + + [graph appendString: + [NSString stringWithFormat: @"digraph %@ {\n", graphName]]; + [graph appendString: @"graph [rankdir = LR];\n"]; + [graph appendString: @"node [shape = record];\n"]; + values = [[NSMutableDictionary alloc] init]; + edges = [[NSMutableArray alloc] init]; + [values setObject: + [NSMutableString stringWithFormat: + @"\"%p\" [label = \"%p (NIL) |{ 0 | }", + GSISLNil, GSISLNil] + forKey: [NSString stringWithFormat: @"%p", GSISLNil]]; for (k = 0; k < l->level + 1; k++) { for (p = l->header; p != GSISLNil; p = p->forward[k].next) { - NSString *value = [NSString stringWithFormat:@"%p", p]; - NSMutableString *foo = [values objectForKey:value]; + NSString *value; + NSMutableString *foo; + value = [NSString stringWithFormat: @"%p", p]; + foo = [values objectForKey: value]; if (foo == nil) { foo = [[NSMutableString alloc] init]; - [foo appendString:[NSString stringWithFormat:@"\"%p\" [label = \"%p%@ |{ %i | }", p, p, p == l->header ? @"(HEADER)" : @"", k, p->forward[k].delta, k]]; + [foo appendString: + [NSString stringWithFormat: + @"\"%p\" [label = \"%p%@ |{ %i | }", + p, p, p == l->header ? @"(HEADER)" : @"", k, + p->forward[k].delta, k]]; if (p != GSISLNil) - [edges addObject:[NSString stringWithFormat:@"\"%p\":forward%i -> \"%p\":delta%i;\n",p,k, p->forward[k].next,p->forward[k].next == GSISLNil ? 0 : k]]; - [values setObject:foo forKey:value]; + [edges addObject: + [NSString stringWithFormat: + @"\"%p\": forward%i -> \"%p\": delta%i;\n", + p, k, p->forward[k].next, + p->forward[k].next == GSISLNil ? 0 : k]]; + [values setObject: foo forKey: value]; RELEASE(foo); } else { - [foo appendString:[NSString stringWithFormat:@"|{ %i | }", k, p->forward[k].delta, k]]; + [foo appendString: + [NSString stringWithFormat: + @"|{ %i | }", + k, p->forward[k].delta, k]]; if (p != GSISLNil) - [edges addObject:[NSString stringWithFormat:@"\"%p\":forward%i -> \"%p\":delta%i;\n",p,k, p->forward[k].next, p->forward[k].next == GSISLNil ? 0 : k]]; - [values setObject:foo forKey:value]; + [edges addObject: + [NSString stringWithFormat: + @"\"%p\": forward%i -> \"%p\": delta%i;\n", + p, k, p->forward[k].next, + p->forward[k].next == GSISLNil ? 0 : k]]; + [values setObject: foo forKey: value]; } } } @@ -234,18 +300,17 @@ tmp = [values allKeys]; for (i = 0; i < [tmp count]; i++) { - [graph appendString:[values objectForKey:[tmp objectAtIndex:i]]]; - [graph appendString:@"\"];\n"]; + [graph appendString: [values objectForKey: [tmp objectAtIndex: i]]]; + [graph appendString: @"\"];\n"]; } for (i = 0; i < [edges count]; i++) { - [graph appendString:[edges objectAtIndex:i]]; + [graph appendString: [edges objectAtIndex: i]]; } - [graph appendString:@"}\n"]; + [graph appendString: @"}\n"]; RELEASE(values); RELEASE(edges); return AUTORELEASE(graph); } - @end