From ed994b6d46e411aeaec2d492d1b442b0b0a5b64c Mon Sep 17 00:00:00 2001 From: rfm Date: Fri, 23 Jan 2009 17:49:37 +0000 Subject: [PATCH] add NSPointerArray git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@27660 72102866-910b-0410-8b05-ffd578937521 --- ChangeLog | 2 + Headers/Foundation/Foundation.h | 1 + Headers/Foundation/NSPointerArray.h | 134 +++++++++++++ Source/DocMakefile | 2 + Source/GNUmakefile | 2 + Source/NSPointerArray.m | 296 ++++++++++++++++++++++++++++ 6 files changed, 437 insertions(+) create mode 100644 Headers/Foundation/NSPointerArray.h create mode 100644 Source/NSPointerArray.m diff --git a/ChangeLog b/ChangeLog index fdffa0880..54bb19c59 100644 --- a/ChangeLog +++ b/ChangeLog @@ -5,6 +5,8 @@ are dealing with none-nil values. * Headers/Additions/GNUstepBase/GSIMap.h: Some changes moving towards use of typed memory for gc. + * Headers/Foundation/NSPointerArray.h: New class header. + * Source/NSPointerArray.m: Skeletal (non-working) implementation 2009-01-22 Richard Frith-Macdonald diff --git a/Headers/Foundation/Foundation.h b/Headers/Foundation/Foundation.h index 9e487c823..e53aa3637 100644 --- a/Headers/Foundation/Foundation.h +++ b/Headers/Foundation/Foundation.h @@ -85,6 +85,7 @@ #import #import #import +#import #import #import #import diff --git a/Headers/Foundation/NSPointerArray.h b/Headers/Foundation/NSPointerArray.h new file mode 100644 index 000000000..12c825f5a --- /dev/null +++ b/Headers/Foundation/NSPointerArray.h @@ -0,0 +1,134 @@ +/**Interface for NSPointerArray for GNUStep + Copyright (C) 2009 Free Software Foundation, Inc. + + Written by: Richard Frith-Macdonald + Date: 2009 + + This file is part of the GNUstep Base 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 2 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 + Library 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., 51 Franklin Street, Fifth Floor, + Boston, MA 02111 USA. + + */ + +#ifndef __NSPointerArray_h_GNUSTEP_BASE_INCLUDE +#define __NSPointerArray_h_GNUSTEP_BASE_INCLUDE + +#import +#import +#import + +#if OS_API_VERSION(100500, GS_API_LATEST) + +#if defined(__cplusplus) +extern "C" { +#endif + +/** + * An NSPointerArray acts like a standard mutable array except that it + * can contain nil and even non-object values.
+ * The count can also be set causing the array to shrink (discarding items) + * or grow (adding nil/zero items). + */ + +@interface NSPointerArray : NSObject + +/** Allocate an instance, initialise using initWithOptions: and + * return it autoreleased. + */ ++ (id) pointerArrayWithOptions: (NSPointerFunctionsOptions)options; + +/** Allocate an instance, initialise using initWithPointerFunctions: and + * return it autoreleased. + */ ++ (id) pointerArrayWithPointerFunctions: (NSPointerFunctions *)functions; + +/** Removes all nil/zero items from the array. + */ +- (void) compact; // eliminate NULLs + +/** Returns the number of items in the array. + */ +- (NSUInteger) count; + +/** Initialises the receiver with the spefieifd options. + */ +- (id) initWithOptions: (NSPointerFunctionsOptions)options; + +/** Initialises the receiver using the supplied object. + */ +- (id) initWithPointerFunctions: (NSPointerFunctions*)functions; + +/** Adds an item at the end of the array. + */ +- (void) addPointer: (void*)pointer; + +/** Inserts an item at the specified index causing all higher indexed + * items to be adjusted upwards. + */ +- (void) insertPointer: (void*)pointer atIndex: (NSUInteger)index; + +/** Returns the item at the given index or raises an exception if index + * is out of range. + */ +- (void*) pointerAtIndex: (NSUInteger)index; + +/** Returns an autorelease NSPointerFunctions instance giving the + * functions in use by the receiver. + */ +- (NSPointerFunctions*) pointerFunctions; + +/** Removes the item at the specified index, adjusting the positions of + * all higher indexed items. + */ +- (void) removePointerAtIndex: (NSUInteger)index; + +/* Replaces the item at the specified index. The index must be less than + * the current count or an exception is raised. + */ +- (void) replacePointerAtIndex: (NSUInteger)index withPointer: (void*)item; + +/** Sets the number of items in the receiver. Adds nil/zero items to pad + * the end of the array, or removes extraneous items from the end. + */ +- (void) setCount: (NSUInteger)count; + +@end + +@interface NSPointerArray (NSArrayConveniences) + +/** Creates an instance configured to hold objects and prevent them from + * being garbage collected. + */ ++ (id) pointerArrayWithStrongObjects; + +/** Creates an instance configured to hold objects, allowing them to be + * garbage collected and replaced by nil if/when they are collected. + */ ++ (id) pointerArrayWithWeakObjects; + +/** Returns an array containing all the non-nil objects from the receiver. + */ +- (NSArray*) allObjects; + +@end + +#if defined(__cplusplus) +} +#endif + +#endif + +#endif diff --git a/Source/DocMakefile b/Source/DocMakefile index d0cdeebe0..1973f2c6d 100644 --- a/Source/DocMakefile +++ b/Source/DocMakefile @@ -84,6 +84,8 @@ NSNumberFormatter.h \ NSObjCRuntime.h \ NSObject.h \ NSPathUtilities.h \ +NSPointerFunctions.h \ +NSPointerArray.h \ NSPortCoder.h \ NSPort.h \ NSPortMessage.h \ diff --git a/Source/GNUmakefile b/Source/GNUmakefile index 2af7195c1..243b75a9f 100644 --- a/Source/GNUmakefile +++ b/Source/GNUmakefile @@ -223,6 +223,7 @@ NSObject+NSComparisonMethods.m \ NSPage.m \ NSPathUtilities.m \ NSPipe.m \ +NSPointerArray.m \ NSPointerFunctions.m \ NSPort.m \ NSPortCoder.m \ @@ -361,6 +362,7 @@ NSNumberFormatter.h \ NSObjCRuntime.h \ NSObject.h \ NSPathUtilities.h \ +NSPointerArray.h \ NSPointerFunctions.h \ NSPortCoder.h \ NSPort.h \ diff --git a/Source/NSPointerArray.m b/Source/NSPointerArray.m new file mode 100644 index 000000000..6e8e06fac --- /dev/null +++ b/Source/NSPointerArray.m @@ -0,0 +1,296 @@ +/**Implementation for NSPointerArray for GNUStep + Copyright (C) 2009 Free Software Foundation, Inc. + + Written by: Richard Frith-Macdonald + Date: 2009 + + This file is part of the GNUstep Base 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 2 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 + Library 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., 51 Franklin Street, Fifth Floor, + Boston, MA 02111 USA. + + */ + +#import "config.h" +#import "GNUstepBase/preface.h" +#import "Foundation/NSPointerArray.h" +#import "GNUstepBase/GSObjCRuntime.h" +#import "Foundation/NSDictionary.h" +#import "Foundation/NSEnumerator.h" +#import "Foundation/NSException.h" +#import "Foundation/NSDebug.h" +#import "Foundation/NSValue.h" +#import "Foundation/NSKeyedArchiver.h" + +#import "GSPrivate.h" + +@implementation NSPointerArray + ++ (id) pointerArrayWithOptions: (NSPointerFunctionsOptions)options +{ + return AUTORELEASE([[self alloc] initWithOptions: options]); +} + ++ (id) pointerArrayWithPointerFunctions: (NSPointerFunctions *)functions +{ + return AUTORELEASE([[self alloc] initWithPointerFunctions: functions]); +} + +- (void) compact +{ + [self subclassResponsibility: _cmd]; +} + +- (id) copyWithZone: (NSZone*)zone +{ + [self subclassResponsibility: _cmd]; + return nil; +} + +- (NSUInteger) count +{ + [self subclassResponsibility: _cmd]; + return 0; +} + +- (void) encodeWithCoder: (NSCoder*)aCoder +{ + [self subclassResponsibility: _cmd]; +} + +- (id) init +{ + return [self initWithOptions: 0]; +} + +- (id) initWithCoder: (NSCoder*)aCoder +{ + [self subclassResponsibility: _cmd]; + return nil; +} + +- (id) initWithOptions: (NSPointerFunctionsOptions)options +{ + NSPointerFunctions *functions; + + functions = [NSPointerFunctions pointerFunctionsWithOptions: options]; + return [self initWithPointerFunctions: functions]; +} + +- (id) initWithPointerFunctions: (NSPointerFunctions*)functions +{ + [self subclassResponsibility: _cmd]; + return nil; +} + +- (void) addPointer: (void*)pointer +{ + [self insertPointer: pointer atIndex: [self count]]; +} + +- (void) insertPointer: (void*)pointer atIndex: (NSUInteger)index +{ + [self subclassResponsibility: _cmd]; +} + +- (void*) pointerAtIndex: (NSUInteger)index +{ + [self subclassResponsibility: _cmd]; + return 0; +} + +- (NSPointerFunctions*) pointerFunctions +{ + [self subclassResponsibility: _cmd]; + return nil; +} + +- (void) removePointerAtIndex: (NSUInteger)index +{ + [self subclassResponsibility: _cmd]; +} + +- (void) replacePointerAtIndex: (NSUInteger)index withPointer: (void*)item +{ + [self subclassResponsibility: _cmd]; +} + +- (void) setCount: (NSUInteger)count +{ + [self subclassResponsibility: _cmd]; +} + +@end + +@implementation NSPointerArray (NSArrayConveniences) + ++ (id) pointerArrayWithStrongObjects +{ + return [self pointerArrayWithOptions: NSPointerFunctionsStrongMemory]; +} + ++ (id) pointerArrayWithWeakObjects +{ + return [self pointerArrayWithOptions: NSPointerFunctionsZeroingWeakMemory]; +} + +- (NSArray*) allObjects +{ + [self subclassResponsibility: _cmd]; + return nil; +} + +@end + +@interface GSPointerArray : NSPointerArray +{ + NSUInteger _count; + void **_contents_array; + unsigned _capacity; + unsigned _grow_factor; + NSPointerFunctions *_functions; +} +@end + +@implementation GSPointerArray + +- (void) _raiseRangeExceptionWithIndex: (NSUInteger)index from: (SEL)sel +{ + NSDictionary *info; + NSException *exception; + NSString *reason; + + info = [NSDictionary dictionaryWithObjectsAndKeys: + [NSNumber numberWithUnsignedInt: index], @"Index", + [NSNumber numberWithUnsignedInt: _count], @"Count", + self, @"Array", nil, nil]; + + reason = [NSString stringWithFormat: + @"Index %d is out of range %d (in '%@')", + index, _count, NSStringFromSelector(sel)]; + + exception = [NSException exceptionWithName: NSRangeException + reason: reason + userInfo: info]; + [exception raise]; +} + +- (id) copyWithZone: (NSZone*)zone +{ + return RETAIN(self); // FIXME +} + +- (void) dealloc +{ + [self finalize]; + if (_contents_array != 0) + { + NSZoneFree([self zone], _contents_array); + } + [_functions release]; + [super dealloc]; +} + +- (void) encodeWithCoder: (NSCoder*)aCoder +{ + if ([aCoder allowsKeyedCoding]) + { + [super encodeWithCoder: aCoder]; + } + else + { + /* For performace we encode directly ... must exactly match the + * superclass implemenation. */ + [aCoder encodeValueOfObjCType: @encode(unsigned) + at: &_count]; + if (_count > 0) + { + [aCoder encodeArrayOfObjCType: @encode(id) + count: _count + at: _contents_array]; + } + } +} + +- (id) initWithCoder: (NSCoder*)aCoder +{ + if ([aCoder allowsKeyedCoding]) + { + self = [super initWithCoder: aCoder]; + } + else + { + /* for performance, we decode directly into memory rather than + * using the superclass method. Must exactly match superclass. */ + [aCoder decodeValueOfObjCType: @encode(unsigned) + at: &_count]; + if (_count > 0) + { +#if GS_WITH_GC + _contents_array = NSAllocateCollectable(sizeof(id) * _count, + NSScannedOption); +#else + _contents_array = NSZoneCalloc([self zone], _count, sizeof(id)); +#endif + if (_contents_array == 0) + { + [NSException raise: NSMallocException + format: @"Unable to make array"]; + } + [aCoder decodeArrayOfObjCType: @encode(id) + count: _count + at: _contents_array]; + } + } + return self; +} + +- (unsigned) count +{ + return _count; +} + +- (unsigned) hash +{ + return _count; +} + +- (void) insertPointer: (void*)pointer atIndex: (NSUInteger)index +{ + if (index > _count) + { + [self _raiseRangeExceptionWithIndex: index from: _cmd]; + } + if (_count >= _capacity) + { + void **ptr; + size_t size = (_capacity + _grow_factor)*sizeof(void*); + + ptr = (void**)NSZoneRealloc([self zone], _contents_array, size); + if (ptr == 0) + { + [NSException raise: NSMallocException + format: @"Unable to grow array"]; + } + _contents_array = ptr; + _capacity += _grow_factor; + _grow_factor = _capacity/2; + } +// FIXME ... retain/copy in + _contents_array[_count] = pointer; + _count++; +} +@end +