Add NSIndexSet

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@22474 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
Richard Frith-MacDonald 2006-02-12 19:02:58 +00:00
parent b394550bf7
commit 92eb512dc6
6 changed files with 542 additions and 0 deletions

View file

@ -1,3 +1,11 @@
2006-02-12 Richard Frith-Macdonald <rfm@gnu.org>
* Source/NSIndexPath.m: new
* Headers/Foundation/NSIndexPath.h: new
* Headers/Foundation/Foundation.h: include NSIndexPath.h
* Source/GNUmakefile: build NSIndexPath
* Source/DocMakefile: document NSIndexPath
2006-02-10 Richard Frith-Macdonald <rfm@gnu.org>
* Source/win32/GSFileHandleWin32.m: Ignore extraneous write events.

View file

@ -59,6 +59,7 @@
#include <Foundation/NSHashTable.h>
#include <Foundation/NSGeometry.h>
#include <Foundation/NSHost.h>
#include <Foundation/NSIndexPath.h>
#include <Foundation/NSIndexSet.h>
#include <Foundation/NSInvocation.h>
#include <Foundation/NSKeyValueCoding.h>

View file

@ -0,0 +1,107 @@
/** Interface for NSIndexPath for GNUStep
Copyright (C) 2006 Free Software Foundation, Inc.
Written by: Richard Frith-Macdonald <rfm@gnu.org>
Created: Feb 2006
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 Library 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 Library 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.
AutogsdocSource: NSIndexPath.m
*/
#ifndef _NSIndexPath_h_GNUSTEP_BASE_INCLUDE
#define _NSIndexPath_h_GNUSTEP_BASE_INCLUDE
#include <Foundation/NSObject.h>
#if OS_API_VERSION(100400,GS_API_LATEST) && GS_API_VERSION(010200,GS_API_LATEST)
/**
* Instances of this class represent a series of indexes into a hierarchy
* of arrays.<br />
* Each instance is a unique shared object.
*/
@interface NSIndexPath : NSObject <NSCopying, NSCoding>
{
unsigned _hash;
unsigned _length;
unsigned *_indexes;
}
/**
* Return a path containing the single value anIndex.
*/
+ (id) indexPathWithIndex: (unsigned)anIndex;
/**
* Return a path containing all the indexes in the supplied array.
*/
+ (id) indexPathWithIndexes: (unsigned*)indexes length: (unsigned)length;
/**
* Compares other with the receiver.<br />
* Returns NSOrderedSame if the two are identical.<br />
* Returns NSOrderedAscending if other is less than the receiver in a
* depth-wise comparison.<br />
* Returns NSOrderedDescending otherwise.
*/
- (NSComparisonResult) compare: (NSIndexPath*)other;
/**
* Copies all index values from the receiver into aBuffer.
*/
- (void) getIndexes: (unsigned*)aBuffer;
/**
* Return the index at the specified position or raise an exception.
*/
- (unsigned) indexAtPosition: (unsigned)position;
/**
* Return path formed by adding anIndex to the receiver.
*/
- (NSIndexPath *) indexPathByAddingIndex: (unsigned)anIndex;
/**
* Return path formed by removing the last index from the receiver.
*/
- (NSIndexPath *) indexPathByRemovingLastIndex;
/** <init />
* Returns the shared instance containing the specified index, creating it
* and destroying the receiver if necessary.
*/
- (id) initWithIndex: (unsigned)anIndex;
/** <init />
* Returns the shared instance containing the specified index array,
* creating it and destroying the receiver if necessary.
*/
- (id) initWithIndexes: (unsigned*)indexes length: (unsigned)length;
/**
* Returns the number of index values present in the receiver.
*/
- (unsigned) length;
@end
#endif
#endif

View file

@ -63,6 +63,7 @@ NSFormatter.h \
NSGeometry.h \
NSHashTable.h \
NSHost.h \
NSIndexPath.h \
NSIndexSet.h \
NSInvocation.h \
NSKeyedArchiver.h \

View file

@ -168,6 +168,7 @@ NSFormatter.m \
NSGeometry.m \
NSHashTable.m \
NSHost.m \
NSIndexPath.m \
NSIndexSet.m \
NSInvocation.m \
NSKeyedArchiver.m \
@ -290,6 +291,7 @@ NSFormatter.h \
NSGeometry.h \
NSHashTable.h \
NSHost.h \
NSIndexPath.h \
NSIndexSet.h \
NSInvocation.h \
NSKeyedArchiver.h \

423
Source/NSIndexPath.m Normal file
View file

