Index: src/OFMapTable.h ================================================================== --- src/OFMapTable.h +++ src/OFMapTable.h @@ -72,11 +72,11 @@ @interface OFMapTable: OFObject { OFMapTableFunctions _keyFunctions, _objectFunctions; struct OFMapTableBucket *_Nonnull *_Nullable _buckets; uint32_t _count, _capacity; - unsigned char _rotate; + unsigned char _rotation; unsigned long _mutations; } /** * @brief The key functions used by the map table. Index: src/OFMapTable.m ================================================================== --- src/OFMapTable.m +++ src/OFMapTable.m @@ -155,11 +155,11 @@ _capacity = minCapacity; _buckets = OFAllocZeroedMemory(_capacity, sizeof(*_buckets)); if (OFHashSeed != 0) - _rotate = OFRandom16() & 31; + _rotation = OFRandom16() & 31; } @catch (id e) { [self release]; @throw e; } @@ -185,10 +185,11 @@ static void resizeForCount(OFMapTable *self, uint32_t count) { uint32_t fullness, capacity; struct OFMapTableBucket **buckets; + unsigned char newRotation; if (count > UINT32_MAX / sizeof(*self->_buckets) || count > UINT32_MAX / 8) @throw [OFOutOfRangeException exception]; @@ -211,24 +212,27 @@ if ((capacity < self->_capacity && count > self->_count) || capacity < minCapacity) return; buckets = OFAllocZeroedMemory(capacity, sizeof(*buckets)); + newRotation = (OFHashSeed != 0 ? OFRandom16() & 31 : 0); for (uint32_t i = 0; i < self->_capacity; i++) { if (self->_buckets[i] != NULL && self->_buckets[i] != &deletedBucket) { - uint32_t j, last; + uint32_t rotatedHash, j, last; + rotatedHash = OFRotateLeft(self->_buckets[i]->hash, + newRotation); last = capacity; - for (j = self->_buckets[i]->hash & (capacity - 1); + for (j = rotatedHash & (capacity - 1); j < last && buckets[j] != NULL; j++); /* In case the last bucket is already used */ if (j >= last) { - last = self->_buckets[i]->hash & (capacity - 1); + last = rotatedHash & (capacity - 1); for (j = 0; j < last && buckets[j] != NULL; j++); } @@ -240,25 +244,26 @@ } OFFreeMemory(self->_buckets); self->_buckets = buckets; self->_capacity = capacity; + self->_rotation = newRotation; } static void setObject(OFMapTable *restrict self, void *key, void *object, uint32_t hash) { - uint32_t i, last; + uint32_t rotatedHash, i, last; void *old; if (key == NULL || object == NULL) @throw [OFInvalidArgumentException exception]; - hash = OFRotateLeft(hash, self->_rotate); + rotatedHash = OFRotateLeft(hash, self->_rotation); last = self->_capacity; - for (i = hash & (self->_capacity - 1); + for (i = rotatedHash & (self->_capacity - 1); i < last && self->_buckets[i] != NULL; i++) { if (self->_buckets[i] == &deletedBucket) continue; if (self->_keyFunctions.equal(self->_buckets[i]->key, key)) @@ -265,11 +270,11 @@ break; } /* In case the last bucket is already used */ if (i >= last) { - last = hash & (self->_capacity - 1); + last = rotatedHash & (self->_capacity - 1); for (i = 0; i < last && self->_buckets[i] != NULL; i++) { if (self->_buckets[i] == &deletedBucket) continue; @@ -284,21 +289,23 @@ self->_buckets[i] == &deletedBucket || !self->_keyFunctions.equal(self->_buckets[i]->key, key)) { struct OFMapTableBucket *bucket; resizeForCount(self, self->_count + 1); + /* Resizing can change the rotation */ + rotatedHash = OFRotateLeft(hash, self->_rotation); self->_mutations++; last = self->_capacity; - for (i = hash & (self->_capacity - 1); i < last && + for (i = rotatedHash & (self->_capacity - 1); i < last && self->_buckets[i] != NULL && self->_buckets[i] != &deletedBucket; i++); /* In case the last bucket is already used */ if (i >= last) { - last = hash & (self->_capacity - 1); + last = rotatedHash & (self->_capacity - 1); for (i = 0; i < last && self->_buckets[i] != NULL && self->_buckets[i] != &deletedBucket; i++); } @@ -370,11 +377,11 @@ { unsigned long hash = 0; for (unsigned long i = 0; i < _capacity; i++) { if (_buckets[i] != NULL && _buckets[i] != &deletedBucket) { - hash ^= OFRotateRight(_buckets[i]->hash, _rotate); + hash ^= _buckets[i]->hash; hash ^= _objectFunctions.hash(_buckets[i]->object); } } return hash; @@ -390,12 +397,11 @@ @try { for (uint32_t i = 0; i < _capacity; i++) if (_buckets[i] != NULL && _buckets[i] != &deletedBucket) setObject(copy, _buckets[i]->key, - _buckets[i]->object, - OFRotateRight(_buckets[i]->hash, _rotate)); + _buckets[i]->object, _buckets[i]->hash); } @catch (id e) { [copy release]; @throw e; } @@ -407,19 +413,21 @@ return _count; } - (void *)objectForKey: (void *)key { - uint32_t i, hash, last; + uint32_t i, rotatedHash, last; if (key == NULL) @throw [OFInvalidArgumentException exception]; - hash = OFRotateLeft((uint32_t)_keyFunctions.hash(key), _rotate); + rotatedHash = OFRotateLeft((uint32_t)_keyFunctions.hash(key), + _rotation); last = _capacity; - for (i = hash & (_capacity - 1); i < last && _buckets[i] != NULL; i++) { + for (i = rotatedHash & (_capacity - 1); + i < last && _buckets[i] != NULL; i++) { if (_buckets[i] == &deletedBucket) continue; if (_keyFunctions.equal(_buckets[i]->key, key)) return _buckets[i]->object; @@ -427,11 +435,11 @@ if (i < last) return nil; /* In case the last bucket is already used */ - last = hash & (_capacity - 1); + last = rotatedHash & (_capacity - 1); for (i = 0; i < last && _buckets[i] != NULL; i++) { if (_buckets[i] == &deletedBucket) continue; @@ -447,19 +455,21 @@ setObject(self, key, object, (uint32_t)_keyFunctions.hash(key)); } - (void)removeObjectForKey: (void *)key { - uint32_t i, hash, last; + uint32_t i, rotatedHash, last; if (key == NULL) @throw [OFInvalidArgumentException exception]; - hash = OFRotateLeft((uint32_t)_keyFunctions.hash(key), _rotate); + rotatedHash = OFRotateLeft((uint32_t)_keyFunctions.hash(key), + _rotation); last = _capacity; - for (i = hash & (_capacity - 1); i < last && _buckets[i] != NULL; i++) { + for (i = rotatedHash & (_capacity - 1); + i < last && _buckets[i] != NULL; i++) { if (_buckets[i] == &deletedBucket) continue; if (_keyFunctions.equal(_buckets[i]->key, key)) { _mutations++; @@ -479,11 +489,11 @@ if (i < last) return; /* In case the last bucket is already used */ - last = hash & (_capacity - 1); + last = rotatedHash & (_capacity - 1); for (i = 0; i < last && _buckets[i] != NULL; i++) { if (_buckets[i] == &deletedBucket) continue; @@ -523,15 +533,15 @@ _count = 0; _capacity = minCapacity; _buckets = OFResizeMemory(_buckets, _capacity, sizeof(*_buckets)); /* - * Get a new random value for _rotate, so that it is not less secure + * Get a new random value for _rotation, so that it is not less secure * than creating a new hash map. */ if (OFHashSeed != 0) - _rotate = OFRandom16() & 31; + _rotation = OFRandom16() & 31; } - (bool)containsObject: (void *)object { if (object == NULL || _count == 0)