mirror of
https://github.com/gnustep/libs-base.git
synced 2025-04-22 16:33:29 +00:00
Add support (and test) for weak keys and values in NSMapTable. This support should work in GC mode. It also works if the runtime supports ARC, even if the compiler does not use this support.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@33617 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
3e3d12b661
commit
bc37adfb0c
4 changed files with 123 additions and 78 deletions
|
@ -109,7 +109,7 @@ extern "C" {
|
|||
*
|
||||
* GSI_MAP_ZEROED()
|
||||
* Define this macro to check whether a map uses keys which may
|
||||
* be zeroed weak pointers. This is only used when GC is enabled.
|
||||
* be zeroed weak pointers.
|
||||
*/
|
||||
|
||||
#ifndef GSI_MAP_HAS_VALUE
|
||||
|
@ -142,13 +142,21 @@ extern "C" {
|
|||
#define GSI_MAP_ZEROED(M) 0
|
||||
#endif
|
||||
#ifndef GSI_MAP_READ_KEY
|
||||
# define GSI_MAP_READ_KEY(x) (*(x))
|
||||
# define GSI_MAP_READ_KEY(M, x) (*(x))
|
||||
#endif
|
||||
#ifndef GSI_MAP_READ_VALUE
|
||||
# define GSI_MAP_READ_VALUE(M, x) (*(x))
|
||||
#endif
|
||||
#ifndef GSI_MAP_WRITE_KEY
|
||||
# define GSI_MAP_WRITE_KEY(addr, obj) (*(addr) = obj)
|
||||
# define GSI_MAP_WRITE_KEY(M, addr, obj) (*(addr) = obj)
|
||||
#endif
|
||||
#ifndef GSI_MAP_WRITE_VAL
|
||||
# define GSI_MAP_WRITE_VAL(addr, obj) (*(addr) = obj)
|
||||
# define GSI_MAP_WRITE_VAL(M, addr, obj) (*(addr) = obj)
|
||||
#endif
|
||||
#if GSI_MAP_HAS_VALUE
|
||||
#define GSI_MAP_NODE_IS_EMPTY(M, node) (((GSI_MAP_READ_VALUE(M, &node->key).addr) == 0) || ((GSI_MAP_READ_VALUE(M, &node->value).addr == 0)))
|
||||
#else
|
||||
#define GSI_MAP_NODE_IS_EMPTY(M, node) (((GSI_MAP_READ_VALUE(M, &node->key).addr) == 0))
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
@ -193,9 +201,9 @@ extern "C" {
|
|||
|
||||
|
||||
#if (GSI_MAP_KTYPES) & GSUNION_OBJ
|
||||
#define GSI_MAP_CLEAR_KEY(node) GSI_MAP_WRITE_KEY(&node->key.obj, nil)
|
||||
#define GSI_MAP_CLEAR_KEY(node) GSI_MAP_WRITE_KEY(map, &node->key, (GSIMapKey)nil)
|
||||
#elif (GSI_MAP_KTYPES) & GSUNION_PTR
|
||||
#define GSI_MAP_CLEAR_KEY(node) GSI_MAP_WRITE_KEY(&node->key.ptr, 0)
|
||||
#define GSI_MAP_CLEAR_KEY(node) GSI_MAP_WRITE_KEY(map, &node->key, (GSIMapKey)NULL)
|
||||
#else
|
||||
#define GSI_MAP_CLEAR_KEY(node)
|
||||
#endif
|
||||
|
@ -245,9 +253,9 @@ extern "C" {
|
|||
#endif
|
||||
|
||||
#if (GSI_MAP_VTYPES) & GSUNION_OBJ
|
||||
#define GSI_MAP_CLEAR_VAL(node) GSI_MAP_WRITE_VAL(&node->value.obj, nil)
|
||||
#define GSI_MAP_CLEAR_VAL(node) GSI_MAP_WRITE_VAL(map, &node->value, (GSIMapVal)nil)
|
||||
#elif (GSI_MAP_VTYPES) & GSUNION_PTR
|
||||
#define GSI_MAP_CLEAR_VAL(node) GSI_MAP_WRITE_VAL(&node->value.ptr, 0)
|
||||
#define GSI_MAP_CLEAR_VAL(node) GSI_MAP_WRITE_VAL(map, &node->value, (GSIMapVal)NULL)
|
||||
#else
|
||||
#define GSI_MAP_CLEAR_VAL(node)
|
||||
#endif
|
||||
|
@ -478,7 +486,6 @@ GSIMapRemangleBuckets(GSIMapTable map,
|
|||
GSIMapBucket old_buckets, uintptr_t old_bucketCount,
|
||||
GSIMapBucket new_buckets, uintptr_t new_bucketCount)
|
||||
{
|
||||
#if GS_WITH_GC
|
||||
if (GSI_MAP_ZEROED(map))
|
||||
{
|
||||
while (old_bucketCount-- > 0)
|
||||
|
@ -487,7 +494,7 @@ GSIMapRemangleBuckets(GSIMapTable map,
|
|||
|
||||
while ((node = old_buckets->firstNode) != 0)
|
||||
{
|
||||
if (node->key.addr == 0)
|
||||
if (GSI_MAP_NODE_IS_EMPTY(map, node))
|
||||
{
|
||||
GSIMapRemoveNodeFromMap(map, old_buckets, node);
|
||||
GSIMapFreeNode(map, node);
|
||||
|
@ -506,7 +513,6 @@ GSIMapRemangleBuckets(GSIMapTable map,
|
|||
}
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
while (old_bucketCount-- > 0)
|
||||
{
|
||||
GSIMapNode node;
|
||||
|
@ -592,14 +598,13 @@ GSIMapNodeForKeyInBucket(GSIMapTable map, GSIMapBucket bucket, GSIMapKey key)
|
|||
{
|
||||
GSIMapNode node = bucket->firstNode;
|
||||
|
||||
#if GS_WITH_GC
|
||||
if (GSI_MAP_ZEROED(map))
|
||||
{
|
||||
while ((node != 0) && GSI_MAP_EQUAL(map, GSI_MAP_READ_KEY(&node->key), key) == NO)
|
||||
while ((node != 0) && GSI_MAP_EQUAL(map, GSI_MAP_READ_KEY(map, &node->key), key) == NO)
|
||||
{
|
||||
GSIMapNode tmp = node->nextInBucket;
|
||||
|
||||
if (GSI_MAP_READ_KEY(&node->key).addr == 0)
|
||||
if (GSI_MAP_NODE_IS_EMPTY(map, node))
|
||||
{
|
||||
GSIMapRemoveNodeFromMap(map, bucket, node);
|
||||
GSIMapFreeNode(map, node);
|
||||
|
@ -608,8 +613,7 @@ GSIMapNodeForKeyInBucket(GSIMapTable map, GSIMapBucket bucket, GSIMapKey key)
|
|||
}
|
||||
return node;
|
||||
}
|
||||
#endif
|
||||
while ((node != 0) && GSI_MAP_EQUAL(map, GSI_MAP_READ_KEY(&node->key), key) == NO)
|
||||
while ((node != 0) && GSI_MAP_EQUAL(map, GSI_MAP_READ_KEY(map, &node->key), key) == NO)
|
||||
{
|
||||
node = node->nextInBucket;
|
||||
}
|
||||
|
@ -640,13 +644,12 @@ GSIMapFirstNode(GSIMapTable map)
|
|||
uintptr_t bucket = 0;
|
||||
GSIMapNode node = 0;
|
||||
|
||||
#if GS_WITH_GC
|
||||
if (GSI_MAP_ZEROED(map))
|
||||
{
|
||||
while (bucket < count)
|
||||
{
|
||||
node = map->buckets[bucket].firstNode;
|
||||
while (node != 0 && GSI_MAP_READ_KEY(&node->key).addr == 0)
|
||||
while (node != 0 && GSI_MAP_NODE_IS_EMPTY(map, node))
|
||||
{
|
||||
node = GSIMapRemoveAndFreeNode(map, bucket, node);
|
||||
}
|
||||
|
@ -658,7 +661,6 @@ GSIMapFirstNode(GSIMapTable map)
|
|||
}
|
||||
return node;
|
||||
}
|
||||
#endif
|
||||
while (bucket < count)
|
||||
{
|
||||
node = map->buckets[bucket].firstNode;
|
||||
|
@ -694,14 +696,13 @@ GSIMapNodeForSimpleKey(GSIMapTable map, GSIMapKey key)
|
|||
}
|
||||
bucket = map->buckets + ((unsigned)key.addr) % map->bucketCount;
|
||||
node = bucket->firstNode;
|
||||
#if GS_WITH_GC
|
||||
if (GSI_MAP_ZEROED(map))
|
||||
{
|
||||
while ((node != 0) && GSI_MAP_READ_KEY(&node->key).addr != key.addr)
|
||||
while ((node != 0) && GSI_MAP_READ_KEY(map, &node->key).addr != key.addr)
|
||||
{
|
||||
GSIMapNode tmp = node->nextInBucket;
|
||||
|
||||
if (GSI_MAP_READ_KEY(&node->key).addr == 0)
|
||||
if (GSI_MAP_NODE_IS_EMPTY(map, node))
|
||||
{
|
||||
GSIMapRemoveNodeFromMap(map, bucket, node);
|
||||
GSIMapFreeNode(map, node);
|
||||
|
@ -710,8 +711,7 @@ GSIMapNodeForSimpleKey(GSIMapTable map, GSIMapKey key)
|
|||
}
|
||||
return node;
|
||||
}
|
||||
#endif
|
||||
while ((node != 0) && GSI_MAP_READ_KEY(&node->key).addr != key.addr)
|
||||
while ((node != 0) && GSI_MAP_READ_KEY(map, &node->key).addr != key.addr)
|
||||
{
|
||||
node = node->nextInBucket;
|
||||
}
|
||||
|
@ -820,14 +820,13 @@ GSIMapEnumeratorForMap(GSIMapTable map)
|
|||
/*
|
||||
* Locate next bucket and node to be returned.
|
||||
*/
|
||||
#if GS_WITH_GC
|
||||
if (GSI_MAP_ZEROED(map))
|
||||
{
|
||||
while (enumerator.bucket < map->bucketCount)
|
||||
{
|
||||
GSIMapNode node = map->buckets[enumerator.bucket].firstNode;
|
||||
|
||||
while (node != 0 && GSI_MAP_READ_KEY(&node->key).addr == 0)
|
||||
while (node != 0 && GSI_MAP_READ_KEY(map, &node->key).addr == 0)
|
||||
{
|
||||
node = GSIMapRemoveAndFreeNode(map, enumerator.bucket, node);
|
||||
}
|
||||
|
@ -838,7 +837,6 @@ GSIMapEnumeratorForMap(GSIMapTable map)
|
|||
enumerator.bucket++;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
while (enumerator.bucket < map->bucketCount)
|
||||
{
|
||||
enumerator.node = map->buckets[enumerator.bucket].firstNode;
|
||||
|
@ -890,21 +888,20 @@ GSIMapEnumeratorNextNode(GSIMapEnumerator enumerator)
|
|||
GSIMapNode node = ((_GSIE)enumerator)->node;
|
||||
GSIMapTable map = ((_GSIE)enumerator)->map;
|
||||
|
||||
#if GS_WITH_GC
|
||||
/* Find the frst available non-zeroed node.
|
||||
*/
|
||||
if (node != 0 && GSI_MAP_ZEROED(map) && GSI_MAP_READ_KEY(&node->key).addr == 0)
|
||||
if (node != 0 && GSI_MAP_ZEROED(map) && GSI_MAP_READ_KEY(map, &node->key).addr == 0)
|
||||
{
|
||||
uintptr_t bucketCount = map->bucketCount;
|
||||
uintptr_t bucket = ((_GSIE)enumerator)->bucket;
|
||||
|
||||
while (node != 0 && GSI_MAP_READ_KEY(&node->key).addr == 0)
|
||||
while (node != 0 && GSI_MAP_READ_KEY(map, &node->key).addr == 0)
|
||||
{
|
||||
node = GSIMapRemoveAndFreeNode(map, bucket, node);
|
||||
while (node == 0 && ++bucket < bucketCount)
|
||||
{
|
||||
node = (map->buckets[bucket]).firstNode;
|
||||
while (node != 0 && GSI_MAP_READ_KEY(&node->key).addr == 0)
|
||||
while (node != 0 && GSI_MAP_READ_KEY(map, &node->key).addr == 0)
|
||||
{
|
||||
node = GSIMapRemoveAndFreeNode(map, bucket, node);
|
||||
}
|
||||
|
@ -913,13 +910,11 @@ GSIMapEnumeratorNextNode(GSIMapEnumerator enumerator)
|
|||
((_GSIE)enumerator)->node = node;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (node != 0)
|
||||
{
|
||||
GSIMapNode next = node->nextInBucket;
|
||||
|
||||
#if GS_WITH_GC
|
||||
if (GSI_MAP_ZEROED(map))
|
||||
{
|
||||
uintptr_t bucket = ((_GSIE)enumerator)->bucket;
|
||||
|
@ -929,14 +924,12 @@ GSIMapEnumeratorNextNode(GSIMapEnumerator enumerator)
|
|||
next = GSIMapRemoveAndFreeNode(map, bucket, next);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (next == 0)
|
||||
{
|
||||
uintptr_t bucketCount = map->bucketCount;
|
||||
uintptr_t bucket = ((_GSIE)enumerator)->bucket;
|
||||
|
||||
#if GS_WITH_GC
|
||||
if (GSI_MAP_ZEROED(map))
|
||||
{
|
||||
while (next == 0 && ++bucket < bucketCount)
|
||||
|
@ -951,7 +944,6 @@ GSIMapEnumeratorNextNode(GSIMapEnumerator enumerator)
|
|||
((_GSIE)enumerator)->node = next;
|
||||
return node;
|
||||
}
|
||||
#endif
|
||||
while (next == 0 && ++bucket < bucketCount)
|
||||
{
|
||||
next = (map->buckets[bucket]).firstNode;
|
||||
|
@ -1011,7 +1003,7 @@ GSIMapCountByEnumeratingWithStateObjectsCount(GSIMapTable map,
|
|||
* will only work with things that are id-sized, however, so don't
|
||||
* try using it with non-object collections.
|
||||
*/
|
||||
stackbuf[i] = *(id*)(void*)&GSI_MAP_READ_KEY(&node->key).addr;
|
||||
stackbuf[i] = (id)GSI_MAP_READ_KEY(map, &node->key).addr;
|
||||
}
|
||||
}
|
||||
/* Store the important bits of the enumerator in the caller. */
|
||||
|
@ -1039,8 +1031,8 @@ GSIMapAddPairNoRetain(GSIMapTable map, GSIMapKey key, GSIMapVal value)
|
|||
}
|
||||
}
|
||||
map->freeNodes = node->nextInBucket;
|
||||
GSI_MAP_WRITE_KEY(&node->key, key);
|
||||
GSI_MAP_WRITE_VAL(&node->value, value);
|
||||
GSI_MAP_WRITE_KEY(map, &node->key, key);
|
||||
GSI_MAP_WRITE_VAL(map, &node->value, value);
|
||||
node->nextInBucket = 0;
|
||||
GSIMapRightSizeMap(map, map->nodeCount);
|
||||
GSIMapAddNodeToMap(map, node);
|
||||
|
@ -1062,9 +1054,9 @@ GSIMapAddPair(GSIMapTable map, GSIMapKey key, GSIMapVal value)
|
|||
}
|
||||
}
|
||||
map->freeNodes = node->nextInBucket;
|
||||
GSI_MAP_WRITE_KEY(&node->key, key);
|
||||
GSI_MAP_WRITE_KEY(map, &node->key, key);
|
||||
GSI_MAP_RETAIN_KEY(map, node->key);
|
||||
GSI_MAP_WRITE_VAL(&node->value, value);
|
||||
GSI_MAP_WRITE_VAL(map, &node->value, value);
|
||||
GSI_MAP_RETAIN_VAL(map, node->value);
|
||||
node->nextInBucket = 0;
|
||||
GSIMapRightSizeMap(map, map->nodeCount);
|
||||
|
@ -1087,7 +1079,7 @@ GSIMapAddKeyNoRetain(GSIMapTable map, GSIMapKey key)
|
|||
}
|
||||
}
|
||||
map->freeNodes = node->nextInBucket;
|
||||
GSI_MAP_WRITE_KEY(&node->key, node->key);
|
||||
GSI_MAP_WRITE_KEY(map, &node->key, node->key);
|
||||
node->nextInBucket = 0;
|
||||
GSIMapRightSizeMap(map, map->nodeCount);
|
||||
GSIMapAddNodeToMap(map, node);
|
||||
|
@ -1109,7 +1101,7 @@ GSIMapAddKey(GSIMapTable map, GSIMapKey key)
|
|||
}
|
||||
}
|
||||
map->freeNodes = node->nextInBucket;
|
||||
GSI_MAP_WRITE_KEY(&node->key, key);
|
||||
GSI_MAP_WRITE_KEY(map, &node->key, key);
|
||||
GSI_MAP_RETAIN_KEY(map, node->key);
|
||||
node->nextInBucket = 0;
|
||||
GSIMapRightSizeMap(map, map->nodeCount);
|
||||
|
|
|
@ -97,10 +97,28 @@ typedef GSIMapNode_t *GSIMapNode;
|
|||
#define GSI_MAP_RETAIN_VAL(M, X)\
|
||||
(M->legacy ? M->cb.old.v.retain(M, X.ptr) \
|
||||
: pointerFunctionsAcquire(&M->cb.pf.v, &X.ptr, X.ptr))
|
||||
|
||||
#define GSI_MAP_WRITE_KEY(M, addr, x) \
|
||||
if (M->legacy) \
|
||||
*(addr) = x;\
|
||||
else\
|
||||
pointerFunctionsAssign(&M->cb.pf.k, (void**)addr, (x).obj);
|
||||
#define GSI_MAP_WRITE_VAL(M, addr, x) \
|
||||
if (M->legacy) \
|
||||
*(addr) = x;\
|
||||
else\
|
||||
pointerFunctionsAssign(&M->cb.pf.v, (void**)addr, (x).obj);
|
||||
#define GSI_MAP_READ_KEY(M,addr) \
|
||||
(M->legacy ? *(addr) :\
|
||||
(typeof(*addr))pointerFunctionsRead(&M->cb.pf.k, (void**)addr))
|
||||
#define GSI_MAP_READ_VALUE(M,addr) \
|
||||
(M->legacy ? *(addr) :\
|
||||
(typeof(*addr))pointerFunctionsRead(&M->cb.pf.v, (void**)addr))
|
||||
#define GSI_MAP_ZEROED(M)\
|
||||
(M->legacy ? 0 \
|
||||
: ((M->cb.pf.k.options & NSPointerFunctionsZeroingWeakMemory) ? YES : NO))
|
||||
|
||||
|
||||
#define GSI_MAP_ENUMERATOR NSMapEnumerator
|
||||
|
||||
#if GS_WITH_GC
|
||||
|
@ -1183,6 +1201,10 @@ const NSMapTableValueCallBacks NSOwnedPointerMapValueCallBacks =
|
|||
|
||||
- (NSUInteger) count
|
||||
{
|
||||
if (!legacy && (cb.pf.k.options | cb.pf.v.options) & NSPointerFunctionsZeroingWeakMemory)
|
||||
{
|
||||
GSIMapCleanMap(self);
|
||||
}
|
||||
return (NSUInteger)nodeCount;
|
||||
}
|
||||
|
||||
|
|
|
@ -24,10 +24,38 @@
|
|||
*/
|
||||
|
||||
#import "Foundation/NSPointerFunctions.h"
|
||||
#if __OBJC_GC__
|
||||
#include <objc/objc-auto.h>
|
||||
|
||||
#ifdef __GNUSTEP_RUNTIME__
|
||||
# include <objc/capabilities.h>
|
||||
#endif
|
||||
|
||||
// Define a weak read barrier macro for ARC or GC, depending on which one this
|
||||
// target supports. If this target doesn't support zeroing weak references,
|
||||
// then use an unsafe unretained access.
|
||||
#if __OBJC_GC__
|
||||
# include <objc/objc-auto.h>
|
||||
# define WEAK_READ(x) objc_read_weak((id*)x)
|
||||
# define WEAK_WRITE(addr, x) objc_assign_weak((id)x, (id*)addr)
|
||||
# define STRONG_WRITE(addr, x) objc_assign_strongCast((id)x, (id*)addr)
|
||||
# define STRONG_ACQUIRE(x) x
|
||||
#elif defined(OBJC_CAP_ARC)
|
||||
# include <objc/objc-arc.h>
|
||||
# define WEAK_READ(x) objc_loadWeak((id*)x)
|
||||
# define WEAK_WRITE(addr, x) objc_storeWeak((id*)addr, (id)x)
|
||||
# define STRONG_WRITE(addr, x) objc_storeStrong((id*)addr, (id)x)
|
||||
# define STRONG_ACQUIRE(x) objc_retain(x)
|
||||
#else
|
||||
# define WEAK_READ(x) (*x)
|
||||
# if GS_WITH_GC
|
||||
# define WEAK_WRITE(addr, x) GSAssignZeroingWeakPointer(addr, x)
|
||||
# else
|
||||
# define WEAK_WRITE(addr, x) (*(addr) = x)
|
||||
# endif
|
||||
# define STRONG_WRITE(addr, x) ASSIGN(*(addr), x)
|
||||
# define STRONG_ACQUIRE(x) RETAIN(x)
|
||||
#endif
|
||||
|
||||
|
||||
/* Declare a structure type to copy pointer functions information
|
||||
* around easily.
|
||||
*/
|
||||
|
@ -68,29 +96,13 @@ typedef struct
|
|||
|
||||
/* Acquire the pointer value to store for the specified item.
|
||||
*/
|
||||
static inline void
|
||||
static inline void *
|
||||
pointerFunctionsAcquire(PFInfo *PF, void **dst, void *src)
|
||||
{
|
||||
if (PF->acquireFunction != 0)
|
||||
src = (*PF->acquireFunction)(src, PF->sizeFunction,
|
||||
PF->options & NSPointerFunctionsCopyIn ? YES : NO);
|
||||
#if __OBJC_GC__
|
||||
if (PF->options & NSPointerFunctionsZeroingWeakMemory)
|
||||
{
|
||||
objc_assign_weak((id)src, (id*)dst);
|
||||
}
|
||||
else
|
||||
{
|
||||
objc_assign_strongCast((id)src, (id*)dst);
|
||||
}
|
||||
#else
|
||||
#if GS_WITH_GC
|
||||
if (PF->options & NSPointerFunctionsZeroingWeakMemory)
|
||||
GSAssignZeroingWeakPointer(dst, src);
|
||||
else
|
||||
#endif
|
||||
*dst = src;
|
||||
#endif
|
||||
return src;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -99,12 +111,10 @@ pointerFunctionsAcquire(PFInfo *PF, void **dst, void *src)
|
|||
*/
|
||||
static inline void *pointerFunctionsRead(PFInfo *PF, void **addr)
|
||||
{
|
||||
#if __OBJC_GC__
|
||||
if (PF->options & NSPointerFunctionsZeroingWeakMemory)
|
||||
{
|
||||
return objc_read_weak((id*)addr);
|
||||
return WEAK_READ((id*)addr);
|
||||
}
|
||||
#endif
|
||||
return *addr;
|
||||
}
|
||||
|
||||
|
@ -113,21 +123,18 @@ static inline void *pointerFunctionsRead(PFInfo *PF, void **addr)
|
|||
*/
|
||||
static inline void pointerFunctionsAssign(PFInfo *PF, void **addr, void *value)
|
||||
{
|
||||
#if __OBJC_GC__
|
||||
if (PF->options & NSPointerFunctionsZeroingWeakMemory)
|
||||
{
|
||||
objc_assign_weak(value, (id*)addr);
|
||||
WEAK_WRITE(addr, value);
|
||||
}
|
||||
else if (PF->options & NSPointerFunctionsStrongMemory)
|
||||
{
|
||||
STRONG_WRITE(addr, value);
|
||||
}
|
||||
else
|
||||
{
|
||||
objc_assign_strongCast(value, (id*)addr);
|
||||
*addr = value;
|
||||
}
|
||||
#elif GS_WITH_GC
|
||||
if (PF->options & NSPointerFunctionsZeroingWeakMemory)
|
||||
GSAssignZeroingWeakPointer(addr, value);
|
||||
#else
|
||||
*addr = value;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -179,6 +186,7 @@ pointerFunctionsEqual(PFInfo *PF, void *item1, void *item2)
|
|||
static inline void
|
||||
pointerFunctionsRelinquish(PFInfo *PF, void **itemptr)
|
||||
{
|
||||
|
||||
if (PF->relinquishFunction != 0)
|
||||
(*PF->relinquishFunction)(*itemptr, PF->sizeFunction);
|
||||
if (PF->options & NSPointerFunctionsZeroingWeakMemory)
|
||||
|
@ -198,11 +206,9 @@ pointerFunctionsReplace(PFInfo *PF, void **dst, void *src)
|
|||
PF->options & NSPointerFunctionsCopyIn ? YES : NO);
|
||||
if (PF->relinquishFunction != 0)
|
||||
(*PF->relinquishFunction)(*dst, PF->sizeFunction);
|
||||
#if GS_WITH_GC
|
||||
if (PF->options & NSPointerFunctionsZeroingWeakMemory)
|
||||
GSAssignZeroingWeakPointer(dst, src);
|
||||
WEAK_WRITE(dst, src);
|
||||
else
|
||||
#endif
|
||||
*dst = src;
|
||||
}
|
||||
}
|
||||
|
|
25
Tests/base/NSMapTable/weak.m
Normal file
25
Tests/base/NSMapTable/weak.m
Normal file
|
@ -0,0 +1,25 @@
|
|||
#import "ObjectTesting.h"
|
||||
#import <Foundation/NSAutoreleasePool.h>
|
||||
#import <Foundation/NSMapTable.h>
|
||||
|
||||
int main()
|
||||
{
|
||||
[NSAutoreleasePool new];
|
||||
NSMapTable *map = [NSMapTable mapTableWithStrongToWeakObjects];
|
||||
NSMapTable *map2 = [NSMapTable mapTableWithWeakToStrongObjects];
|
||||
id obj = [NSObject new];
|
||||
|
||||
[map setObject: obj forKey: @"1"];
|
||||
[map2 setObject: @"1" forKey: obj];
|
||||
PASS(obj == [map objectForKey: @"1"], "Value stored in weak-value map");
|
||||
PASS(nil != [map2 objectForKey: obj], "Value stored in weak-key map");
|
||||
[obj release];
|
||||
PASS(nil == [map objectForKey: @"1"], "Value removed from weak-value map");
|
||||
NSEnumerator *enumerator = [map2 keyEnumerator];
|
||||
NSUInteger count = 0;
|
||||
while ([enumerator nextObject] != nil) { count++; }
|
||||
PASS(count == 0, "Value removed from weak-key map");
|
||||
PASS(0 == [map count], "Weak-value map reports correct count");
|
||||
PASS(0 == [map2 count], "Weak-key map reports correct count");
|
||||
return 0;
|
||||
}
|
Loading…
Reference in a new issue