public static void Free(UnsafeHashCollection *collection) { Assert.Check(collection->Entries.Dynamic); AllocHelper.Free(collection->Buckets); AllocHelper.Free(collection->Entries.Ptr); }
public static void Free(UnsafeHashCollection *collection) { Assert.Check(collection->Entries.Dynamic == 1); Native.Free(collection->Buckets); Native.Free(collection->Entries.Ptr); }
public Iterator(UnsafeHashCollection *collection) { _index = -1; // Current = null; Collection = collection; }
public static Entry *Insert <T>(UnsafeHashCollection *collection, T value, int valueHash) where T : unmanaged { Entry *entry; if (collection->FreeHead != null) { Assert.Check(collection->FreeCount > 0); // entry we're adding entry = collection->FreeHead; // update free list collection->FreeHead = entry->Next; collection->FreeCount = collection->FreeCount - 1; // this HAS to be a FREE state entry, or something is seriously wrong Assert.Check(entry->State == EntryState.Free); } else { if (collection->UsedCount == collection->Entries.Length) { // !! IMPORTANT !! // when this happens, it's very important to be // aware of the fact that all pointers to to buckets // or entries etc. are not valid anymore as we have // re-allocated all of the memory Expand(collection); } // grab 'next' element maintained by _count entry = (Entry *)UnsafeBuffer.Element(collection->Entries.Ptr, collection->UsedCount, collection->Entries.Stride); // step up used count collection->UsedCount = collection->UsedCount + 1; // this HAS to be a NONE state entry, or something is seriously wrong Assert.Check(entry->State == EntryState.None); } // compute bucket hash var bucketHash = valueHash % collection->Entries.Length; // hook up entry entry->Hash = valueHash; entry->Next = collection->Buckets[bucketHash]; entry->State = EntryState.Used; // store value *(T *)((byte *)entry + collection->KeyOffset) = value; // store as head on bucket collection->Buckets[bucketHash] = entry; // done! return(entry); }
public static void Clear(UnsafeHashCollection *collection) { collection->FreeCount = 0; collection->UsedCount = 0; var length = collection->Entries.Length; AllocHelper.MemClear(collection->Buckets, length * sizeof(Entry * *)); UnsafeBuffer.Clear(&collection->Entries); }
public static void Clear(UnsafeHashCollection *collection) { collection->FreeHead = null; collection->FreeCount = 0; collection->UsedCount = 0; var length = collection->Entries.Length; Memory.ZeroMem(collection->Buckets, length * sizeof(Entry * *)); UnsafeBuffer.Clear(&collection->Entries); }
static void Expand(UnsafeHashCollection *collection) { UDebug.Assert(collection->Entries.Dynamic == 1); // We need to grab the pext prime, so at least current length + 1 var capacity = GetNextPrime(collection->Entries.Length + 1); UDebug.Assert(capacity >= collection->Entries.Length); var newBuckets = (Entry **)Memory.MallocAndZero(capacity * sizeof(Entry * *), sizeof(Entry * *)); var newEntries = default(UnsafeBuffer); UnsafeBuffer.InitDynamic(&newEntries, capacity, collection->Entries.Stride); UnsafeBuffer.Copy(collection->Entries, 0, newEntries, 0, collection->Entries.Length); collection->FreeHead = null; collection->FreeCount = 0; for (int i = collection->Entries.Length - 1; i >= 0; --i) { var entry = (Entry *)((byte *)newEntries.Ptr + (i * newEntries.Stride)); if (entry->State == EntryState.Used) { var bucketHash = entry->Hash % capacity; // assign current entry in buckets as next entry->Next = newBuckets[bucketHash]; // assign entry as new bucket head newBuckets[bucketHash] = entry; } // entry is in free list else if (entry->State == EntryState.Free) { // assign free list as next entry->Next = collection->FreeHead; // re-assign free list to entry collection->FreeHead = entry; collection->FreeCount = collection->FreeCount + 1; } } // free old memory Memory.Free(collection->Buckets); UnsafeBuffer.Free(&collection->Entries); // new storage collection->Buckets = newBuckets; collection->Entries = newEntries; }
private static void Expand(UnsafeHashCollection *collection) { Assert.Check(collection->Entries.Dynamic); var capacity = GetNextPrime(collection->Entries.Length); Assert.Check(capacity >= collection->Entries.Length); var newBuckets = (Entry **)AllocHelper.MallocAndClear(capacity * sizeof(Entry * *), sizeof(Entry * *)); var newEntries = default(UnsafeBuffer); UnsafeBuffer.InitDynamic(&newEntries, capacity, collection->Entries.Stride); UnsafeBuffer.Copy(collection->Entries, 0, newEntries, 0, collection->Entries.Length); collection->FreeHead = null; collection->FreeCount = 0; for (var i = collection->Entries.Length - 1; i >= 0; --i) { var entry = (Entry *)((byte *)newEntries.Ptr + i * newEntries.Stride); if (entry->State == EntryState.Used) { var bucketHash = entry->Hash % capacity; // assign current entry in buckets as next entry->Next = newBuckets[bucketHash]; // assign entry as new bucket head newBuckets[bucketHash] = entry; } // entry is in free list else if (entry->State == EntryState.Free) { // assign free list as next entry->Next = collection->FreeHead; // re-assign free list to entry collection->FreeHead = entry; collection->FreeCount = collection->FreeCount + 1; } } // free old memory AllocHelper.Free(collection->Buckets); UnsafeBuffer.Free(&collection->Entries); // new storage collection->Buckets = newBuckets; collection->Entries = newEntries; }
public static void Free(UnsafeHashCollection *collection) { if (collection == null) { return; } UDebug.Assert(collection->Entries.Dynamic == 1); Memory.Free(collection->Buckets); Memory.Free(collection->Entries.Ptr); *collection = default; }
public static Entry *Find <T>(UnsafeHashCollection *collection, T value, int valueHash) where T : unmanaged, IEquatable <T> { var bucketHead = collection->Buckets[valueHash % collection->Entries.Length]; while (bucketHead != null) { if (bucketHead->Hash == valueHash && value.Equals(*(T *)((byte *)bucketHead + collection->KeyOffset))) { return(bucketHead); } else { bucketHead = bucketHead->Next; } } return(null); }
public static bool Remove <T>(UnsafeHashCollection *collection, T value, int valueHash) where T : unmanaged, IEquatable <T> { var bucketHash = valueHash % collection->Entries.Length; var bucketHead = collection->Buckets[valueHash % collection->Entries.Length]; var bucketPrev = default(Entry *); while (bucketHead != null) { if (bucketHead->Hash == valueHash && value.Equals(*(T *)((byte *)bucketHead + collection->KeyOffset))) { // if previous was null, this means we're at the head of the list if (bucketPrev == null) { collection->Buckets[bucketHash] = bucketHead->Next; } // previous was not null, it means we're in the middle // of the list so stitch the elements together else { bucketPrev->Next = bucketHead->Next; } Assert.Check(bucketHead->State == EntryState.Used); // next for the node we removed becomes current free list head bucketHead->Next = collection->FreeHead; bucketHead->State = EntryState.Free; // set it as free list head, and increment count collection->FreeHead = bucketHead; collection->FreeCount = collection->FreeCount + 1; return(true); } else { bucketPrev = bucketHead; bucketHead = bucketHead->Next; } } return(false); }
public static T GetKey <T>(UnsafeHashCollection *collection, Entry *entry) where T : unmanaged { return(*(T *)((byte *)entry + collection->KeyOffset)); }
public static Entry *GetEntry(UnsafeHashCollection *collection, int index) { return((Entry *)UnsafeBuffer.Element(collection->Entries.Ptr, index, collection->Entries.Stride)); }
public static Entry *Insert <T>(UnsafeHashCollection *collection, T key, int valueHash) where T : unmanaged { Entry *entry; if (collection->FreeHead != null) { UDebug.Assert(collection->FreeCount > 0); // entry we're adding entry = collection->FreeHead; // update free list collection->FreeHead = entry->Next; collection->FreeCount = collection->FreeCount - 1; // this HAS to be a FREE state entry, or something is seriously wrong UDebug.Assert(entry->State == EntryState.Free); } else { if (collection->UsedCount == collection->Entries.Length) { // Cannot expand fixed-size HashCollection if (collection->Entries.Dynamic == 0) { throw new InvalidOperationException(ThrowHelper.InvalidOperation_CollectionFull); } // !! IMPORTANT !! // when this happens, it's very important to be // aware of the fact that all pointers to to buckets // or entries etc. are not valid anymore as we have // re-allocated all of the memory Expand(collection); } // grab 'next' element maintained by _count entry = collection->Entries.Element <Entry>(collection->UsedCount); // step up used count collection->UsedCount = collection->UsedCount + 1; // this HAS to be a NONE state entry, or something is seriously wrong UDebug.Assert(entry->State == EntryState.None); } // compute bucket hash var bucketHash = valueHash % collection->Entries.Length; // hook up entry entry->Hash = valueHash; entry->Next = collection->Buckets[bucketHash]; entry->State = EntryState.Used; // store value *(T *)((byte *)entry + collection->KeyOffset) = key; // store as head on bucket collection->Buckets[bucketHash] = entry; // done! return(entry); }
public static Entry *GetEntry(UnsafeHashCollection *collection, int index) { return(collection->Entries.Element <Entry>(index)); }