mirror of
https://github.com/gnustep/libs-base.git
synced 2025-04-25 17:51:01 +00:00
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
592 lines
13 KiB
Objective-C
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
|
|
|