@ -0,0 +1,423 @@
/** Implementation for NSIndexPath for GNUStep
Copyright (C) 2006 Free Software Foundation, Inc.
Written by: Richard Frith-Macdonald <rfm@gnu.org>
Created: Feb 2006
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 Library 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 Library 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.
*/
#include <Foundation/NSByteOrder.h>
#include <Foundation/NSData.h>
#include <Foundation/NSException.h>
#include <Foundation/NSHashTable.h>
#include <Foundation/NSIndexPath.h>
#include <Foundation/NSKeyedArchiver.h>
#include <Foundation/NSLock.h>
#include <Foundation/NSZone.h>
static NSLock *lock = nil;
static NSHashTable *shared = 0;
static Class myClass = 0;
static NSIndexPath *empty = nil;
static NSIndexPath *dummy = nil;
@implementation NSIndexPath
+ (id) allocWithZone: (NSZone*)aZone
{
if (self == myClass)
{
return empty;
}
return [super allocWithZone: aZone];
}
+ (id) indexPathWithIndex: (unsigned)anIndex
{
return [self indexPathWithIndexes: &anIndex length: 1];
}
+ (id) indexPathWithIndexes: (unsigned*)indexes length: (unsigned)length
{
id o = [self allocWithZone: NSDefaultMallocZone()];
o = [o initWithIndexes: indexes length: length];
AUTORELEASE(o);
return o;
}
+ (void) initialize
{
if (empty == nil)
{
myClass = self;
empty = (NSIndexPath*)NSAllocateObject(self, 0, NSDefaultMallocZone());
dummy = (NSIndexPath*)NSAllocateObject(self, 0, NSDefaultMallocZone());
shared = NSCreateHashTable(NSNonRetainedObjectHashCallBacks, 1024);
NSHashInsert(shared, empty);
lock = [NSLock new];
}
}
- (NSComparisonResult) compare: (NSIndexPath*)other
{
if (other == self)
{
return NSOrderedSame;
}
else
{
unsigned pos;
for (pos = 0; pos < _length; pos++)
{
if (pos >= other->_length || other->_indexes[pos] < _indexes[pos])
{
return NSOrderedAscending;
}
if (other->_indexes[pos] > _indexes[pos])
{
return NSOrderedDescending;
}
}
if (_length == other->_length)
{
/*
* Should never get here.
*/
NSLog(@"Argh ... two identical index paths exist!");
return NSOrderedSame;
}
return NSOrderedDescending;
}
}
- (id) copyWithZone: (NSZone*)aZone
{
return RETAIN(self);
}
- (void) dealloc
{
if (self != empty)
{
[lock lock];
NSHashRemove(shared, self);
[lock unlock];
NSZoneFree(NSDefaultMallocZone(), _indexes);
NSDeallocateObject(self);
}
}
- (NSString*)description
{
NSMutableString *m = [[super description] mutableCopy];
unsigned i;
[m appendFormat: @"%u indexes [", _length];
for (i = 0; i < _length; i++)
{
if (i > 0)
{
[m appendString: @", "];
}
[m appendFormat: @"%u", _indexes[i]];
}
[m appendString: @"]"];
return AUTORELEASE(m);
}
- (void) encodeWithCoder: (NSCoder*)aCoder
{
if ([aCoder allowsKeyedCoding] == YES)
{
[aCoder encodeInt: (int)_length forKey: @"NSIndexPathLength"];
if (_length == 1)
{
[aCoder encodeInt: (int)_indexes[0] forKey: @"NSIndexPathValue"];
}
else if (_length > 1)
{
NSMutableData *m;
unsigned *buf;
unsigned i;
m = [NSMutableData new];
[m setLength: _length * sizeof(unsigned)];
buf = [m mutableBytes];
for (i = 0; i < _length; i++)
{
buf[i] = NSSwapHostIntToBig(_indexes[i]);
}
[aCoder encodeObject: m forKey: @"NSIndexPathData"];
RELEASE(m);
}
}
else
{
[aCoder encodeValueOfObjCType: @encode(unsigned) at: &_length];
if (_length > 0)
{
[aCoder encodeArrayOfObjCType: @encode(unsigned)
count: _length
at: _indexes];
}
}
}
- (void) getIndexes: (unsigned*)aBuffer
{
memcpy(aBuffer, _indexes, _length * sizeof(unsigned));
}
- (unsigned) hash
{
return _hash;
}
- (unsigned) indexAtPosition: (unsigned)position
{
if (position >= _length)
[NSException raise: NSRangeException format: @"Invalid location."];
return _indexes[position];
}
/**
* Return path formed by adding the index to the receiver.
*/
- (NSIndexPath *) indexPathByAddingIndex: (unsigned)anIndex
{
unsigned buffer[_length + 1];
[self getIndexes: buffer];
buffer[_length] = anIndex;
return [[self class] indexPathWithIndexes: buffer length: _length + 1];
}
- (NSIndexPath *) indexPathByRemovingLastIndex
{
if (_length <= 1)
{
return empty;
}
else
{
return [[self class] indexPathWithIndexes: _indexes length: _length - 1];
}
}
- (id) initWithCoder: (NSCoder*)aCoder
{
if ([aCoder allowsKeyedCoding] == YES)
{
unsigned length;
unsigned index;
length = (unsigned)[aCoder decodeIntForKey: @"NSIndexPathLength"];
if (length == 1)
{
index = (unsigned)[aCoder decodeIntForKey: @"NSIndexPathValue"];
self = [self initWithIndex: index];
}
else if (length > 1)
{
// FIXME ... not MacOS-X
NSMutableData *d = [aCoder decodeObjectForKey: @"NSIndexPathData"];
unsigned l = [d length];
unsigned s = l / length;
unsigned i;
if (s == sizeof(unsigned))
{
unsigned *ptr = (unsigned*)[d mutableBytes];
for (i = 0; i < _length; i++)
{
ptr[i] = NSSwapBigIntToHost(ptr[i]);
}
self = [self initWithIndexes: ptr length: length];
}
else
{
unsigned *buf;
buf = (unsigned*)NSZoneMalloc(NSDefaultMallocZone(),
length * sizeof(unsigned));
if (s == sizeof(long))
{
long *ptr = (long*)[d mutableBytes];
for (i = 0; i < _length; i++)
{
buf[i] = (unsigned)NSSwapBigLongToHost(ptr[i]);
}
}
else if (s == sizeof(short))
{
short *ptr = (short*)[d mutableBytes];
for (i = 0; i < _length; i++)
{
buf[i] = (unsigned)NSSwapBigShortToHost(ptr[i]);
}
}
else if (s == sizeof(long long))
{
long long *ptr = (long long*)[d mutableBytes];
for (i = 0; i < _length; i++)
{
buf[i] = (unsigned)NSSwapBigLongLongToHost(ptr[i]);
}
}
else
{
[NSException raise: NSGenericException format:
@"Unable to decode unsigned integers of size %u", s];
}
self = [self initWithIndexes: buf length: length];
NSZoneFree(NSDefaultMallocZone(), buf);
}
}
}
else
{
unsigned length;
[aCoder decodeValueOfObjCType: @encode(unsigned) at: &length];
if (length == 0)
{
RELEASE(self);
self = empty;
}
else
{
unsigned buf[16];
unsigned *indexes = buf;
if (length > 16)
{
indexes = NSZoneMalloc(NSDefaultMallocZone(),
length * sizeof(unsigned));
}
[aCoder decodeArrayOfObjCType: @encode(unsigned)
count: length
at: indexes];
self = [self initWithIndexes: indexes length: length];
if (indexes != buf)
{
NSZoneFree(NSDefaultMallocZone(), indexes);
}
}
}
return self;
}
- (id) initWithIndex: (unsigned)anIndex
{
return [self initWithIndexes: &anIndex length: 1];
}
/** <init />
* Initialise the receiver to contain the specified indexes.<br />
* May return an existing index path.
*/
- (id) initWithIndexes: (unsigned*)indexes length: (unsigned)length
{
NSIndexPath *found;
unsigned h = 0;
unsigned i;
if (_length != 0)
{
[NSException raise: NSGenericException
format: @"Attempt to re-initialize NSIndexPath"];
}
// FIXME ... need better hash function?
for (i = 0; i < length; i++)
{
h = (h << 5) ^ indexes[i];
}
[lock lock];
dummy->_hash = h;
dummy->_length = length;
dummy->_indexes = indexes;
found = NSHashGet(shared, dummy);
if (found == nil)
{
if (self == empty)
{
self = (NSIndexPath*)NSAllocateObject([self class],
0, NSDefaultMallocZone());
}
_hash = dummy->_hash;
_length = dummy->_length;
_indexes = NSZoneMalloc(NSDefaultMallocZone(),
_length * sizeof(unsigned));
memcpy(_indexes, dummy->_indexes, _length * sizeof(unsigned));
NSHashInsert(shared, self);
}
else
{
RELEASE(self);
self = RETAIN(found);
}
[lock unlock];
return self;
}
- (BOOL) isEqual: (id)other
{
if (other == self)
{
return YES;
}
if (other == nil || GSObjCIsKindOf(GSObjCClass(other), myClass) == NO)
{
return NO;
}
if (((NSIndexPath*)other)->_length != _length)
{
return NO;
}
else
{
unsigned *oindexes = ((NSIndexPath*)other)->_indexes;
unsigned pos = _length;
while (pos-- > 0)
{
if (_indexes[pos] != oindexes[pos])
{
return NO;
}
}
}
return YES;
}
- (unsigned) length
{
return _length;
}
@end