Fix the case where we replace a value already in the map

This commit is contained in:
rfm 2024-11-12 14:27:06 +00:00
parent b78b2e2030
commit 28ba7788ce
4 changed files with 84 additions and 11 deletions

View file

@ -457,11 +457,20 @@ NSHashInsert(NSHashTable *table, const void *element)
GSIMapAddKey(t, (GSIMapKey)element);
((NSConcreteHashTable*)table)->version++;
}
else if (element != n->key.ptr)
{
GSI_MAP_RELEASE_KEY(t, n->key);
n->key = (GSIMapKey)element;
GSI_MAP_RETAIN_KEY(t, n->key);
else if (GSI_MAP_READ_KEY(t, &n->key).ptr != element)
{
if (t->legacy)
{
t->cb.old.release(t, n->key.ptr);
n->key = (GSIMapKey)element;
t->cb.old.retain(t, n->key.ptr);
}
else
{
pointerFunctionsRelinquish(&t->cb.pf, (void**)&n->key);
pointerFunctionsReplace(&t->cb.pf, (void**)&n->key,
(void*)element);
}
((NSConcreteHashTable*)table)->version++;
}
}
@ -854,11 +863,19 @@ const NSHashTableCallBacks NSPointerToStructHashCallBacks =
GSIMapAddKey(t, (GSIMapKey)anObject);
version++;
}
else if (n->key.obj != anObject)
else if (GSI_MAP_READ_KEY(t, &n->key).ptr != anObject)
{
GSI_MAP_RELEASE_KEY(t, n->key);
n->key = (GSIMapKey)anObject;
GSI_MAP_RETAIN_KEY(t, n->key);
if (t->legacy)
{
t->cb.old.release(t, n->key.ptr);
n->key.ptr = anObject;
t->cb.old.retain(t, n->key.ptr);
}
else
{
pointerFunctionsRelinquish(&t->cb.pf, (void**)&n->key);
pointerFunctionsReplace(&t->cb.pf, (void**)&n->key, (void*)anObject);
}
version++;
}
}

View file

@ -641,7 +641,18 @@ NSMapInsert(NSMapTable *table, const void *key, const void *value)
}
else if (GSI_MAP_READ_VALUE(t, &n->value).ptr != value)
{
GSI_MAP_STORE_VALUE(t, &n->value, (GSIMapVal)value);
if (t->legacy)
{
t->cb.old.v.release(t, n->value.ptr);
n->value = (GSIMapVal)value;
t->cb.old.v.retain(t, n->value.ptr);
}
else
{
pointerFunctionsRelinquish(&t->cb.pf.v, (void**)&n->value);
pointerFunctionsReplace(&t->cb.pf.v, (void**)&n->value,
(void*)value);
}
t->version++;
}
}
@ -1380,7 +1391,18 @@ const NSMapTableValueCallBacks NSOwnedPointerMapValueCallBacks =
{
if (GSI_MAP_READ_VALUE(self, &node->value).obj != anObject)
{
GSI_MAP_STORE_VALUE(self, &node->value, (GSIMapVal)anObject);
if (self->legacy)
{
self->cb.old.v.release(self, node->value.ptr);
node->value = (GSIMapVal)anObject;
self->cb.old.v.retain(self, node->value.ptr);
}
else
{
pointerFunctionsRelinquish(&self->cb.pf.v, (void**)&node->value);
pointerFunctionsReplace(&self->cb.pf.v, (void**)&node->value,
(void*)anObject);
}
version++;
}
}

View file

@ -6,6 +6,14 @@
@end
@implementation MyClass
- (NSUInteger) hash
{
return 42;
}
- (BOOL) isEqual: (id)other
{
return [other isKindOfClass: [self class]];
}
#if 0
- (oneway void) release
{
@ -27,6 +35,7 @@ int main()
NSAutoreleasePool *arp = [NSAutoreleasePool new];
NSHashTable *t;
MyClass *o;
MyClass *o2;
int c;
t = [[NSHashTable alloc] initWithOptions: NSHashTableObjectPointerPersonality
@ -63,8 +72,17 @@ int main()
[t removeObject: o];
PASS([o retainCount] == c, "remove from hash table decrements retain count")
o2 = [MyClass new];
PASS([o2 retainCount] == 1, "initial retain count of second object OK")
[t addObject: o];
[t addObject: o2];
PASS([o retainCount] == 1, "first object was removed")
PASS([o2 retainCount] == 2, "second object was added")
RELEASE(t);
RELEASE(o);
RELEASE(o2);
[arp release]; arp = nil;
return 0;

View file

@ -6,6 +6,14 @@
@end
@implementation MyClass
- (NSUInteger) hash
{
return 42;
}
- (BOOL) isEqual: (id)other
{
return [other isKindOfClass: [self class]];
}
#if 0
- (oneway void) release
{
@ -27,6 +35,7 @@ int main()
NSAutoreleasePool *arp = [NSAutoreleasePool new];
NSMapTable *t;
MyClass *o;
MyClass *o2;
int c;
t = [[NSMapTable alloc] initWithKeyOptions: NSMapTableObjectPointerPersonality
@ -78,8 +87,15 @@ int main()
[t removeObjectForKey: @"a"];
PASS([o retainCount] == c, "remove map table val decrements retain count")
[t setObject: o forKey: @"a"];
o2 = [MyClass new];
[t setObject: o2 forKey: @"a"];
PASS([o retainCount] == 1, "old instance removed")
PASS([o2 retainCount] == 2, "new instance added")
RELEASE(t);
RELEASE(o);
RELEASE(o2);
[arp release]; arp = nil;
return 0;