mirror of
https://github.com/gnustep/libs-performance.git
synced 2025-02-16 08:31:25 +00:00
Some tidyups
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/performance/trunk@23634 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
05cebfc22b
commit
bfe4fb8df2
5 changed files with 182 additions and 85 deletions
11
ChangeLog
11
ChangeLog
|
@ -1,3 +1,14 @@
|
|||
2006-09-27 Richard Frith-Macdonald <rfm@gnu.org>
|
||||
|
||||
* 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 <ratmice@yahoo.com>
|
||||
|
||||
* GSSkipMutableArray.[hm]: New NSMutableArray subclass.
|
||||
|
|
|
@ -26,7 +26,6 @@ Performance_HEADER_FILES += \
|
|||
GSCache.h \
|
||||
GSThroughput.h \
|
||||
GSTicker.h \
|
||||
GSIndexedSkipList.h \
|
||||
GSSkipMutableArray.h \
|
||||
|
||||
|
||||
|
|
|
@ -28,6 +28,10 @@
|
|||
#include <string.h>
|
||||
#include "GSIndexedSkipList.h"
|
||||
|
||||
#if defined(__MINGW32__)
|
||||
#include <cstdlib.h> /* 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;
|
||||
|
|
|
@ -21,49 +21,64 @@
|
|||
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA.
|
||||
*/
|
||||
#include <Foundation/NSArray.h>
|
||||
#include <GSIndexedSkipList.h>
|
||||
|
||||
/**
|
||||
<p>A NSMutableArray subclass which uses a skip list variant for it's underlying
|
||||
data structure.</p>
|
||||
|
||||
<p>while a skip list is typically sorted and represents a dictionary.
|
||||
<p>An NSMutableArray subclass which uses a skip list variant for
|
||||
it's underlying data structure.
|
||||
</p>
|
||||
<p>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.</p>
|
||||
|
||||
<p><code>the underlying data structure looks much like the figure below:<br/>
|
||||
index -> HEAD 1 2 3 4 5 6 TAIL<br/>
|
||||
5| ---------------------> # ------> #<br/>
|
||||
3| -----------> 2 ------> # ------> #<br/>
|
||||
1| -> 1 -> 1 -> 1 -> 1 -> 1 -> # -> #<br/></code></p>
|
||||
the distance between linked nodes.
|
||||
</p>
|
||||
<p>The underlying data structure looks much like the figure below:
|
||||
</p>
|
||||
<example>
|
||||
index -> HEAD 1 2 3 4 5 6 TAIL
|
||||
5| ---------------------> # ------> #
|
||||
3| -----------> 2 ------> # ------> #
|
||||
1| -> 1 -> 1 -> 1 -> 1 -> 1 -> # -> #
|
||||
</example>
|
||||
|
||||
<p>where the numbers represent how many indexes it is to the next node
|
||||
<p>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.</p>
|
||||
|
||||
<p>finding a specific index starts at the top level, until the current
|
||||
<p>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.</p>
|
||||
1 level, and repeats until it finds the wanted index.
|
||||
</p>
|
||||
|
||||
<p>addition and removal of indexes requires an update of the deltas of nodes
|
||||
<p>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.</p>
|
||||
these are the places where it goes down a level.
|
||||
</p>
|
||||
|
||||
<p>the rationale behind it was where a linked list based mutable array will
|
||||
<p>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).</p>
|
||||
random index (because it must traverse the entire list to get to the index).
|
||||
</p>
|
||||
|
||||
<p>and while a c array based mutable array will perform good at random index
|
||||
<p>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).</p>
|
||||
(because it must move all items after the altered index).
|
||||
</p>
|
||||
|
||||
<p>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..</p>
|
||||
<p>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.
|
||||
</p>
|
||||
*/
|
||||
@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
|
||||
|
||||
|
|
|
@ -21,43 +21,76 @@
|
|||
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA.
|
||||
*/
|
||||
|
||||
#include "GSSkipMutableArray.h"
|
||||
#include <Foundation/NSException.h>
|
||||
#include <Foundation/NSValue.h>
|
||||
#include <Foundation/NSEnumerator.h>
|
||||
|
||||
@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) |{ <delta0> 0 | <forward0> }",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) |{ <delta0> 0 | <forward0> }",
|
||||
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%@ |{ <delta%i> %i | <forward%i> }", p, p, p == l->header ? @"(HEADER)" : @"", k, p->forward[k].delta, k]];
|
||||
[foo appendString:
|
||||
[NSString stringWithFormat:
|
||||
@"\"%p\" [label = \"%p%@ |{ <delta%i> %i | <forward%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:@"|{ <delta%i> %i | <forward%i> }", k, p->forward[k].delta, k]];
|
||||
[foo appendString:
|
||||
[NSString stringWithFormat:
|
||||
@"|{ <delta%i> %i | <forward%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
|
||||
|
|
Loading…
Reference in a new issue