libs-base/Source/NSPointerArray.m
theraven ceba92a265 Lots of little fixes to make -base compile with -Werror (now builds without warnings).
Richard: I'm unsure about three of these, which were fixes in memset() calls in:
- NSConcreteMapTable.m
- NSConcreteHashTable.m
- Additions/NSData+GNUstepBase.m

Please can you check them?  I think they are intended to zero the entire object
(rather than the first word), but the lack of comments makes me unsure.

Most changes were just tweaks to variable types.  I've also removed some dead code from NSInvocation.  This was small group of things that were marked for internal use only, but not actually referenced in the code anywhere.

Other improvements:

- NSArray / NSDictionary fixed up to use the 10.7 (ARC-friendly) prototypes.
- getObjects:andKeys: implemented for NSDictionary (10.5 method)
- NSPointerArray and NSHashTable now properly support weak objects.
- Tests for weak objects in collections.



git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@33621 72102866-910b-0410-8b05-ffd578937521
2011-07-24 13:09:22 +00:00

592 lines
13 KiB
Objective-C

/**Implementation for NSPointerArray for GNUStep
Copyright (C) 2009 Free Software Foundation, Inc.
Written by: Richard Frith-Macdonald <rfm@gnu.org>
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 "common.h"
#import "Foundation/NSPointerArray.h"
#import "GNUstepBase/GSObjCRuntime.h"
#import "Foundation/NSDictionary.h"
#import "Foundation/NSEnumerator.h"
#import "Foundation/NSException.h"
#import "Foundation/NSValue.h"
#import "Foundation/NSKeyedArchiver.h"
#import "GNUstepBase/NSObject+GNUstepBase.h"
#import "GSPrivate.h"
#import "NSConcretePointerFunctions.h"
static Class abstractClass = Nil;
static Class concreteClass = Nil;
@interface NSConcretePointerArray : NSPointerArray
{
PFInfo _pf;
NSUInteger _count;
void **_contents;
unsigned _capacity;
unsigned _grow_factor;
}
@end
@implementation NSPointerArray
+ (id) allocWithZone: (NSZone*)z
{
if (abstractClass == self)
{
return NSAllocateObject(concreteClass, 0, z);
}
return [super allocWithZone: z];
}
+ (void) initialize
{
if (abstractClass == Nil)
{
abstractClass = [NSPointerArray class];
concreteClass = [NSConcretePointerArray class];
}
}
+ (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;
}
- (BOOL) isEqual: (id)other
{
NSUInteger count;
if (other == self)
{
return YES;
}
if ([other isKindOfClass: abstractClass] == NO)
{
return NO;
}
if ([other hash] != [self hash])
{
return NO;
}
count = [self count];
while (count-- > 0)
{
// FIXME
}
return YES;
}
- (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
@implementation NSConcretePointerArray
- (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];
}
- (NSArray*) allObjects
{
NSUInteger i;
NSUInteger c = 0;
for (i = 0; i < _count; i++)
{
if (pointerFunctionsRead(&_pf, &_contents[i]) != 0)
{
c++;
}
}
if (0 == c)
{
return [NSArray array];
}
else
{
GSMutableArray *a = [GSMutableArray arrayWithCapacity: c];
for (i = 0; i < _count; i++)
{
id obj = pointerFunctionsRead(&_pf, &_contents[i]);
if (obj != 0)
{
[a addObject: obj];
}
}
return [a makeImmutableCopyOnFail: NO];
}
}
- (void) compact
{
NSUInteger insert = 0;
NSUInteger i;
// We can't use memmove here for __weak pointers, because that would omit the
// required read barriers. We could use objc_memmoveCollectable() for strong
// pointers, but we may as well use the same code path for everything
for (i=0 ; i<_count ; i++)
{
id obj = pointerFunctionsRead(&_pf, &_contents[i]);
// If this object is not nil, but at least one before it has been, then
// move it back to the correct location.
if (nil != obj && i != insert)
{
pointerFunctionsAssign(&_pf, &_contents[insert++], obj);
}
}
_count = insert;
}
- (id) copyWithZone: (NSZone*)zone
{
NSConcretePointerArray *c;
unsigned i;
c = (NSConcretePointerArray*)NSCopyObject(self, 0, NSDefaultMallocZone());
c->_capacity = c->_count;
c->_grow_factor = c->_capacity/2;
#if GS_WITH_GC
if (_pf.options & NSPointerFunctionsZeroingWeakMemory)
{
c->_contents = NSAllocateCollectable(sizeof(id) * _count, 0);
}
else
{
c->_contents = NSAllocateCollectable(sizeof(id) * _count,
NSScannedOption);
}
#else
c->_contents = NSZoneCalloc([self zone], _count, sizeof(id));
#endif
for (i = 0; i < _count; i++)
{
NSLog(@"Copying %d, %p", i, _contents[i]);
pointerFunctionsAcquire(&_pf, &c->_contents[i],
pointerFunctionsRead(&_pf, &_contents[i]));
}
return c;
}
- (NSUInteger) count
{
return _count;
}
- (void) dealloc
{
[self finalize];
if (_contents != 0)
{
NSZoneFree([self zone], _contents);
}
[super dealloc];
}
- (void) encodeWithCoder: (NSCoder*)aCoder
{
/* FIXME ... how can we meaningfully encode the pointer functions???
*/
[self notImplemented: _cmd];
if ([aCoder allowsKeyedCoding])
{
[super encodeWithCoder: aCoder];
}
else
{
/* For performace we encode directly ... must exactly match the
* superclass implemenation. */
[aCoder encodeValueOfObjCType: @encode(NSUInteger)
at: &_count];
if (_count > 0)
{
[aCoder encodeArrayOfObjCType: @encode(id)
count: _count
at: _contents];
}
}
}
- (NSUInteger) hash
{
return _count;
}
- (id) initWithCoder: (NSCoder*)aCoder
{
/* FIXME ... how can we meaningfully encode the pointer functions???
*/
[self notImplemented: _cmd];
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(NSUInteger)
at: &_count];
if (_count > 0)
{
#if GS_WITH_GC
if (_pf.options & NSPointerFunctionsZeroingWeakMemory)
{
_contents = NSAllocateCollectable(sizeof(id) * _count, 0);
}
else
{
_contents = NSAllocateCollectable(sizeof(id) * _count,
NSScannedOption);
}
#else
_contents = NSZoneCalloc([self zone], _count, sizeof(id));
#endif
if (_contents == 0)
{
[NSException raise: NSMallocException
format: @"Unable to make array"];
}
[aCoder decodeArrayOfObjCType: @encode(id)
count: _count
at: _contents];
}
}
return self;
}
- (id) initWithOptions: (NSPointerFunctionsOptions)options
{
NSConcretePointerFunctions *f;
f = [[NSConcretePointerFunctions alloc] initWithOptions: options];
self = [self initWithPointerFunctions: f];
[f release];
return self;
}
- (id) initWithPointerFunctions: (NSPointerFunctions*)functions
{
if (![functions isKindOfClass: [NSConcretePointerFunctions class]])
{
static NSConcretePointerFunctions *defaultFunctions = nil;
if (defaultFunctions == nil)
{
defaultFunctions
= [[NSConcretePointerFunctions alloc] initWithOptions: 0];
}
functions = defaultFunctions;
}
memcpy(&_pf, &((NSConcretePointerFunctions*)functions)->_x, sizeof(_pf));
return self;
}
- (void) insertPointer: (void*)pointer atIndex: (NSUInteger)index
{
NSUInteger i;
if (index > _count)
{
[self _raiseRangeExceptionWithIndex: index from: _cmd];
}
i = _count;
[self setCount: _count + 1];
while (i > index)
{
pointerFunctionsMove(&_pf, _contents+i, _contents + i-1);
i--;
}
pointerFunctionsAcquire(&_pf, &_contents[index], pointer);
}
- (BOOL) isEqual: (id)other
{
NSUInteger count;
if (other == self)
{
return YES;
}
if ([other isKindOfClass: abstractClass] == NO)
{
return NO;
}
if ([other hash] != [self hash])
{
return NO;
}
count = [self count];
while (count-- > 0)
{
if (pointerFunctionsEqual(&_pf,
pointerFunctionsRead(&_pf, &_contents[count]),
[other pointerAtIndex: count]) == NO)
return NO;
}
return YES;
}
- (void*) pointerAtIndex: (NSUInteger)index
{
if (index >= _count)
{
[self _raiseRangeExceptionWithIndex: index from: _cmd];
}
return pointerFunctionsRead(&_pf, &_contents[index]);
}
- (NSPointerFunctions*) pointerFunctions
{
NSConcretePointerFunctions *pf = [NSConcretePointerFunctions new];
pf->_x = _pf;
return [pf autorelease];
}
- (void) removePointerAtIndex: (NSUInteger)index
{
if (index >= _count)
{
[self _raiseRangeExceptionWithIndex: index from: _cmd];
}
pointerFunctionsRelinquish(&_pf, &_contents[index]);
while (++index < _count)
{
pointerFunctionsMove(&_pf, &_contents[index-1], &_contents[index]);
}
[self setCount: _count - 1];
}
- (void) replacePointerAtIndex: (NSUInteger)index withPointer: (void*)item
{
if (index >= _count)
{
[self _raiseRangeExceptionWithIndex: index from: _cmd];
}
pointerFunctionsReplace(&_pf, &_contents[index], item);
}
- (void) setCount: (NSUInteger)count
{
if (count > _count)
{
_count = count;
if (_count >= _capacity)
{
void **ptr;
size_t size;
size_t new_cap = _capacity;
size_t new_gf = _grow_factor ? _grow_factor : 2;
while (new_cap + new_gf < _count)
{
new_cap += new_gf;
new_gf = new_cap/2;
}
size = (new_cap + new_gf)*sizeof(void*);
new_cap += new_gf;
new_gf = new_cap / 2;
if (_contents == 0)
{
#if GS_WITH_GC
ptr = (void**)NSZoneMalloc([self zone], size);
#else
if (_pf.options & NSPointerFunctionsZeroingWeakMemory)
{
ptr = (void**)NSAllocateCollectable(size, 0);
}
else
{
ptr = (void**)NSAllocateCollectable(size, NSScannedOption);
}
#endif
}
else
{
#if GS_WITH_GC
ptr = (void**)NSZoneRealloc([self zone], _contents, size);
#else
if (_pf.options & NSPointerFunctionsZeroingWeakMemory)
{
ptr = (void**)NSReallocateCollectable(
_contents, size, 0);
}
else
{
ptr = (void**)NSReallocateCollectable(
_contents, size, NSScannedOption);
}
#endif
}
if (ptr == 0)
{
[NSException raise: NSMallocException
format: @"Unable to grow array"];
}
_contents = ptr;
_capacity = new_cap;
_grow_factor = new_gf;
}
}
else
{
while (count < _count)
{
_count--;
pointerFunctionsRelinquish(&_pf, &_contents[_count]);
}
}
}
@end