/// <summary> /// Removes all elements in the specified hashset from the current hashset. /// </summary> public static void ExceptWith <T>(UnsafeHashSet *set, UnsafeHashSet *other) where T : unmanaged, IEquatable <T> { UDebug.Assert(set != null); UDebug.Assert(typeof(T).TypeHandle.Value == set->_typeHandle); UDebug.Assert(other != null); UDebug.Assert(typeof(T).TypeHandle.Value == other->_typeHandle); // When this set has no elements, return if (GetCount(set) == 0) { return; } // A set except itself is an empty set. if (other == set) { Clear(set); return; } for (int i = other->_collection.UsedCount - 1; i >= 0; --i) { var entry = UnsafeHashCollection.GetEntry(&other->_collection, i); if (entry->State == UnsafeHashCollection.EntryState.Used) { var key = *(T *)((byte *)entry + other->_collection.KeyOffset); var keyHash = key.GetHashCode(); UnsafeHashCollection.Remove(&set->_collection, key, keyHash); } } }
public static bool Remove <K>(UnsafeDictionary *map, K key) where K : unmanaged, IEquatable <K> { UDebug.Assert(map != null); UDebug.Assert(typeof(K).TypeHandle.Value == map->_typeHandleKey); return(UnsafeHashCollection.Remove <K>(&map->_collection, key, key.GetHashCode())); }
private static bool TryInsert <K, V>(UnsafeDictionary *map, K key, V value, MapInsertionBehaviour behaviour) where K : unmanaged, IEquatable <K> where V : unmanaged { UDebug.Assert(map != null); UDebug.Assert(typeof(K).TypeHandle.Value == map->_typeHandleKey); UDebug.Assert(typeof(V).TypeHandle.Value == map->_typeHandleValue); var hash = key.GetHashCode(); var entry = UnsafeHashCollection.Find <K>(&map->_collection, key, hash); // Entry is already present if (entry != null) { if (behaviour == MapInsertionBehaviour.Overwrite) { *GetValue <V>(map->_valueOffset, entry) = value; return(true); } if (behaviour == MapInsertionBehaviour.ThrowIfExists) { throw new ArgumentException(string.Format(ThrowHelper.Arg_AddingDuplicateWithKey, key)); } return(false); } // Create new entry else { entry = UnsafeHashCollection.Insert <K>(&map->_collection, key, hash); *GetValue <V>(map->_valueOffset, entry) = value; return(true); } }
public static bool Contains <T>(UnsafeHashSet *set, T key) where T : unmanaged, IEquatable <T> { UDebug.Assert(set != null); UDebug.Assert(typeof(T).TypeHandle.Value == set->_typeHandle); return(UnsafeHashCollection.Find(&set->_collection, key, key.GetHashCode()) != null); }
public static UnsafeHashSet *Allocate <T>(int capacity, bool fixedSize = false) where T : unmanaged, IEquatable <T> { var valStride = sizeof(T); var entryStride = sizeof(UnsafeHashCollection.Entry); // round capacity up to next prime capacity = UnsafeHashCollection.GetNextPrime(capacity); var valAlignment = Memory.GetAlignment(valStride); // the alignment for entry/key/val, we can't have less than ENTRY_ALIGNMENT // bytes alignment because entries are 16 bytes with 1 x pointer + 2 x 4 byte integers var alignment = Math.Max(UnsafeHashCollection.Entry.ALIGNMENT, valAlignment); // calculate strides for all elements valStride = Memory.RoundToAlignment(valStride, alignment); entryStride = Memory.RoundToAlignment(sizeof(UnsafeHashCollection.Entry), alignment); // dictionary ptr UnsafeHashSet *set; if (fixedSize) { var sizeOfHeader = Memory.RoundToAlignment(sizeof(UnsafeHashSet), alignment); var sizeOfBucketsBuffer = Memory.RoundToAlignment(sizeof(UnsafeHashCollection.Entry * *) * capacity, alignment); var sizeofEntriesBuffer = (entryStride + valStride) * capacity; // allocate memory var ptr = Memory.MallocAndZero(sizeOfHeader + sizeOfBucketsBuffer + sizeofEntriesBuffer, alignment); // start of memory is the dict itself set = (UnsafeHashSet *)ptr; // buckets are offset by header size set->_collection.Buckets = (UnsafeHashCollection.Entry * *)((byte *)ptr + sizeOfHeader); // initialize fixed buffer UnsafeBuffer.InitFixed(&set->_collection.Entries, (byte *)ptr + (sizeOfHeader + sizeOfBucketsBuffer), capacity, entryStride + valStride); } else { // allocate dict, buckets and entries buffer separately set = Memory.MallocAndZero <UnsafeHashSet>(); set->_collection.Buckets = (UnsafeHashCollection.Entry * *)Memory.MallocAndZero(sizeof(UnsafeHashCollection.Entry * *) * capacity, sizeof(UnsafeHashCollection.Entry * *)); // init dynamic buffer UnsafeBuffer.InitDynamic(&set->_collection.Entries, capacity, entryStride + valStride); } set->_collection.FreeCount = 0; set->_collection.UsedCount = 0; set->_collection.KeyOffset = entryStride; set->_typeHandle = typeof(T).TypeHandle.Value; return(set); }
public static void Free(UnsafeHashSet *set) { if (set == null) { return; } if (set->_collection.Entries.Dynamic == 1) { UnsafeHashCollection.Free(&set->_collection); } *set = default; Memory.Free(set); }
public static bool Add <T>(UnsafeHashSet *set, T key) where T : unmanaged, IEquatable <T> { UDebug.Assert(set != null); UDebug.Assert(typeof(T).TypeHandle.Value == set->_typeHandle); var hash = key.GetHashCode(); var entry = UnsafeHashCollection.Find <T>(&set->_collection, key, hash); if (entry == null) { UnsafeHashCollection.Insert <T>(&set->_collection, key, hash); return(true); } return(false); }
public static V Get <K, V>(UnsafeDictionary *map, K key) where K : unmanaged, IEquatable <K> where V : unmanaged { UDebug.Assert(map != null); UDebug.Assert(typeof(K).TypeHandle.Value == map->_typeHandleKey); UDebug.Assert(typeof(V).TypeHandle.Value == map->_typeHandleValue); var entry = UnsafeHashCollection.Find(&map->_collection, key, key.GetHashCode()); if (entry == null) { throw new ArgumentException(string.Format(ThrowHelper.Arg_KeyNotFoundWithKey, key)); } return(*GetValue <V>(map->_valueOffset, entry)); }
/// <summary> /// Modifies the current hashset to contain all elements that are present in itself, the specified hashset, or both. /// </summary> public static void UnionWith <T>(UnsafeHashSet *set, UnsafeHashSet *other) where T : unmanaged, IEquatable <T> { UDebug.Assert(set != null); UDebug.Assert(typeof(T).TypeHandle.Value == set->_typeHandle); UDebug.Assert(other != null); UDebug.Assert(typeof(T).TypeHandle.Value == other->_typeHandle); for (int i = other->_collection.UsedCount - 1; i >= 0; --i) { var entry = UnsafeHashCollection.GetEntry(&other->_collection, i); if (entry->State == UnsafeHashCollection.EntryState.Used) { // always add to this collection Add <T>(set, *(T *)((byte *)entry + other->_collection.KeyOffset)); } } }
public static bool TryGetValue <K, V>(UnsafeDictionary *map, K key, out V val) where K : unmanaged, IEquatable <K> where V : unmanaged { UDebug.Assert(map != null); UDebug.Assert(typeof(K).TypeHandle.Value == map->_typeHandleKey); UDebug.Assert(typeof(V).TypeHandle.Value == map->_typeHandleValue); var entry = UnsafeHashCollection.Find <K>(&map->_collection, key, key.GetHashCode()); if (entry != null) { val = *GetValue <V>(map->_valueOffset, entry); return(true); } val = default; return(false); }
/// <summary> /// Modifies the current hashset to contain only elements that are present in that hashset and in the specified hashset. /// </summary> public static void IntersectsWith <T>(UnsafeHashSet *set, UnsafeHashSet *other) where T : unmanaged, IEquatable <T> { UDebug.Assert(set != null); UDebug.Assert(typeof(T).TypeHandle.Value == set->_typeHandle); UDebug.Assert(other != null); UDebug.Assert(typeof(T).TypeHandle.Value == other->_typeHandle); // When this set has no elements, there is nothing to intersect. // When this set equals other, it is already intersecting. if (GetCount(set) == 0 || set == other) { return; } // When the other set has no elements, clear this one completely if (GetCount(other) == 0) { Clear(set); return; } for (int i = set->_collection.UsedCount - 1; i >= 0; --i) { var entry = UnsafeHashCollection.GetEntry(&set->_collection, i); if (entry->State == UnsafeHashCollection.EntryState.Used) { var key = *(T *)((byte *)entry + set->_collection.KeyOffset); var keyHash = key.GetHashCode(); // if we don't find this in other collection, remove it (And) if (UnsafeHashCollection.Find <T>(&other->_collection, key, keyHash) == null) { UnsafeHashCollection.Remove <T>(&set->_collection, key, keyHash); } } } }
public static void AddOrGet <K, V>(UnsafeDictionary *map, K key, ref V value) where K : unmanaged, IEquatable <K> where V : unmanaged { UDebug.Assert(map != null); UDebug.Assert(typeof(K).TypeHandle.Value == map->_typeHandleKey); UDebug.Assert(typeof(V).TypeHandle.Value == map->_typeHandleValue); var hash = key.GetHashCode(); var entry = UnsafeHashCollection.Find <K>(&map->_collection, key, hash); if (entry == null) { // insert new entry for key entry = UnsafeHashCollection.Insert <K>(&map->_collection, key, hash); // assign value to entry *GetValue <V>(map->_valueOffset, entry) = value; } else { value = *GetValue <V>(map->_valueOffset, entry); } }
public static void Clear(UnsafeHashSet *set) { UDebug.Assert(set != null); UnsafeHashCollection.Clear(&set->_collection); }
int _valueOffset; // Readonly public static UnsafeDictionary *Allocate <K, V>(int capacity, bool fixedSize = false) where K : unmanaged, IEquatable <K> where V : unmanaged { var keyStride = sizeof(K); var valStride = sizeof(V); var entryStride = sizeof(UnsafeHashCollection.Entry); // round capacity up to next prime capacity = UnsafeHashCollection.GetNextPrime(capacity); var keyAlignment = Memory.GetAlignment(keyStride); var valAlignment = Memory.GetAlignment(valStride); // the alignment for entry/key/val, we can't have less than ENTRY_ALIGNMENT // bytes alignment because entries are 8 bytes with 2 x 32 bit integers var alignment = Math.Max(UnsafeHashCollection.Entry.ALIGNMENT, Math.Max(keyAlignment, valAlignment)); // calculate strides for all elements keyStride = Memory.RoundToAlignment(keyStride, alignment); valStride = Memory.RoundToAlignment(valStride, alignment); entryStride = Memory.RoundToAlignment(sizeof(UnsafeHashCollection.Entry), alignment); // map ptr UnsafeDictionary *map; if (fixedSize) { var sizeOfHeader = Memory.RoundToAlignment(sizeof(UnsafeDictionary), alignment); var sizeOfBucketsBuffer = Memory.RoundToAlignment(sizeof(UnsafeHashCollection.Entry * *) * capacity, alignment); var sizeofEntriesBuffer = (entryStride + keyStride + valStride) * capacity; // allocate memory var ptr = Memory.MallocAndZero(sizeOfHeader + sizeOfBucketsBuffer + sizeofEntriesBuffer, alignment); // start of memory is the dict itself map = (UnsafeDictionary *)ptr; // buckets are offset by header size map->_collection.Buckets = (UnsafeHashCollection.Entry * *)((byte *)ptr + sizeOfHeader); // initialize fixed buffer UnsafeBuffer.InitFixed(&map->_collection.Entries, (byte *)ptr + (sizeOfHeader + sizeOfBucketsBuffer), capacity, entryStride + keyStride + valStride); } else { // allocate dict, buckets and entries buffer separately map = Memory.MallocAndZero <UnsafeDictionary>(); map->_collection.Buckets = (UnsafeHashCollection.Entry * *)Memory.MallocAndZero(sizeof(UnsafeHashCollection.Entry * *) * capacity, sizeof(UnsafeHashCollection.Entry * *)); // init dynamic buffer UnsafeBuffer.InitDynamic(&map->_collection.Entries, capacity, entryStride + keyStride + valStride); } // header init map->_collection.FreeCount = 0; map->_collection.UsedCount = 0; map->_collection.KeyOffset = entryStride; map->_typeHandleKey = typeof(K).TypeHandle.Value; map->_typeHandleValue = typeof(V).TypeHandle.Value; map->_valueOffset = entryStride + keyStride; return(map); }
public static void Clear(UnsafeDictionary *map) { UDebug.Assert(map != null); UnsafeHashCollection.Clear(&map->_collection); }