public static void AllocateHashMap <TKey, TValue>(int length, int bucketLength, Allocator label, out NativeHashMapData *outBuf) where TKey : struct where TValue : struct { #if ENABLE_UNITY_COLLECTIONS_CHECKS if (!UnsafeUtility.IsBlittable <TKey>()) { throw new ArgumentException(string.Format("{0} used in NativeHashMap<{0},{1}> must be blittable", typeof(TKey), typeof(TValue))); } if (!UnsafeUtility.IsBlittable <TValue>()) { throw new ArgumentException(string.Format("{1} used in NativeHashMap<{0},{1}> must be blittable", typeof(TKey), typeof(TValue))); } #endif NativeHashMapData *data = (NativeHashMapData *)UnsafeUtility.Malloc(sizeof(NativeHashMapData), UnsafeUtility.AlignOf <NativeHashMapData>(), label); bucketLength = CollectionHelper.CeilPow2(bucketLength); data->capacity = length; data->bucketCapacityMask = bucketLength - 1; int keyOffset, nextOffset, bucketOffset; int totalSize = CalculateDataSize <TKey, TValue>(length, bucketLength, out keyOffset, out nextOffset, out bucketOffset); data->values = (byte *)UnsafeUtility.Malloc(totalSize, JobsUtility.CacheLineSize, label); data->keys = data->values + keyOffset; data->next = data->values + nextOffset; data->buckets = data->values + bucketOffset; outBuf = data; }
public static void ReallocateHashMap <TKey, TValue>(NativeHashMapData *data, int newCapacity, int newBucketCapacity, Allocator label) where TKey : struct where TValue : struct { newBucketCapacity = CollectionHelper.CeilPow2(newBucketCapacity); if (data->capacity == newCapacity && (data->bucketCapacityMask + 1) == newBucketCapacity) { return; } if (data->capacity > newCapacity) { throw new Exception("Shrinking a hash map is not supported"); } int keyOffset, nextOffset, bucketOffset; int totalSize = CalculateDataSize <TKey, TValue>(newCapacity, newBucketCapacity, out keyOffset, out nextOffset, out bucketOffset); byte *newData = (byte *)UnsafeUtility.Malloc(totalSize, JobsUtility.CacheLineSize, label); byte *newKeys = newData + keyOffset; byte *newNext = newData + nextOffset; byte *newBuckets = newData + bucketOffset; // The items are taken from a free-list and might not be tightly packed, copy all of the old capcity UnsafeUtility.MemCpy(newData, data->values, data->capacity * UnsafeUtility.SizeOf <TValue>()); UnsafeUtility.MemCpy(newKeys, data->keys, data->capacity * UnsafeUtility.SizeOf <TKey>()); UnsafeUtility.MemCpy(newNext, data->next, data->capacity * UnsafeUtility.SizeOf <int>()); for (int emptyNext = data->capacity; emptyNext < newCapacity; ++emptyNext) { ((int *)newNext)[emptyNext] = -1; } // re-hash the buckets, first clear the new bucket list, then insert all values from the old list for (int bucket = 0; bucket < newBucketCapacity; ++bucket) { ((int *)newBuckets)[bucket] = -1; } for (int bucket = 0; bucket <= data->bucketCapacityMask; ++bucket) { int *buckets = (int *)data->buckets; int *nextPtrs = (int *)newNext; while (buckets[bucket] >= 0) { int curEntry = buckets[bucket]; buckets[bucket] = nextPtrs[curEntry]; int newBucket = UnsafeUtility.ReadArrayElement <TKey>(data->keys, curEntry).GetHashCode() & (newBucketCapacity - 1); nextPtrs[curEntry] = ((int *)newBuckets)[newBucket]; ((int *)newBuckets)[newBucket] = curEntry; } } UnsafeUtility.Free(data->values, label); if (data->allocatedIndexLength > data->capacity) { data->allocatedIndexLength = data->capacity; } data->values = newData; data->keys = newKeys; data->next = newNext; data->buckets = newBuckets; data->capacity = newCapacity; data->bucketCapacityMask = newBucketCapacity - 1; }