You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
271 lines
7.5 KiB
271 lines
7.5 KiB
//
|
|
// AMutableDictionary.m
|
|
// ST4
|
|
//
|
|
// Created by Alan Condit on 4/18/11.
|
|
// Copyright 2011 Alan Condit. All rights reserved.
|
|
//
|
|
|
|
#import <Foundation/Foundation.h>
|
|
#import "AMutableDictionary.h"
|
|
#import "ACBTree.h"
|
|
|
|
@implementation AMutableDictionary
|
|
|
|
@synthesize root;
|
|
@synthesize nodes_av;
|
|
@synthesize nodes_inuse;
|
|
@synthesize nxt_nodeid;
|
|
//@synthesize count;
|
|
@synthesize data;
|
|
@synthesize ptrBuffer;
|
|
|
|
+ (AMutableDictionary *) newDictionary
|
|
{
|
|
return [[AMutableDictionary alloc] init];
|
|
}
|
|
|
|
/** dictionaryWithCapacity
|
|
* capacity is meaningless to ACBTree because
|
|
* capacity is automatically increased
|
|
*/
|
|
+ (AMutableDictionary *) dictionaryWithCapacity
|
|
{
|
|
return [[AMutableDictionary alloc] init];
|
|
}
|
|
|
|
- (id)init
|
|
{
|
|
self = [super init];
|
|
if (self) {
|
|
// Initialization code here.
|
|
nxt_nodeid = 0;
|
|
count = 0;
|
|
root = [ACBTree newNodeWithDictionary:self];
|
|
root.nodeType = LEAF;
|
|
root.numrecs = 0;
|
|
root.updtd = NO;
|
|
root.lnodeid = 1;
|
|
root.lnode = nil;
|
|
root.rnodeid = 0xffff;
|
|
root.rnode = nil;
|
|
}
|
|
return self;
|
|
}
|
|
|
|
/** initWithCapacity
|
|
* capacity is meaningless to ACBTree because
|
|
* capacity is automatically increased
|
|
*/
|
|
- (id) initWithCapacity:(NSUInteger)numItems
|
|
{
|
|
self = [super init];
|
|
if (self) {
|
|
// Initialization code here.
|
|
nxt_nodeid = 0;
|
|
count = 0;
|
|
root = [ACBTree newNodeWithDictionary:self];
|
|
root.nodeType = LEAF;
|
|
root.numrecs = 0;
|
|
root.updtd = NO;
|
|
root.lnodeid = 1;
|
|
root.lnode = nil;
|
|
root.rnodeid = 0xffff;
|
|
root.rnode = nil;
|
|
}
|
|
return self;
|
|
}
|
|
|
|
- (void) dealloc
|
|
{
|
|
#ifdef DEBUG_DEALLOC
|
|
NSLog( @"called dealloc in AMutableDictionary" );
|
|
#endif
|
|
if ( data ) [data release];
|
|
if ( root ) [root release];
|
|
[super dealloc];
|
|
}
|
|
|
|
- (id) objectForKey:(id)aKey
|
|
{
|
|
id obj = nil;
|
|
ACBTree *node;
|
|
ACBKey *kp;
|
|
NSInteger ret;
|
|
BOOL mustRelease = NO;
|
|
|
|
if ( [aKey isKindOfClass:[NSString class]] ) {
|
|
kp = [ACBKey newKeyWithKStr:aKey];
|
|
mustRelease = YES;
|
|
}
|
|
else if ( [aKey isKindOfClass:[ACBKey class]] ) {
|
|
kp = aKey;
|
|
//ACBKey *akey = [ACBKey newKey:aKey];
|
|
}
|
|
else {
|
|
@throw [NSException exceptionWithName:NSInvalidArgumentException
|
|
reason:[NSString stringWithFormat:@"What kind of key is this? %@", aKey]
|
|
userInfo:nil];
|
|
return nil; // not a key that I know how to deal with
|
|
}
|
|
node = [root search:kp.key];
|
|
if ( node != nil ) {
|
|
ret = [node searchnode:kp.key match:YES];
|
|
if ( ret >= 0 && ret < node.numkeys ) {
|
|
obj = node.btNodes[ret];
|
|
if ( obj == [NSNull null] ) {
|
|
obj = nil;
|
|
}
|
|
}
|
|
}
|
|
if ( mustRelease ) [kp release];
|
|
return obj;
|
|
}
|
|
|
|
- (void) setObject:(id)obj forKey:(id)aKey
|
|
{
|
|
ACBKey *kp;
|
|
BOOL mustRelease = NO;
|
|
if ( [aKey isKindOfClass:[NSString class]] ) {
|
|
kp = [ACBKey newKeyWithKStr:aKey];
|
|
mustRelease = YES;
|
|
}
|
|
else if ( [aKey isKindOfClass:[ACBKey class]] ) {
|
|
kp = (ACBKey *)aKey;
|
|
}
|
|
else {
|
|
@throw [NSException exceptionWithName:NSInvalidArgumentException
|
|
reason:[NSString stringWithFormat:@"What kind of key is this? %@", aKey]
|
|
userInfo:nil];
|
|
}
|
|
if ( [root search:kp.key] == nil ) {
|
|
if ( obj == nil ) {
|
|
obj = [NSNull null];
|
|
}
|
|
root = [root insertkey:kp value:obj];
|
|
[kp retain];
|
|
[obj retain];
|
|
kp.recnum = count++;
|
|
}
|
|
else {
|
|
if ( mustRelease ) [kp release];
|
|
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"key alreadyExists" userInfo:nil];
|
|
}
|
|
return;
|
|
}
|
|
|
|
- (BOOL) isEqual:(id)object
|
|
{
|
|
return [super isEqual:object];
|
|
}
|
|
|
|
- (void) removeObjectForKey:(id)aKey
|
|
{
|
|
if ( [root deletekey:aKey] == SUCCESS )
|
|
count--;
|
|
}
|
|
|
|
- (NSUInteger) count
|
|
{
|
|
return count;
|
|
}
|
|
|
|
- (NSArray *) allKeys
|
|
{
|
|
NSUInteger cnt = [root keyWalkLeaves];
|
|
return [NSArray arrayWithObjects:ptrBuffer count:cnt];
|
|
}
|
|
|
|
- (NSArray *) allValues
|
|
{
|
|
NSUInteger cnt = [root objectWalkLeaves];
|
|
return [NSArray arrayWithObjects:ptrBuffer count:cnt];
|
|
}
|
|
|
|
- (ArrayIterator *) keyEnumerator
|
|
{
|
|
return [ArrayIterator newIterator:[self allKeys]];
|
|
}
|
|
|
|
- (ArrayIterator *) objectEnumerator
|
|
{
|
|
return [ArrayIterator newIterator:[self allValues]];
|
|
}
|
|
|
|
// This is where all the magic happens.
|
|
// You have two choices when implementing this method:
|
|
// 1) Use the stack based array provided by stackbuf. If you do this, then you must respect the value of 'len'.
|
|
// 2) Return your own array of objects. If you do this, return the full length of the array returned until you run out of objects, then return 0. For example, a linked-array implementation may return each array in order until you iterate through all arrays.
|
|
// In either case, state->itemsPtr MUST be a valid array (non-nil). This sample takes approach #1, using stackbuf to store results.
|
|
- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)len
|
|
{
|
|
NSUInteger cnt = 0;
|
|
// This is the initialization condition, so we'll do one-time setup here.
|
|
// Ensure that you never set state->state back to 0, or use another method to detect initialization
|
|
// (such as using one of the values of state->extra).
|
|
if (state->state == 0) {
|
|
// We are not tracking mutations, so we'll set state->mutationsPtr to point into one of our extra values,
|
|
// since these values are not otherwise used by the protocol.
|
|
// If your class was mutable, you may choose to use an internal variable that is updated when the class is mutated.
|
|
// state->mutationsPtr MUST NOT be NULL.
|
|
state->mutationsPtr = &state->extra[0];
|
|
[self.root objectWalkLeaves];
|
|
}
|
|
// Now we provide items, which we track with state->state, and determine if we have finished iterating.
|
|
if (state->state < self.count) {
|
|
// Set state->itemsPtr to the provided buffer.
|
|
// Alternate implementations may set state->itemsPtr to an internal C array of objects.
|
|
// state->itemsPtr MUST NOT be NULL.
|
|
state->itemsPtr = stackbuf;
|
|
// Fill in the stack array, either until we've provided all items from the list
|
|
// or until we've provided as many items as the stack based buffer will hold.
|
|
while((state->state < self.count) && (cnt < len)) {
|
|
// For this sample, we generate the contents on the fly.
|
|
// A real implementation would likely just be copying objects from internal storage.
|
|
stackbuf[cnt++] = ptrBuffer[state->state++];
|
|
}
|
|
// state->state = ((cnt < len)? cnt : len);
|
|
}
|
|
else
|
|
{
|
|
// We've already provided all our items, so we signal we are done by returning 0.
|
|
cnt = 0;
|
|
}
|
|
return cnt;
|
|
}
|
|
|
|
- (void) clear
|
|
{
|
|
if ( count ) [self removeAllObjects];
|
|
}
|
|
|
|
- (void) removeAllObjects
|
|
{
|
|
if ( [self count] > 0 ) {
|
|
// root = [ACBTree newNodeWithDictionary:self];
|
|
NSArray *list = [self allKeys];
|
|
for ( NSInteger i = [self count] - 1; i >= 0; i-- ) {
|
|
[self removeObjectForKey:[list objectAtIndex:i]];
|
|
}
|
|
root.nodeid = 0;
|
|
nxt_nodeid = 1;
|
|
}
|
|
}
|
|
|
|
- (NSInteger) nextNodeId
|
|
{
|
|
return nxt_nodeid++;
|
|
}
|
|
|
|
- (NSArray *) toKeyArray
|
|
{
|
|
return nil;
|
|
}
|
|
|
|
- (NSArray *) toValueArray
|
|
{
|
|
return nil;
|
|
}
|
|
|
|
@end
|