mirror of
https://github.com/gnustep/libs-base.git
synced 2025-04-23 00:41:02 +00:00
more GC updates
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@28223 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
d3398a8044
commit
92c3166df3
6 changed files with 1015 additions and 532 deletions
|
@ -1,3 +1,10 @@
|
|||
2009-04-16 Richard Frith-Macdonald <rfm@gnu.org>
|
||||
|
||||
* Headers/Foundation/NSHasTable.h: new OSX 10.5 API
|
||||
* Source/NSHashTable.m: New abstract class
|
||||
* Source/NSConcreteHashTable.m: concrete implementation
|
||||
* Source/NSKeyValueObserving.m: Fix incorrect hash table references.
|
||||
|
||||
2009-04-13 Richard Frith-Macdonald <rfm@gnu.org>
|
||||
|
||||
* Source/GSString.m: Change placeholder string initialisation so that,
|
||||
|
|
|
@ -39,7 +39,7 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
|
||||
@class NSArray, NSSet, NSHashTable;
|
||||
|
||||
/**** Type, Constant, and Macro Definitions **********************************/
|
||||
|
@ -146,12 +146,6 @@ typedef NSUInteger NSHashTableOptions;
|
|||
|
||||
@end
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Hash table type ... an opaque pointer to a data structure.
|
||||
*/
|
||||
typedef void* NSHashTable;
|
||||
|
||||
/**
|
||||
* Type for enumerating.<br />
|
||||
|
|
|
@ -176,6 +176,7 @@ NSClassDescription.m \
|
|||
NSCoder.m \
|
||||
NSCopyObject.m \
|
||||
NSCountedSet.m \
|
||||
NSConcreteHashTable.m \
|
||||
NSConcreteMapTable.m \
|
||||
NSConcreteNumber.m \
|
||||
NSConnection.m \
|
||||
|
|
877
Source/NSConcreteHashTable.m
Normal file
877
Source/NSConcreteHashTable.m
Normal file
|
@ -0,0 +1,877 @@
|
|||
/** Implementation of NSHashTable for GNUStep
|
||||
Copyright (C) 2009 Free Software Foundation, Inc.
|
||||
|
||||
Written by: Richard Frith-Macdonald <rfm@gnu.org>
|
||||
Date: April 2009
|
||||
|
||||
Based on original o_hash code by Albin L. Jones <Albin.L.Jones@Dartmouth.EDU>
|
||||
|
||||
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.
|
||||
|
||||
$Date: 2008-06-08 11:38:33 +0100 (Sun, 08 Jun 2008) $ $Revision: 26606 $
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#import "Foundation/NSArray.h"
|
||||
#import "Foundation/NSDebug.h"
|
||||
#import "Foundation/NSDictionary.h"
|
||||
#import "Foundation/NSEnumerator.h"
|
||||
#import "Foundation/NSException.h"
|
||||
#import "Foundation/NSGarbageCollector.h"
|
||||
#import "Foundation/NSHashTable.h"
|
||||
#import "Foundation/NSString.h"
|
||||
#import "Foundation/NSZone.h"
|
||||
|
||||
#import "NSConcretePointerFunctions.h"
|
||||
#import "NSCallBacks.h"
|
||||
|
||||
static Class concreteClass = 0;
|
||||
|
||||
/* Here is the interface for the concrete class as used by the functions.
|
||||
*/
|
||||
|
||||
typedef struct _GSIMapBucket GSIMapBucket_t;
|
||||
typedef struct _GSIMapNode GSIMapNode_t;
|
||||
typedef GSIMapBucket_t *GSIMapBucket;
|
||||
typedef GSIMapNode_t *GSIMapNode;
|
||||
|
||||
@interface NSConcreteHashTable : NSHashTable
|
||||
{
|
||||
@public
|
||||
NSZone *zone;
|
||||
size_t nodeCount; /* Number of used nodes in hash. */
|
||||
size_t bucketCount; /* Number of buckets in hash. */
|
||||
GSIMapBucket buckets; /* Array of buckets. */
|
||||
GSIMapNode freeNodes; /* List of unused nodes. */
|
||||
GSIMapNode *nodeChunks; /* Chunks of allocated memory. */
|
||||
size_t chunkCount; /* Number of chunks in array. */
|
||||
size_t increment; /* Amount to grow by. */
|
||||
BOOL legacy; /* old style callbacks? */
|
||||
union {
|
||||
PFInfo pf;
|
||||
NSHashTableCallBacks old;
|
||||
}cb;
|
||||
}
|
||||
@end
|
||||
|
||||
#define GSI_MAP_HAS_VALUE 0
|
||||
#define GSI_MAP_TABLE_T NSConcreteHashTable
|
||||
|
||||
#define GSI_MAP_HASH(M, X)\
|
||||
(M->legacy ? M->cb.old.hash(M, X.ptr) \
|
||||
: pointerFunctionsHash(&M->cb.pf, X.ptr))
|
||||
#define GSI_MAP_EQUAL(M, X, Y)\
|
||||
(M->legacy ? M->cb.old.isEqual(M, X.ptr, Y.ptr) \
|
||||
: pointerFunctionsEqual(&M->cb.pf, X.ptr, Y.ptr))
|
||||
#define GSI_MAP_RELEASE_KEY(M, X)\
|
||||
(M->legacy ? M->cb.old.release(M, X.ptr) \
|
||||
: pointerFunctionsRelinquish(&M->cb.pf, &X.ptr))
|
||||
#define GSI_MAP_RETAIN_KEY(M, X)\
|
||||
(M->legacy ? M->cb.old.retain(M, X.ptr) \
|
||||
: pointerFunctionsAcquire(&M->cb.pf, &X.ptr, X.ptr))
|
||||
|
||||
#define GSI_MAP_ENUMERATOR NSHashEnumerator
|
||||
|
||||
#if GS_WITH_GC
|
||||
#include <gc_typed.h>
|
||||
static GC_descr nodeS = 0;
|
||||
static GC_descr nodeW = 0;
|
||||
#define GSI_MAP_NODES(M, X) \
|
||||
(GSIMapNode)GC_calloc_explicitly_typed(X, sizeof(GSIMapNode_t), (GC_descr)M->zone)
|
||||
#endif
|
||||
|
||||
#include "GNUstepBase/GSIMap.h"
|
||||
|
||||
/**** Function Implementations ****/
|
||||
|
||||
/**
|
||||
* Returns an array of all the objects in the table.
|
||||
* NB. The table <em>must</em> contain objects for its keys.
|
||||
*/
|
||||
NSArray *
|
||||
NSAllHashTableObjects(NSHashTable *table)
|
||||
{
|
||||
NSMutableArray *array;
|
||||
NSHashEnumerator enumerator;
|
||||
id element;
|
||||
|
||||
if (table == nil)
|
||||
{
|
||||
NSWarnFLog(@"Null table argument supplied");
|
||||
return nil;
|
||||
}
|
||||
|
||||
/* Create our mutable key array. */
|
||||
array = [NSMutableArray arrayWithCapacity: NSCountHashTable(table)];
|
||||
|
||||
/* Get an enumerator for TABLE. */
|
||||
enumerator = NSEnumerateHashTable(table);
|
||||
|
||||
/* Step through TABLE... */
|
||||
while ((element = NSNextHashEnumeratorItem(&enumerator)) != nil)
|
||||
{
|
||||
[array addObject: element];
|
||||
}
|
||||
NSEndHashTableEnumeration(&enumerator);
|
||||
return array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares the two hash tables for equality.
|
||||
* If the tables are different sizes, returns NO.
|
||||
* Otherwise, compares the values in the two tables
|
||||
* and returns NO if they differ.<br />
|
||||
* The GNUstep implementation enumerates the values in table1
|
||||
* and uses the hash and isEqual functions of table2 for comparison.
|
||||
*/
|
||||
BOOL
|
||||
NSCompareHashTables(NSHashTable *table1, NSHashTable *table2)
|
||||
{
|
||||
if (table1 == table2)
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
if (table1 == nil)
|
||||
{
|
||||
NSWarnFLog(@"Nul first argument supplied");
|
||||
return NO;
|
||||
}
|
||||
if (table2 == nil)
|
||||
{
|
||||
NSWarnFLog(@"Nul second argument supplied");
|
||||
return NO;
|
||||
}
|
||||
if ([table1 count] != [table2 count])
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
if (GSObjCClass(table1) != concreteClass
|
||||
&& GSObjCClass(table2) == concreteClass)
|
||||
{
|
||||
id t = table1;
|
||||
|
||||
table1 = table2;
|
||||
table2 = t;
|
||||
}
|
||||
if (GSObjCClass(table1) == concreteClass)
|
||||
{
|
||||
BOOL result = YES;
|
||||
NSHashEnumerator enumerator;
|
||||
GSIMapNode n;
|
||||
|
||||
enumerator = NSEnumerateHashTable(table1);
|
||||
if (GSObjCClass(table2) == concreteClass)
|
||||
{
|
||||
GSIMapTable t2 = (GSIMapTable)table2;
|
||||
|
||||
while ((n = GSIMapEnumeratorNextNode(&enumerator)) != 0)
|
||||
{
|
||||
if (GSIMapNodeForKey(t2, n->key) == 0)
|
||||
{
|
||||
result = NO;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while ((n = GSIMapEnumeratorNextNode(&enumerator)) != 0)
|
||||
{
|
||||
void *v2;
|
||||
|
||||
v2 = NSHashGet(table2, n->key.ptr);
|
||||
if (v2 == 0 && v2 != n->key.ptr)
|
||||
{
|
||||
result = NO;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
NSEndHashTableEnumeration(&enumerator);
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOL result = YES;
|
||||
NSHashEnumerator enumerator;
|
||||
void *v1;
|
||||
|
||||
enumerator = NSEnumerateHashTable(table1);
|
||||
while ((v1 = NSNextHashEnumeratorItem(&enumerator)) != 0)
|
||||
{
|
||||
void *v2 = NSHashGet(table2, v1);
|
||||
|
||||
if ((v2 = NSHashGet(table2, v1)) == 0)
|
||||
{
|
||||
result = NO;
|
||||
break;
|
||||
}
|
||||
}
|
||||
NSEndHashTableEnumeration(&enumerator);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy the supplied hash table.<br />
|
||||
* Returns a hash table, space for which is allocated in zone, which
|
||||
* has (newly retained) copies of table's contents. As always,
|
||||
* if zone is 0, then NSDefaultMallocZone() is used.
|
||||
*/
|
||||
NSHashTable *
|
||||
NSCopyHashTableWithZone(NSHashTable *table, NSZone *zone)
|
||||
{
|
||||
GSIMapTable o = (GSIMapTable)table;
|
||||
GSIMapTable t;
|
||||
GSIMapNode n;
|
||||
NSHashEnumerator enumerator;
|
||||
|
||||
if (table == nil)
|
||||
{
|
||||
NSWarnFLog(@"Null table argument supplied");
|
||||
return 0;
|
||||
}
|
||||
t = (GSIMapTable)[concreteClass allocWithZone: zone];
|
||||
t->legacy = o->legacy;
|
||||
if (t->legacy == YES)
|
||||
{
|
||||
t->cb.old = o->cb.old;
|
||||
}
|
||||
else
|
||||
{
|
||||
t->cb.pf = o->cb.pf;
|
||||
}
|
||||
#if GS_WITH_GC
|
||||
zone = ((GSIMapTable)table)->zone;
|
||||
#endif
|
||||
GSIMapInitWithZoneAndCapacity(t, zone, ((GSIMapTable)table)->nodeCount);
|
||||
|
||||
enumerator = GSIMapEnumeratorForMap((GSIMapTable)table);
|
||||
while ((n = GSIMapEnumeratorNextNode(&enumerator)) != 0)
|
||||
{
|
||||
GSIMapAddKey(t, n->key);
|
||||
}
|
||||
GSIMapEndEnumerator((GSIMapEnumerator)&enumerator);
|
||||
|
||||
return (NSHashTable*)t;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of items in the table.
|
||||
*/
|
||||
unsigned int
|
||||
NSCountHashTable(NSHashTable *table)
|
||||
{
|
||||
if (table == nil)
|
||||
{
|
||||
NSWarnFLog(@"Null table argument supplied");
|
||||
return 0;
|
||||
}
|
||||
return ((GSIMapTable)table)->nodeCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new hash table by calling NSCreateHashTableWithZone() using
|
||||
* NSDefaultMallocZone().<br />
|
||||
* Returns a (pointer to) an NSHashTable space for which is allocated
|
||||
* in the default zone. If capacity is small or 0, then the returned
|
||||
* table has a reasonable capacity.
|
||||
*/
|
||||
NSHashTable *
|
||||
NSCreateHashTable(
|
||||
NSHashTableCallBacks callBacks,
|
||||
unsigned int capacity)
|
||||
{
|
||||
return NSCreateHashTableWithZone(callBacks, capacity, NSDefaultMallocZone());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new hash table using the supplied callbacks structures.
|
||||
* If any functions in the callback structures are null the default
|
||||
* values are used ... as for non-owned pointers.<br />
|
||||
* Of course, if you send 0 for zone, then the hash table will be
|
||||
* created in NSDefaultMallocZone().<br />
|
||||
* The table will be created with the specified capacity ... ie ready
|
||||
* to hold at least that many items.
|
||||
*/
|
||||
NSHashTable *
|
||||
NSCreateHashTableWithZone(
|
||||
NSHashTableCallBacks k,
|
||||
unsigned int capacity,
|
||||
NSZone *zone)
|
||||
{
|
||||
GSIMapTable table;
|
||||
|
||||
if (concreteClass == 0)
|
||||
{
|
||||
[NSConcreteHashTable class];
|
||||
}
|
||||
table = (GSIMapTable)[concreteClass allocWithZone: zone];
|
||||
|
||||
if (k.hash == 0)
|
||||
k.hash = NSNonOwnedPointerHashCallBacks.hash;
|
||||
if (k.isEqual == 0)
|
||||
k.isEqual = NSNonOwnedPointerHashCallBacks.isEqual;
|
||||
if (k.retain == 0)
|
||||
k.retain = NSNonOwnedPointerHashCallBacks.retain;
|
||||
if (k.release == 0)
|
||||
k.release = NSNonOwnedPointerHashCallBacks.release;
|
||||
if (k.describe == 0)
|
||||
k.describe = NSNonOwnedPointerHashCallBacks.describe;
|
||||
|
||||
table->legacy = YES;
|
||||
table->cb.old = k;
|
||||
|
||||
#if GS_WITH_GC
|
||||
GSIMapInitWithZoneAndCapacity(table, (NSZone*)nodeS, capacity);
|
||||
#else
|
||||
GSIMapInitWithZoneAndCapacity(table, zone, capacity);
|
||||
#endif
|
||||
|
||||
return (NSHashTable*)table;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to be called when finished with the enumerator.
|
||||
* This permits memory used by the enumerator to be released!
|
||||
*/
|
||||
void
|
||||
NSEndHashTableEnumeration(NSHashEnumerator *enumerator)
|
||||
{
|
||||
if (enumerator == 0)
|
||||
{
|
||||
NSWarnFLog(@"Null enumerator argument supplied");
|
||||
return;
|
||||
}
|
||||
GSIMapEndEnumerator((GSIMapEnumerator)enumerator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an enumerator for stepping through a hash table using the
|
||||
* NSNextHashEnumeratorPair() function.
|
||||
*/
|
||||
NSHashEnumerator
|
||||
NSEnumerateHashTable(NSHashTable *table)
|
||||
{
|
||||
if (table == nil)
|
||||
{
|
||||
NSHashEnumerator v = {0, 0, 0};
|
||||
|
||||
NSWarnFLog(@"Null table argument supplied");
|
||||
return v;
|
||||
}
|
||||
return GSIMapEnumeratorForMap((GSIMapTable)table);
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy the hash table and release its contents.<br />
|
||||
* Releases all the keys and values of table (using the key and
|
||||
* value callbacks specified at the time of table's creation),
|
||||
* and then proceeds to deallocate the space allocated for table itself.
|
||||
*/
|
||||
void
|
||||
NSFreeHashTable(NSHashTable *table)
|
||||
{
|
||||
if (table == nil)
|
||||
{
|
||||
NSWarnFLog(@"Null table argument supplied");
|
||||
}
|
||||
else
|
||||
{
|
||||
[table release];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value for the specified item, or a null pointer if the
|
||||
* item is not found in the table.
|
||||
*/
|
||||
void *
|
||||
NSHashGet(NSHashTable *table, const void *element)
|
||||
{
|
||||
GSIMapNode n;
|
||||
|
||||
if (table == nil)
|
||||
{
|
||||
NSWarnFLog(@"Null table argument supplied");
|
||||
return 0;
|
||||
}
|
||||
n = GSIMapNodeForKey((GSIMapTable)table, (GSIMapKey)element);
|
||||
if (n == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return n->key.ptr;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the element to table.<br />
|
||||
* If an equal element is already in table, replaces it with the new one.<br />
|
||||
* If element is null raises an NSInvalidArgumentException.
|
||||
*/
|
||||
void
|
||||
NSHashInsert(NSHashTable *table, const void *element)
|
||||
{
|
||||
GSIMapTable t = (GSIMapTable)table;
|
||||
GSIMapNode n;
|
||||
|
||||
if (table == 0)
|
||||
{
|
||||
[NSException raise: NSInvalidArgumentException
|
||||
format: @"Attempt to place value in null hash table"];
|
||||
}
|
||||
if (element == 0)
|
||||
{
|
||||
[NSException raise: NSInvalidArgumentException
|
||||
format: @"Attempt to place null in hash table"];
|
||||
}
|
||||
n = GSIMapNodeForKey(t, (GSIMapKey)element);
|
||||
if (n == 0)
|
||||
{
|
||||
GSIMapAddKey(t, (GSIMapKey)element);
|
||||
}
|
||||
else
|
||||
{
|
||||
GSI_MAP_RELEASE_KEY(t, n->key);
|
||||
n->key = (GSIMapKey)element;
|
||||
GSI_MAP_RETAIN_KEY(t, n->key);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the element to table and returns nul.<br />
|
||||
* If an equal element is already in table, returns the old element
|
||||
* instead of adding the new one.<br />
|
||||
* If element is nul, raises an NSInvalidArgumentException.
|
||||
*/
|
||||
void *
|
||||
NSHashInsertIfAbsent(NSHashTable *table, const void *element)
|
||||
{
|
||||
GSIMapTable t = (GSIMapTable)table;
|
||||
GSIMapNode n;
|
||||
|
||||
if (table == 0)
|
||||
{
|
||||
[NSException raise: NSInvalidArgumentException
|
||||
format: @"Attempt to place value in null hash table"];
|
||||
}
|
||||
if (element == 0)
|
||||
{
|
||||
[NSException raise: NSInvalidArgumentException
|
||||
format: @"Attempt to place null in hash table"];
|
||||
}
|
||||
n = GSIMapNodeForKey(t, (GSIMapKey)element);
|
||||
if (n == 0)
|
||||
{
|
||||
GSIMapAddKey(t, (GSIMapKey)element);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return n->key.ptr;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the element to table and returns nul.<br />
|
||||
* If an equal element is already present, raises NSInvalidArgumentException.
|
||||
* <br />If element is null raises an NSInvalidArgumentException.
|
||||
*/
|
||||
void
|
||||
NSHashInsertKnownAbsent(NSHashTable *table, const void *element)
|
||||
{
|
||||
GSIMapTable t = (GSIMapTable)table;
|
||||
GSIMapNode n;
|
||||
|
||||
if (table == 0)
|
||||
{
|
||||
[NSException raise: NSInvalidArgumentException
|
||||
format: @"Attempt to place value in null hash table"];
|
||||
}
|
||||
if (element == 0)
|
||||
{
|
||||
[NSException raise: NSInvalidArgumentException
|
||||
format: @"Attempt to place null in hash table"];
|
||||
}
|
||||
n = GSIMapNodeForKey(t, (GSIMapKey)element);
|
||||
if (n == 0)
|
||||
{
|
||||
GSIMapAddKey(t, (GSIMapKey)element);
|
||||
}
|
||||
else
|
||||
{
|
||||
[NSException raise: NSInvalidArgumentException
|
||||
format: @"NSHashInsertKnownAbsent ... element not absent"];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified element from the table.
|
||||
*/
|
||||
void
|
||||
NSHashRemove(NSHashTable *table, const void *element)
|
||||
{
|
||||
if (table == 0)
|
||||
{
|
||||
NSWarnFLog(@"Nul table argument supplied");
|
||||
}
|
||||
else
|
||||
{
|
||||
GSIMapRemoveKey((GSIMapTable)table, (GSIMapKey)element);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Step through the hash table ... return the next item or
|
||||
* return nul if we hit the of the table.
|
||||
*/
|
||||
void *
|
||||
NSNextHashEnumeratorItem(NSHashEnumerator *enumerator)
|
||||
{
|
||||
GSIMapNode n;
|
||||
|
||||
if (enumerator == 0)
|
||||
{
|
||||
NSWarnFLog(@"Nul enumerator argument supplied");
|
||||
return 0;
|
||||
}
|
||||
n = GSIMapEnumeratorNextNode((GSIMapEnumerator)enumerator);
|
||||
if (n == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return n->key.ptr;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Empty the hash table (releasing all elements), but preserve its capacity.
|
||||
*/
|
||||
void
|
||||
NSResetHashTable(NSHashTable *table)
|
||||
{
|
||||
if (table == 0)
|
||||
{
|
||||
NSWarnFLog(@"Nul table argument supplied");
|
||||
}
|
||||
else
|
||||
{
|
||||
GSIMapCleanMap((GSIMapTable)table);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string describing the table contents.<br />
|
||||
* For each item, a string of the form "value;\n"
|
||||
* is appended. The appropriate describe function is used to generate
|
||||
* the strings for each item.
|
||||
*/
|
||||
NSString *
|
||||
NSStringFromHashTable(NSHashTable *table)
|
||||
{
|
||||
GSIMapTable t = (GSIMapTable)table;
|
||||
NSMutableString *string;
|
||||
NSHashEnumerator enumerator;
|
||||
const void *element;
|
||||
|
||||
if (table == 0)
|
||||
{
|
||||
NSWarnFLog(@"Nul table argument supplied");
|
||||
return nil;
|
||||
}
|
||||
|
||||
/* This will be our string. */
|
||||
string = [NSMutableString stringWithCapacity: 0];
|
||||
|
||||
/* Get an enumerator for TABLE. */
|
||||
enumerator = NSEnumerateHashTable(table);
|
||||
|
||||
/* Iterate over the elements of TABLE, appending the description of
|
||||
* each to the mutable string STRING. */
|
||||
if (t->legacy)
|
||||
{
|
||||
while ((element = NSNextHashEnumeratorItem(&enumerator)) != nil)
|
||||
{
|
||||
[string appendFormat: @"%@;\n",
|
||||
(t->cb.old.describe)(table, element)];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while ((element = NSNextHashEnumeratorItem(&enumerator)) != nil)
|
||||
{
|
||||
[string appendFormat: @"%@;\n",
|
||||
(t->cb.pf.descriptionFunction)(element)];
|
||||
}
|
||||
}
|
||||
NSEndHashTableEnumeration(&enumerator);
|
||||
return string;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* These are to increase readabilty locally. */
|
||||
typedef unsigned int (*NSHT_hash_func_t)(NSHashTable *, const void *);
|
||||
typedef BOOL (*NSHT_isEqual_func_t)(NSHashTable *, const void *, const void *);
|
||||
typedef void (*NSHT_retain_func_t)(NSHashTable *, const void *);
|
||||
typedef void (*NSHT_release_func_t)(NSHashTable *, void *);
|
||||
typedef NSString *(*NSHT_describe_func_t)(NSHashTable *, const void *);
|
||||
|
||||
/** For sets of pointer-sized or smaller quantities. */
|
||||
const NSHashTableCallBacks NSIntHashCallBacks =
|
||||
{
|
||||
(NSHT_hash_func_t) _NS_int_hash,
|
||||
(NSHT_isEqual_func_t) _NS_int_is_equal,
|
||||
(NSHT_retain_func_t) _NS_int_retain,
|
||||
(NSHT_release_func_t) _NS_int_release,
|
||||
(NSHT_describe_func_t) _NS_int_describe
|
||||
};
|
||||
|
||||
/** For sets of pointers hashed by address. */
|
||||
const NSHashTableCallBacks NSNonOwnedPointerHashCallBacks =
|
||||
{
|
||||
(NSHT_hash_func_t) _NS_non_owned_void_p_hash,
|
||||
(NSHT_isEqual_func_t) _NS_non_owned_void_p_is_equal,
|
||||
(NSHT_retain_func_t) _NS_non_owned_void_p_retain,
|
||||
(NSHT_release_func_t) _NS_non_owned_void_p_release,
|
||||
(NSHT_describe_func_t) _NS_non_owned_void_p_describe
|
||||
};
|
||||
|
||||
/** For sets of objects without retaining and releasing. */
|
||||
const NSHashTableCallBacks NSNonRetainedObjectHashCallBacks =
|
||||
{
|
||||
(NSHT_hash_func_t) _NS_non_retained_id_hash,
|
||||
(NSHT_isEqual_func_t) _NS_non_retained_id_is_equal,
|
||||
(NSHT_retain_func_t) _NS_non_retained_id_retain,
|
||||
(NSHT_release_func_t) _NS_non_retained_id_release,
|
||||
(NSHT_describe_func_t) _NS_non_retained_id_describe
|
||||
};
|
||||
|
||||
/** For sets of objects; similar to [NSSet]. */
|
||||
const NSHashTableCallBacks NSObjectHashCallBacks =
|
||||
{
|
||||
(NSHT_hash_func_t) _NS_id_hash,
|
||||
(NSHT_isEqual_func_t) _NS_id_is_equal,
|
||||
(NSHT_retain_func_t) _NS_id_retain,
|
||||
(NSHT_release_func_t) _NS_id_release,
|
||||
(NSHT_describe_func_t) _NS_id_describe
|
||||
};
|
||||
|
||||
/** For sets of pointers with transfer of ownership upon insertion. */
|
||||
const NSHashTableCallBacks NSOwnedPointerHashCallBacks =
|
||||
{
|
||||
(NSHT_hash_func_t) _NS_owned_void_p_hash,
|
||||
(NSHT_isEqual_func_t) _NS_owned_void_p_is_equal,
|
||||
(NSHT_retain_func_t) _NS_owned_void_p_retain,
|
||||
(NSHT_release_func_t) _NS_owned_void_p_release,
|
||||
(NSHT_describe_func_t) _NS_owned_void_p_describe
|
||||
};
|
||||
|
||||
/** For sets of pointers to structs when the first field of the
|
||||
* struct is the size of an int. */
|
||||
const NSHashTableCallBacks NSPointerToStructHashCallBacks =
|
||||
{
|
||||
(NSHT_hash_func_t) _NS_int_p_hash,
|
||||
(NSHT_isEqual_func_t) _NS_int_p_is_equal,
|
||||
(NSHT_retain_func_t) _NS_int_p_retain,
|
||||
(NSHT_release_func_t) _NS_int_p_release,
|
||||
(NSHT_describe_func_t) _NS_int_p_describe
|
||||
};
|
||||
|
||||
|
||||
|
||||
@implementation NSConcreteHashTable
|
||||
|
||||
+ (void) initialize
|
||||
{
|
||||
if (concreteClass == nil)
|
||||
{
|
||||
concreteClass = [NSConcreteHashTable class];
|
||||
}
|
||||
#if GS_WITH_GC
|
||||
/* We create a typed memory descriptor for hash nodes.
|
||||
*/
|
||||
if (nodeS == 0)
|
||||
{
|
||||
GC_word w[GC_BITMAP_SIZE(GSIMapNode_t)] = {0};
|
||||
|
||||
nodeW = GC_make_descriptor(w, GC_WORD_LEN(GSIMapNode_t));
|
||||
GC_set_bit(w, GC_WORD_OFFSET(GSIMapNode_t, key));
|
||||
nodeS = GC_make_descriptor(w, GC_WORD_LEN(GSIMapNode_t));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void) addObject: (id)anObject
|
||||
{
|
||||
GSIMapTable t = (GSIMapTable)self;
|
||||
GSIMapNode n;
|
||||
|
||||
n = GSIMapNodeForKey(t, (GSIMapKey)anObject);
|
||||
if (n == 0)
|
||||
{
|
||||
GSIMapAddKey(t, (GSIMapKey)anObject);
|
||||
}
|
||||
else if (n->key.obj != anObject)
|
||||
{
|
||||
GSI_MAP_RELEASE_KEY(t, n->key);
|
||||
n->key = (GSIMapKey)anObject;
|
||||
GSI_MAP_RETAIN_KEY(t, n->key);
|
||||
}
|
||||
}
|
||||
|
||||
- (id) copyWithZone: (NSZone*)aZone
|
||||
{
|
||||
return NSCopyHashTableWithZone(self, aZone);
|
||||
}
|
||||
|
||||
- (NSUInteger) count
|
||||
{
|
||||
return (NSUInteger)nodeCount;
|
||||
}
|
||||
|
||||
- (NSUInteger) countByEnumeratingWithState: (NSFastEnumerationState*)state
|
||||
objects: (id*)stackbuf
|
||||
count: (NSUInteger)len
|
||||
{
|
||||
return (NSUInteger)[self subclassResponsibility: _cmd];
|
||||
}
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
GSIMapEmptyMap(self);
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (void) encodeWithCoder: (NSCoder*)aCoder
|
||||
{
|
||||
[self subclassResponsibility: _cmd];
|
||||
}
|
||||
|
||||
- (void) finalize
|
||||
{
|
||||
GSIMapEmptyMap(self);
|
||||
}
|
||||
|
||||
- (NSUInteger) hash
|
||||
{
|
||||
return (NSUInteger)nodeCount;
|
||||
}
|
||||
|
||||
- (id) init
|
||||
{
|
||||
return [self initWithPointerFunctions: nil capacity: 0];
|
||||
}
|
||||
|
||||
- (id) initWithCoder: (NSCoder*)aCoder
|
||||
{
|
||||
return [self subclassResponsibility: _cmd];
|
||||
}
|
||||
|
||||
- (id) initWithPointerFunctions: (NSPointerFunctions*)functions
|
||||
capacity: (NSUInteger)initialCapacity
|
||||
{
|
||||
if (functions == nil)
|
||||
{
|
||||
functions = [NSPointerFunctions pointerFunctionsWithOptions: 0];
|
||||
}
|
||||
legacy = NO;
|
||||
if ([functions class] == [NSConcretePointerFunctions class])
|
||||
{
|
||||
memcpy(&self->cb.pf, &((NSConcretePointerFunctions*)functions)->_x,
|
||||
sizeof(self->cb.pf));
|
||||
}
|
||||
else
|
||||
{
|
||||
self->cb.pf.acquireFunction = [functions acquireFunction];
|
||||
self->cb.pf.descriptionFunction = [functions descriptionFunction];
|
||||
self->cb.pf.hashFunction = [functions hashFunction];
|
||||
self->cb.pf.isEqualFunction = [functions isEqualFunction];
|
||||
self->cb.pf.relinquishFunction = [functions relinquishFunction];
|
||||
self->cb.pf.sizeFunction = [functions sizeFunction];
|
||||
self->cb.pf.usesStrongWriteBarrier
|
||||
= [functions usesStrongWriteBarrier];
|
||||
self->cb.pf.usesWeakReadAndWriteBarriers
|
||||
= [functions usesWeakReadAndWriteBarriers];
|
||||
}
|
||||
|
||||
#if GC_WITH_GC
|
||||
if (self->cb.pf.usesWeakReadAndWriteBarriers)
|
||||
{
|
||||
zone = (NSZone*)nodeW;
|
||||
}
|
||||
else
|
||||
{
|
||||
zone = (NSZone*)nodeS;
|
||||
}
|
||||
#endif
|
||||
GSIMapInitWithZoneAndCapacity(self, zone, initialCapacity);
|
||||
return self;
|
||||
}
|
||||
|
||||
- (BOOL) isEqualToHashTable: (NSHashTable*)other
|
||||
{
|
||||
return NSCompareHashTables(self, other);
|
||||
}
|
||||
|
||||
- (NSEnumerator*) objectEnumerator
|
||||
{
|
||||
return [self subclassResponsibility: _cmd];
|
||||
}
|
||||
|
||||
- (id) member: (id)aKey
|
||||
{
|
||||
if (aKey != nil)
|
||||
{
|
||||
GSIMapNode node = GSIMapNodeForKey(self, (GSIMapKey)aKey);
|
||||
|
||||
if (node)
|
||||
{
|
||||
return node->key.obj;
|
||||
}
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (NSPointerFunctions*) pointerFunctions
|
||||
{
|
||||
NSConcretePointerFunctions *p = [NSConcretePointerFunctions new];
|
||||
|
||||
p->_x = self->cb.pf;
|
||||
return [p autorelease];
|
||||
}
|
||||
|
||||
- (void) removeAllObjects
|
||||
{
|
||||
GSIMapEmptyMap(self);
|
||||
}
|
||||
|
||||
- (NSSet*) setRepresentation
|
||||
{
|
||||
return [self subclassResponsibility: _cmd];
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
@ -1,11 +1,7 @@
|
|||
/** NSHashTable implementation for GNUStep.
|
||||
* Copyright (C) 1994, 1995, 1996, 1997, 2002 Free Software Foundation, Inc.
|
||||
* Copyright (C) 2009 Free Software Foundation, Inc.
|
||||
*
|
||||
* Author: Albin L. Jones <Albin.L.Jones@Dartmouth.EDU>
|
||||
* Created: Mon Dec 12 23:54:09 EST 1994
|
||||
* Updated: Mon Mar 11 01:48:31 EST 1996
|
||||
* Serial: 96.03.11.06
|
||||
* Rewrite by: Richard Frith-Macdonald <rfm@gnu.org>
|
||||
* Author: Richard Frith-Macdonald <rfm@gnu.org>
|
||||
*
|
||||
* This file is part of the GNUstep Base Library.
|
||||
*
|
||||
|
@ -28,590 +24,197 @@
|
|||
* $Date$ $Revision$
|
||||
*/
|
||||
|
||||
/**** Included Headers *******************************************************/
|
||||
|
||||
#include "config.h"
|
||||
#include "Foundation/NSZone.h"
|
||||
#include "Foundation/NSObject.h"
|
||||
#include "Foundation/NSString.h"
|
||||
#include "Foundation/NSArray.h"
|
||||
#include "Foundation/NSException.h"
|
||||
#include "Foundation/NSPointerFunctions.h"
|
||||
#include "Foundation/NSZone.h"
|
||||
#include "Foundation/NSHashTable.h"
|
||||
#include "Foundation/NSDebug.h"
|
||||
#include "NSCallBacks.h"
|
||||
|
||||
@implementation NSHashTable
|
||||
|
||||
/*
|
||||
* The 'Fastmap' stuff provides an inline implementation of a hash
|
||||
* table - for maximum performance.
|
||||
*/
|
||||
#define GSI_MAP_HAS_VALUE 0
|
||||
#define GSI_MAP_EXTRA NSHashTableCallBacks
|
||||
#define GSI_MAP_KTYPES GSUNION_PTR
|
||||
#define GSI_MAP_HASH(M, X)\
|
||||
(M->extra.hash)((NSHashTable*)M, X.ptr)
|
||||
#define GSI_MAP_EQUAL(M, X, Y)\
|
||||
(M->extra.isEqual)((NSHashTable*)M, X.ptr, Y.ptr)
|
||||
#define GSI_MAP_RELEASE_KEY(M, X)\
|
||||
(M->extra.release)((NSHashTable*)M, X.ptr)
|
||||
#define GSI_MAP_RETAIN_KEY(M, X)\
|
||||
(M->extra.retain)((NSHashTable*)M, X.ptr)
|
||||
#define GSI_MAP_ENUMERATOR NSHashEnumerator
|
||||
@class NSConcreteHashTable;
|
||||
|
||||
#if GS_WITH_GC
|
||||
#include <gc_typed.h>
|
||||
static GC_descr nodeStrong = 0;
|
||||
static GC_descr nodeWeak = 0;
|
||||
#define GSI_MAP_NODES(M, X) (GSIMapNode)GC_calloc_explicitly_typed(X, sizeof(GSIMapNode_t), (GC_descr)M->zone)
|
||||
static Class abstractClass = 0;
|
||||
static Class concreteClass = 0;
|
||||
|
||||
+ (id) allocWithZone: (NSZone*)aZone
|
||||
{
|
||||
if (self == abstractClass)
|
||||
{
|
||||
return NSAllocateObject(concreteClass, 0, aZone);
|
||||
}
|
||||
return NSAllocateObject(self, 0, aZone);
|
||||
}
|
||||
|
||||
+ (void) initialize
|
||||
{
|
||||
if (abstractClass == 0)
|
||||
{
|
||||
abstractClass = [NSHashTable class];
|
||||
concreteClass = [NSConcreteHashTable class];
|
||||
}
|
||||
}
|
||||
|
||||
+ (id) hashTableWithOptions: (NSPointerFunctionsOptions)options
|
||||
{
|
||||
NSHashTable *t;
|
||||
|
||||
t = [self allocWithZone: NSDefaultMallocZone()];
|
||||
t = [t initWithOptions: options
|
||||
capacity: 0];
|
||||
return AUTORELEASE(t);
|
||||
}
|
||||
|
||||
+ (id) hashTableWithWeakObjects;
|
||||
{
|
||||
return [self hashTableWithOptions:
|
||||
NSPointerFunctionsObjectPersonality | NSPointerFunctionsZeroingWeakMemory];
|
||||
}
|
||||
|
||||
- (id) initWithOptions: (NSPointerFunctionsOptions)options
|
||||
capacity: (NSUInteger)initialCapacity
|
||||
{
|
||||
NSPointerFunctions *k;
|
||||
id o;
|
||||
|
||||
k = [[NSPointerFunctions alloc] initWithOptions: options];
|
||||
o = [self initWithPointerFunctions: k capacity: initialCapacity];
|
||||
#if !GS_WITH_GC
|
||||
[k release];
|
||||
#endif
|
||||
|
||||
#include "GNUstepBase/GSIMap.h"
|
||||
|
||||
#if GS_WITH_GC
|
||||
static inline void
|
||||
initialize()
|
||||
{
|
||||
if (nodeStrong == 0)
|
||||
{
|
||||
/* We create a typed memory descriptor for map nodes.
|
||||
* Only the pointer to the key needs to be scanned.
|
||||
*/
|
||||
GC_word w[GC_BITMAP_SIZE(GSIMapNode_t)] = {0};
|
||||
nodeWeak = GC_make_descriptor(w, GC_WORD_LEN(GSIMapNode_t));
|
||||
GC_set_bit(w, GC_WORD_OFFSET(GSIMapNode_t, key));
|
||||
nodeStrong = GC_make_descriptor(w, GC_WORD_LEN(GSIMapNode_t));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Returns an array of all the objects in the table.
|
||||
* NB. The table <em>must</em> contain objects, not pointers or integers.
|
||||
*/
|
||||
NSArray *
|
||||
NSAllHashTableObjects(NSHashTable *table)
|
||||
{
|
||||
NSMutableArray *array;
|
||||
NSHashEnumerator enumerator;
|
||||
id element;
|
||||
|
||||
if (table == 0)
|
||||
{
|
||||
NSWarnFLog(@"Nul table argument supplied");
|
||||
return nil;
|
||||
}
|
||||
|
||||
array = [NSMutableArray arrayWithCapacity: NSCountHashTable(table)];
|
||||
|
||||
/* Get an enumerator for TABLE. */
|
||||
enumerator = NSEnumerateHashTable(table);
|
||||
|
||||
while ((element = NSNextHashEnumeratorItem(&enumerator)) != 0)
|
||||
{
|
||||
[array addObject: element];
|
||||
}
|
||||
NSEndHashTableEnumeration(&enumerator);
|
||||
return array;
|
||||
return o;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares the two hash tables for equality.
|
||||
* If the tables are different sizes, returns NO.
|
||||
* Otherwise, compares the values in the two tables
|
||||
* and returns NO if they differ.<br />
|
||||
* The GNUstep implementation enumerates the values in table1
|
||||
* and uses the hash and isEqual functions of table2 for comparison.
|
||||
*/
|
||||
BOOL
|
||||
NSCompareHashTables(NSHashTable *table1, NSHashTable *table2)
|
||||
- (id) initWithPointerFunctions: (NSPointerFunctions*)functions
|
||||
capacity: (NSUInteger)initialCapacity
|
||||
{
|
||||
GSIMapTable t1 = (GSIMapTable)table1;
|
||||
GSIMapTable t2 = (GSIMapTable)table2;
|
||||
|
||||
if (t1 == t2)
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
if (t1 == 0)
|
||||
{
|
||||
NSWarnFLog(@"Nul first argument supplied");
|
||||
return NO;
|
||||
}
|
||||
if (t2 == 0)
|
||||
{
|
||||
NSWarnFLog(@"Nul second argument supplied");
|
||||
return NO;
|
||||
}
|
||||
|
||||
if (t1->nodeCount != t2->nodeCount)
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
else
|
||||
{
|
||||
NSHashEnumerator enumerator = GSIMapEnumeratorForMap((GSIMapTable)t1);
|
||||
GSIMapNode n;
|
||||
while ((n = GSIMapEnumeratorNextNode(&enumerator)) != 0)
|
||||
{
|
||||
if (GSIMapNodeForKey(t2, n->key) == 0)
|
||||
{
|
||||
GSIMapEndEnumerator((GSIMapEnumerator)&enumerator);
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
GSIMapEndEnumerator((GSIMapEnumerator)&enumerator);
|
||||
return YES;
|
||||
}
|
||||
return [self subclassResponsibility: _cmd];
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy the supplied map table creating the new table in the specified zone.
|
||||
*/
|
||||
NSHashTable *
|
||||
NSCopyHashTableWithZone(NSHashTable *table, NSZone *zone)
|
||||
- (void) addObject: (id)object
|
||||
{
|
||||
GSIMapTable t;
|
||||
GSIMapNode n;
|
||||
NSHashEnumerator enumerator;
|
||||
|
||||
if (table == 0)
|
||||
{
|
||||
NSWarnFLog(@"Nul table argument supplied");
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if GS_WITH_GC
|
||||
t = (GSIMapTable)NSAllocateCollectable(sizeof(GSIMapTable_t),
|
||||
NSScannedOption);
|
||||
zone = ((GSIMapTable)table)->zone;
|
||||
#else
|
||||
t = (GSIMapTable)NSZoneMalloc(zone, sizeof(GSIMapTable_t));
|
||||
#endif
|
||||
GSIMapInitWithZoneAndCapacity(t, zone, ((GSIMapTable)table)->nodeCount);
|
||||
t->extra = ((GSIMapTable)table)->extra;
|
||||
enumerator = GSIMapEnumeratorForMap((GSIMapTable)table);
|
||||
while ((n = GSIMapEnumeratorNextNode(&enumerator)) != 0)
|
||||
{
|
||||
GSIMapAddKey(t, n->key);
|
||||
}
|
||||
GSIMapEndEnumerator((GSIMapEnumerator)&enumerator);
|
||||
|
||||
return (NSHashTable*)t;
|
||||
[self subclassResponsibility: _cmd];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of objects in the table.
|
||||
*/
|
||||
unsigned int
|
||||
NSCountHashTable(NSHashTable *table)
|
||||
- (NSArray*) allObjects
|
||||
{
|
||||
if (table == 0)
|
||||
{
|
||||
NSWarnFLog(@"Nul table argument supplied");
|
||||
return 0;
|
||||
}
|
||||
return ((GSIMapTable)table)->nodeCount;
|
||||
return [self subclassResponsibility: _cmd];
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new hash table by calling NSCreateHashTableWithZone() using
|
||||
* NSDefaultMallocZone(). callbacks provides five helper functions used by
|
||||
* the main implementation. See the NSHashTableCallbacks documentation
|
||||
* for more information.<br />
|
||||
* If capacity is small or 0, then the returned
|
||||
* table has a reasonable (but still small) capacity.
|
||||
*/
|
||||
NSHashTable *
|
||||
NSCreateHashTable(
|
||||
NSHashTableCallBacks callBacks,
|
||||
unsigned int capacity)
|
||||
- (id) anyObject
|
||||
{
|
||||
return NSCreateHashTableWithZone(callBacks, capacity, NSDefaultMallocZone());
|
||||
return [self subclassResponsibility: _cmd];
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new hash table using the supplied callbacks structure.
|
||||
* If any functions in the callback structure is null the default
|
||||
* values are used ... as for non-owned pointers.
|
||||
* The table will be created with the specified capacity ... ie ready
|
||||
* to hold at lest that many items.
|
||||
*/
|
||||
NSHashTable *
|
||||
NSCreateHashTableWithZone(
|
||||
NSHashTableCallBacks callBacks,
|
||||
unsigned int capacity,
|
||||
NSZone *zone)
|
||||
- (BOOL) containsObject: (id)anObject
|
||||
{
|
||||
GSIMapTable table;
|
||||
|
||||
#if GS_WITH_GC
|
||||
initialize();
|
||||
table = (GSIMapTable)NSAllocateCollectable(sizeof(GSIMapTable_t),
|
||||
NSScannedOption);
|
||||
zone = (NSZone*)nodeStrong;
|
||||
#else
|
||||
table = (GSIMapTable)NSZoneMalloc(zone, sizeof(GSIMapTable_t));
|
||||
#endif
|
||||
GSIMapInitWithZoneAndCapacity(table, zone, capacity);
|
||||
table->extra = callBacks;
|
||||
|
||||
if (table->extra.hash == 0)
|
||||
table->extra.hash = NSNonOwnedPointerHashCallBacks.hash;
|
||||
if (table->extra.isEqual == 0)
|
||||
table->extra.isEqual = NSNonOwnedPointerHashCallBacks.isEqual;
|
||||
if (table->extra.retain == 0)
|
||||
table->extra.retain = NSNonOwnedPointerHashCallBacks.retain;
|
||||
if (table->extra.release == 0)
|
||||
table->extra.release = NSNonOwnedPointerHashCallBacks.release;
|
||||
if (table->extra.describe == 0)
|
||||
table->extra.describe = NSNonOwnedPointerHashCallBacks.describe;
|
||||
|
||||
return (NSHashTable*)table;
|
||||
return (BOOL)(uintptr_t)[self subclassResponsibility: _cmd];
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to be called when finished with the enumerator.
|
||||
* This permits memory used by the enumerator to be released.
|
||||
*/
|
||||
void
|
||||
NSEndHashTableEnumeration(NSHashEnumerator *enumerator)
|
||||
- (id) copyWithZone: (NSZone*)aZone
|
||||
{
|
||||
if (enumerator == 0)
|
||||
{
|
||||
NSWarnFLog(@"Nul enumerator argument supplied");
|
||||
return;
|
||||
}
|
||||
GSIMapEndEnumerator((GSIMapEnumerator)enumerator);
|
||||
return [self subclassResponsibility: _cmd];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an enumerator for stepping through a map table using the
|
||||
* NSNextHashEnumeratorItem() function.
|
||||
*/
|
||||
NSHashEnumerator
|
||||
NSEnumerateHashTable(NSHashTable *table)
|
||||
- (NSUInteger) count
|
||||
{
|
||||
if (table == 0)
|
||||
{
|
||||
NSHashEnumerator v = { 0, 0, 0 };
|
||||
|
||||
NSWarnFLog(@"Nul table argument supplied");
|
||||
return v;
|
||||
}
|
||||
else
|
||||
{
|
||||
return GSIMapEnumeratorForMap((GSIMapTable)table);
|
||||
}
|
||||
return (NSUInteger)[self subclassResponsibility: _cmd];
|
||||
}
|
||||
|
||||
/**
|
||||
* Releases all the keys and values of table (using the callbacks
|
||||
* specified at the time of table's creation), and then proceeds
|
||||
* to deallocate the space allocated for table itself.
|
||||
*/
|
||||
void
|
||||
NSFreeHashTable(NSHashTable *table)
|
||||
- (NSUInteger) countByEnumeratingWithState: (NSFastEnumerationState*)state
|
||||
objects: (id*)stackbuf
|
||||
count: (NSUInteger)len
|
||||
{
|
||||
if (table == 0)
|
||||
{
|
||||
NSWarnFLog(@"Nul table argument supplied");
|
||||
}
|
||||
else
|
||||
{
|
||||
NSZone *z = ((GSIMapTable)table)->zone;
|
||||
|
||||
GSIMapEmptyMap((GSIMapTable)table);
|
||||
NSZoneFree(z, table);
|
||||
}
|
||||
return (NSUInteger)[self subclassResponsibility: _cmd];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value for the specified element, or a null pointer if the
|
||||
* element is not found in the table.
|
||||
*/
|
||||
void *
|
||||
NSHashGet(NSHashTable *table, const void *element)
|
||||
- (void) encodeWithCoder: (NSCoder*)aCoder
|
||||
{
|
||||
GSIMapNode n;
|
||||
|
||||
if (table == 0)
|
||||
{
|
||||
NSWarnFLog(@"Nul table argument supplied");
|
||||
return 0;
|
||||
}
|
||||
n = GSIMapNodeForKey((GSIMapTable)table, (GSIMapKey)element);
|
||||
if (n == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return n->key.ptr;
|
||||
}
|
||||
[self subclassResponsibility: _cmd];
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the element to table.<br />
|
||||
* If an equal element is already in table, replaces it with the new one.<br />
|
||||
* If element is null raises an NSInvalidArgumentException.
|
||||
*/
|
||||
void
|
||||
NSHashInsert(NSHashTable *table, const void *element)
|
||||
- (NSUInteger) hash
|
||||
{
|
||||
GSIMapTable t = (GSIMapTable)table;
|
||||
GSIMapNode n;
|
||||
|
||||
if (table == 0)
|
||||
{
|
||||
[NSException raise: NSInvalidArgumentException
|
||||
format: @"Attempt to place value in null hash table"];
|
||||
}
|
||||
if (element == 0)
|
||||
{
|
||||
[NSException raise: NSInvalidArgumentException
|
||||
format: @"Attempt to place null in hash table"];
|
||||
}
|
||||
n = GSIMapNodeForKey(t, (GSIMapKey)element);
|
||||
if (n == 0)
|
||||
{
|
||||
GSIMapAddKey(t, (GSIMapKey)element);
|
||||
}
|
||||
else
|
||||
{
|
||||
GSIMapKey tmp = n->key;
|
||||
|
||||
n->key = (GSIMapKey)element;
|
||||
GSI_MAP_RETAIN_KEY(t, n->key);
|
||||
GSI_MAP_RELEASE_KEY(t, tmp);
|
||||
}
|
||||
return (NSUInteger)[self subclassResponsibility: _cmd];
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the element to table and returns nul.<br />
|
||||
* If an equal element is already in table, returns the old element
|
||||
* instead of adding the new one.<br />
|
||||
* If element is nul, raises an NSInvalidArgumentException.
|
||||
*/
|
||||
void *
|
||||
NSHashInsertIfAbsent(NSHashTable *table, const void *element)
|
||||
- (id) initWithCoder: (NSCoder*)aCoder
|
||||
{
|
||||
GSIMapTable t = (GSIMapTable)table;
|
||||
GSIMapNode n;
|
||||
|
||||
if (table == 0)
|
||||
{
|
||||
[NSException raise: NSInvalidArgumentException
|
||||
format: @"Attempt to place value in null hash table"];
|
||||
}
|
||||
if (element == 0)
|
||||
{
|
||||
[NSException raise: NSInvalidArgumentException
|
||||
format: @"Attempt to place null in hash table"];
|
||||
}
|
||||
n = GSIMapNodeForKey(t, (GSIMapKey)element);
|
||||
if (n == 0)
|
||||
{
|
||||
GSIMapAddKey(t, (GSIMapKey)element);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return n->key.ptr;
|
||||
}
|
||||
return [self subclassResponsibility: _cmd];
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the element to table and returns nul.<br />
|
||||
* If an equal element is already present, raises NSInvalidArgumentException.
|
||||
* <br />If element is null raises an NSInvalidArgumentException.
|
||||
*/
|
||||
void
|
||||
NSHashInsertKnownAbsent(NSHashTable *table, const void *element)
|
||||
- (void) intersectHashTable: (NSHashTable*)other
|
||||
{
|
||||
GSIMapTable t = (GSIMapTable)table;
|
||||
GSIMapNode n;
|
||||
|
||||
if (table == 0)
|
||||
{
|
||||
[NSException raise: NSInvalidArgumentException
|
||||
format: @"Attempt to place value in null hash table"];
|
||||
}
|
||||
if (element == 0)
|
||||
{
|
||||
[NSException raise: NSInvalidArgumentException
|
||||
format: @"Attempt to place null in hash table"];
|
||||
}
|
||||
n = GSIMapNodeForKey(t, (GSIMapKey)element);
|
||||
if (n == 0)
|
||||
{
|
||||
GSIMapAddKey(t, (GSIMapKey)element);
|
||||
}
|
||||
else
|
||||
{
|
||||
[NSException raise: NSInvalidArgumentException
|
||||
format: @"NSHashInsertKnownAbsent ... element not absent"];
|
||||
}
|
||||
[self subclassResponsibility: _cmd];
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified element from the table.
|
||||
*/
|
||||
void
|
||||
NSHashRemove(NSHashTable *table, const void *element)
|
||||
- (BOOL) intersectsHashTable: (NSHashTable*)other
|
||||
{
|
||||
if (table == 0)
|
||||
{
|
||||
NSWarnFLog(@"Nul table argument supplied");
|
||||
}
|
||||
else
|
||||
{
|
||||
GSIMapRemoveKey((GSIMapTable)table, (GSIMapKey)element);
|
||||
}
|
||||
return (BOOL)(uintptr_t)[self subclassResponsibility: _cmd];
|
||||
}
|
||||
|
||||
/**
|
||||
* Step through the hash table ... return the next item or
|
||||
* return nul if we hit the of the table.
|
||||
*/
|
||||
void *
|
||||
NSNextHashEnumeratorItem(NSHashEnumerator *enumerator)
|
||||
- (BOOL) isEqual: (id)other
|
||||
{
|
||||
GSIMapNode n;
|
||||
|
||||
if (enumerator == 0)
|
||||
{
|
||||
NSWarnFLog(@"Nul enumerator argument supplied");
|
||||
return 0;
|
||||
}
|
||||
n = GSIMapEnumeratorNextNode((GSIMapEnumerator)enumerator);
|
||||
if (n == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return n->key.ptr;
|
||||
}
|
||||
if (other == self) return YES;
|
||||
if (other == nil) return NO;
|
||||
if ([other isKindOfClass: abstractClass] == NO) return NO;
|
||||
return [self isEqualToHashTable: other];
|
||||
}
|
||||
|
||||
/**
|
||||
* Empty the hash table (releasing all elements), but preserve its capacity.
|
||||
*/
|
||||
void
|
||||
NSResetHashTable(NSHashTable *table)
|
||||
- (BOOL) isEqualToHashTable: (NSHashTable*)other
|
||||
{
|
||||
if (table == 0)
|
||||
{
|
||||
NSWarnFLog(@"Nul table argument supplied");
|
||||
}
|
||||
else
|
||||
{
|
||||
GSIMapCleanMap((GSIMapTable)table);
|
||||
}
|
||||
return (BOOL)(uintptr_t)[self subclassResponsibility: _cmd];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string describing the table contents.<br />
|
||||
* For each item, a string of the form "value;\n"
|
||||
* is appended. The appropriate describe function is used to generate
|
||||
* the strings for each item.
|
||||
*/
|
||||
NSString *
|
||||
NSStringFromHashTable(NSHashTable *table)
|
||||
- (BOOL) isSubsetOfHashTable: (NSHashTable*)other
|
||||
{
|
||||
GSIMapTable t = (GSIMapTable)table;
|
||||
NSMutableString *string;
|
||||
NSHashEnumerator enumerator;
|
||||
const void *element;
|
||||
|
||||
if (table == 0)
|
||||
{
|
||||
NSWarnFLog(@"Nul table argument supplied");
|
||||
return nil;
|
||||
}
|
||||
|
||||
/* This will be our string. */
|
||||
string = [NSMutableString stringWithCapacity: 0];
|
||||
|
||||
/* Get an enumerator for TABLE. */
|
||||
enumerator = NSEnumerateHashTable(table);
|
||||
|
||||
/* Iterate over the elements of TABLE, appending the description of
|
||||
* each to the mutable string STRING. */
|
||||
while ((element = NSNextHashEnumeratorItem(&enumerator)) != 0)
|
||||
{
|
||||
[string appendFormat: @"%@;\n", (t->extra.describe)(table, element)];
|
||||
}
|
||||
NSEndHashTableEnumeration(&enumerator);
|
||||
return string;
|
||||
return (BOOL)(uintptr_t)[self subclassResponsibility: _cmd];
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* These are to increase readabilty locally. */
|
||||
typedef unsigned int (*NSHT_hash_func_t)(NSHashTable *, const void *);
|
||||
typedef BOOL (*NSHT_isEqual_func_t)(NSHashTable *, const void *, const void *);
|
||||
typedef void (*NSHT_retain_func_t)(NSHashTable *, const void *);
|
||||
typedef void (*NSHT_release_func_t)(NSHashTable *, void *);
|
||||
typedef NSString *(*NSHT_describe_func_t)(NSHashTable *, const void *);
|
||||
|
||||
/** For sets of pointer-sized or smaller quantities. */
|
||||
const NSHashTableCallBacks NSIntHashCallBacks =
|
||||
- (id) member: (id)object
|
||||
{
|
||||
(NSHT_hash_func_t) _NS_int_hash,
|
||||
(NSHT_isEqual_func_t) _NS_int_is_equal,
|
||||
(NSHT_retain_func_t) _NS_int_retain,
|
||||
(NSHT_release_func_t) _NS_int_release,
|
||||
(NSHT_describe_func_t) _NS_int_describe
|
||||
};
|
||||
return [self subclassResponsibility: _cmd];
|
||||
}
|
||||
|
||||
/** For sets of pointers hashed by address. */
|
||||
const NSHashTableCallBacks NSNonOwnedPointerHashCallBacks =
|
||||
- (void) minusHashTable: (NSHashTable*)other
|
||||
{
|
||||
(NSHT_hash_func_t) _NS_non_owned_void_p_hash,
|
||||
(NSHT_isEqual_func_t) _NS_non_owned_void_p_is_equal,
|
||||
(NSHT_retain_func_t) _NS_non_owned_void_p_retain,
|
||||
(NSHT_release_func_t) _NS_non_owned_void_p_release,
|
||||
(NSHT_describe_func_t) _NS_non_owned_void_p_describe
|
||||
};
|
||||
[self subclassResponsibility: _cmd];
|
||||
}
|
||||
|
||||
/** For sets of objects without retaining and releasing. */
|
||||
const NSHashTableCallBacks NSNonRetainedObjectHashCallBacks =
|
||||
- (NSEnumerator*) objectEnumerator
|
||||
{
|
||||
(NSHT_hash_func_t) _NS_non_retained_id_hash,
|
||||
(NSHT_isEqual_func_t) _NS_non_retained_id_is_equal,
|
||||
(NSHT_retain_func_t) _NS_non_retained_id_retain,
|
||||
(NSHT_release_func_t) _NS_non_retained_id_release,
|
||||
(NSHT_describe_func_t) _NS_non_retained_id_describe
|
||||
};
|
||||
return [self subclassResponsibility: _cmd];
|
||||
}
|
||||
|
||||
/** For sets of objects; similar to [NSSet]. */
|
||||
const NSHashTableCallBacks NSObjectHashCallBacks =
|
||||
- (NSPointerFunctions*) pointerFunctions
|
||||
{
|
||||
(NSHT_hash_func_t) _NS_id_hash,
|
||||
(NSHT_isEqual_func_t) _NS_id_is_equal,
|
||||
(NSHT_retain_func_t) _NS_id_retain,
|
||||
(NSHT_release_func_t) _NS_id_release,
|
||||
(NSHT_describe_func_t) _NS_id_describe
|
||||
};
|
||||
return [self subclassResponsibility: _cmd];
|
||||
}
|
||||
|
||||
/** For sets of pointers with transfer of ownership upon insertion. */
|
||||
const NSHashTableCallBacks NSOwnedPointerHashCallBacks =
|
||||
- (void) removeAllObjects
|
||||
{
|
||||
(NSHT_hash_func_t) _NS_owned_void_p_hash,
|
||||
(NSHT_isEqual_func_t) _NS_owned_void_p_is_equal,
|
||||
(NSHT_retain_func_t) _NS_owned_void_p_retain,
|
||||
(NSHT_release_func_t) _NS_owned_void_p_release,
|
||||
(NSHT_describe_func_t) _NS_owned_void_p_describe
|
||||
};
|
||||
[self subclassResponsibility: _cmd];
|
||||
}
|
||||
|
||||
/** For sets of pointers to structs when the first field of the
|
||||
* struct is the size of an int. */
|
||||
const NSHashTableCallBacks NSPointerToStructHashCallBacks =
|
||||
- (void) removeObject: (id)aKey
|
||||
{
|
||||
(NSHT_hash_func_t) _NS_int_p_hash,
|
||||
(NSHT_isEqual_func_t) _NS_int_p_is_equal,
|
||||
(NSHT_retain_func_t) _NS_int_p_retain,
|
||||
(NSHT_release_func_t) _NS_int_p_release,
|
||||
(NSHT_describe_func_t) _NS_int_p_describe
|
||||
};
|
||||
[self subclassResponsibility: _cmd];
|
||||
}
|
||||
|
||||
- (NSSet*) setRepresentation
|
||||
{
|
||||
return [self subclassResponsibility: _cmd];
|
||||
}
|
||||
|
||||
- (void) unionHashTable: (NSHashTable*)other
|
||||
{
|
||||
[self subclassResponsibility: _cmd];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
|
|
@ -558,10 +558,10 @@ replacementForClass(Class c)
|
|||
{
|
||||
NSMapEnumerator enumerator = NSEnumerateMapTable(depKeys);
|
||||
NSString *mainKey;
|
||||
NSHashTable dependents;
|
||||
NSHashTable *dependents;
|
||||
|
||||
while (NSNextMapEnumeratorPair(&enumerator, (void **)(&mainKey),
|
||||
&dependents))
|
||||
(void**)&dependents))
|
||||
{
|
||||
NSHashEnumerator dependentKeyEnum;
|
||||
NSString *dependentKey;
|
||||
|
@ -1478,7 +1478,7 @@ replacementForClass(Class c)
|
|||
|
||||
if (keys != nil)
|
||||
{
|
||||
NSHashTable dependents = NSMapGet(keys, aKey);
|
||||
NSHashTable *dependents = NSMapGet(keys, aKey);
|
||||
|
||||
if (dependents != 0)
|
||||
{
|
||||
|
@ -1501,7 +1501,7 @@ replacementForClass(Class c)
|
|||
|
||||
if (keys != nil)
|
||||
{
|
||||
NSHashTable dependents = NSMapGet(keys, aKey);
|
||||
NSHashTable *dependents = NSMapGet(keys, aKey);
|
||||
|
||||
if (dependents != nil)
|
||||
{
|
||||
|
@ -1822,7 +1822,8 @@ triggerChangeNotificationsForDependentKey: (NSString*)dependentKey
|
|||
enumerator = [triggerKeys objectEnumerator];
|
||||
while ((affectingKey = [enumerator nextObject]))
|
||||
{
|
||||
NSHashTable dependentKeys = NSMapGet(affectingKeys, affectingKey);
|
||||
NSHashTable *dependentKeys = NSMapGet(affectingKeys, affectingKey);
|
||||
|
||||
if (!dependentKeys)
|
||||
{
|
||||
dependentKeys = NSCreateHashTable(NSObjectHashCallBacks, 10);
|
||||
|
|
Loading…
Reference in a new issue