mirror of
https://github.com/gnustep/libs-performance.git
synced 2025-02-19 18:11:16 +00:00
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/performance/trunk@38169 72102866-910b-0410-8b05-ffd578937521
329 lines
7.6 KiB
Objective-C
329 lines
7.6 KiB
Objective-C
/**
|
|
Copyright (C) 2006 Free Software Foundation, Inc.
|
|
|
|
Written by: Matt Rice <ratmice@yahoo.com>
|
|
Date: 2006
|
|
|
|
This file is part of the Performance Library.
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Lesser General Public
|
|
License as published by the Free Software Foundation; either
|
|
version 3 of the License, or (at your option) any later version.
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Lesser General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
|
License along with this library; if not, write to the Free
|
|
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA.
|
|
*/
|
|
|
|
#include <inttypes.h>
|
|
|
|
#import <Foundation/NSDictionary.h>
|
|
#import <Foundation/NSException.h>
|
|
#import <Foundation/NSValue.h>
|
|
#import <Foundation/NSEnumerator.h>
|
|
#import <Foundation/NSString.h>
|
|
|
|
#import "GSSkipMutableArray.h"
|
|
#import "GSIndexedSkipList.h"
|
|
|
|
#if !defined (GNUSTEP) && (MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_4)
|
|
typedef unsigned int NSUInteger;
|
|
#endif
|
|
|
|
static Class abstractClass = 0;
|
|
static Class concreteClass = 0;
|
|
|
|
@interface GSSkipMutableArray : NSMutableArray
|
|
@end
|
|
|
|
@interface GSConcreteSkipArray : GSSkipMutableArray
|
|
{
|
|
GSISList l;
|
|
}
|
|
- (GSISList) _list;
|
|
@end
|
|
|
|
@implementation NSMutableArray (GSSkipMutableArray)
|
|
+ (NSMutableArray*) skipArray
|
|
{
|
|
return [GSSkipMutableArray array];
|
|
}
|
|
@end
|
|
|
|
@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 GSConcreteSkipArrayEnumerator
|
|
- (id) initWithArray: (NSArray *)arr
|
|
{
|
|
if (![arr isKindOfClass: [GSConcreteSkipArray class]])
|
|
{
|
|
[[NSException exceptionWithName: NSInternalInconsistencyException
|
|
reason: @"not a GSConcreteSkipArray"
|
|
userInfo: nil] raise];
|
|
}
|
|
self = [super init];
|
|
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;
|
|
return foo;
|
|
}
|
|
@end
|
|
|
|
@implementation GSConcreteSkipArray
|
|
|
|
- (GSISList) _list
|
|
{
|
|
return l;
|
|
}
|
|
|
|
- (void) _raiseRangeExceptionWithIndex: (NSUInteger)index from: (SEL)sel
|
|
{
|
|
NSDictionary *info;
|
|
NSException *exception;
|
|
NSString *reason;
|
|
|
|
info = [NSDictionary dictionaryWithObjectsAndKeys:
|
|
[NSNumber numberWithUnsignedInt: index], @"Index",
|
|
[NSNumber numberWithUnsignedInt: l->count], @"Count",
|
|
self, @"Array", nil, nil];
|
|
|
|
reason = [NSString stringWithFormat: @"Index %"PRIuPTR
|
|
@" is out of range %d (in '%@')",
|
|
index, l->count, NSStringFromSelector(sel)];
|
|
|
|
exception = [NSException exceptionWithName: NSRangeException
|
|
reason: reason
|
|
userInfo: info];
|
|
[exception raise];
|
|
}
|
|
|
|
+ (void) initialize
|
|
{
|
|
GSISLInitialize();
|
|
}
|
|
|
|
- (id) initWithObjects: (const id[])objects count: (NSUInteger) count
|
|
{
|
|
int i;
|
|
self = [super init];
|
|
|
|
if (!self) return nil;
|
|
|
|
l = GSISLInitList([self zone]);
|
|
|
|
for (i = 0; i < count; i++)
|
|
{
|
|
GSISLInsertItemAtIndex(l, [objects[i] retain], i);
|
|
}
|
|
|
|
return self;
|
|
}
|
|
|
|
- (id) init
|
|
{
|
|
self = [super init];
|
|
|
|
if (!self) return nil;
|
|
|
|
l = GSISLInitList([self zone]);
|
|
return self;
|
|
}
|
|
|
|
- (void) dealloc
|
|
{
|
|
GSISLNode p,q;
|
|
|
|
p = l->header->forward[0].next;
|
|
while (p != GSISLNil)
|
|
{
|
|
q = p->forward[0].next;
|
|
[p->value release];
|
|
NSZoneFree(l->zone,p);
|
|
p = q;
|
|
}
|
|
|
|
NSZoneFree(l->zone, l->header);
|
|
NSZoneFree(l->zone, l);
|
|
[super dealloc];
|
|
}
|
|
|
|
- (void) insertObject: (id)object atIndex: (NSUInteger)index
|
|
{
|
|
if (index > l->count)
|
|
{
|
|
[self _raiseRangeExceptionWithIndex: index from: _cmd];
|
|
}
|
|
|
|
GSISLInsertItemAtIndex(l, [object retain], index);
|
|
}
|
|
|
|
- (id) objectAtIndex: (NSUInteger)index
|
|
{
|
|
if (index >= l->count)
|
|
{
|
|
[self _raiseRangeExceptionWithIndex: index from: _cmd];
|
|
}
|
|
|
|
return GSISLItemAtIndex(l, index);
|
|
}
|
|
|
|
- (void) removeObjectAtIndex: (NSUInteger)index
|
|
{
|
|
if (index >= l->count)
|
|
{
|
|
[self _raiseRangeExceptionWithIndex: index from: _cmd];
|
|
}
|
|
|
|
[GSISLRemoveItemAtIndex(l, index) release];
|
|
}
|
|
|
|
- (void) addObject: (id)obj
|
|
{
|
|
GSISLInsertItemAtIndex(l, [obj retain], l->count);
|
|
}
|
|
|
|
- (NSUInteger) count
|
|
{
|
|
return l->count;
|
|
}
|
|
|
|
- (void) replaceObjectAtIndex: (NSUInteger)index withObject: (id)obj
|
|
{
|
|
[GSISLReplaceItemAtIndex(l, [obj retain], index) release];
|
|
}
|
|
|
|
- (NSEnumerator*) objectEnumerator
|
|
{
|
|
id e;
|
|
|
|
e = [GSConcreteSkipArrayEnumerator
|
|
allocWithZone: NSDefaultMallocZone()];
|
|
e = [e initWithArray: self];
|
|
return [e autorelease];
|
|
}
|
|
|
|
/* returns an in an NSString suitable for running through graphviz,
|
|
* with the graph named 'graphName'
|
|
*/
|
|
- (NSString *) _makeGraphOfInternalLayoutNamed: (NSString *)graphName
|
|
{
|
|
GSISLNode p;
|
|
NSUInteger k, i;
|
|
NSMutableDictionary *values;
|
|
NSMutableArray *edges;
|
|
NSMutableString *graph;
|
|
NSArray *tmp;
|
|
|
|
graph = [[NSMutableString alloc] initWithCapacity: 1024];
|
|
[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;
|
|
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%"PRIuPTR
|
|
@"> %i | <forward%"PRIuPTR"> }",
|
|
p, p, p == l->header ? @"(HEADER)" : @"", k,
|
|
p->forward[k].delta, k]];
|
|
if (p != GSISLNil)
|
|
[edges addObject:
|
|
[NSString stringWithFormat:
|
|
@"\"%p\": forward%"PRIuPTR" -> \"%p\": delta%"PRIuPTR";\n",
|
|
p, k, p->forward[k].next,
|
|
p->forward[k].next == GSISLNil ? 0 : k]];
|
|
[values setObject: foo forKey: value];
|
|
[foo release];
|
|
}
|
|
else
|
|
{
|
|
[foo appendString:
|
|
[NSString stringWithFormat:
|
|
@"|{ <delta%"PRIuPTR"> %i | <forward%"PRIuPTR"> }",
|
|
k, p->forward[k].delta, k]];
|
|
if (p != GSISLNil)
|
|
[edges addObject:
|
|
[NSString stringWithFormat:
|
|
@"\"%p\": forward%"PRIuPTR" -> \"%p\": delta%"PRIuPTR";\n",
|
|
p, k, p->forward[k].next,
|
|
p->forward[k].next == GSISLNil ? 0 : k]];
|
|
[values setObject: foo forKey: value];
|
|
}
|
|
}
|
|
}
|
|
|
|
tmp = [values allKeys];
|
|
for (i = 0; i < [tmp count]; i++)
|
|
{
|
|
[graph appendString: [values objectForKey: [tmp objectAtIndex: i]]];
|
|
[graph appendString: @"\"];\n"];
|
|
}
|
|
for (i = 0; i < [edges count]; i++)
|
|
{
|
|
[graph appendString: [edges objectAtIndex: i]];
|
|
}
|
|
[graph appendString: @"}\n"];
|
|
[values release];
|
|
[edges release];
|
|
return [graph autorelease];
|
|
}
|
|
|
|
@end
|