using System; using System.Collections.Generic; using System.Collections; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Numerics; using Recyclable.Collections.Pools; namespace Recyclable.Collections { internal static class zRecyclableDictionaryAddRange { [MethodImpl(MethodImplOptions.AggressiveInlining)] private static ref RecyclableDictionary.Entry GetEntry(RecyclableDictionary dictionary, int index) where TKey : notnull { return ref dictionary._entries[index >> dictionary._blockShift][index & dictionary._blockSizeMinus1]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static void EnsureCapacity(RecyclableDictionary dictionary, int min) where TKey : notnull { int requiredBlocks = (min + dictionary._blockSizeMinus1) >> dictionary._blockShift; if (dictionary._entries.Length < requiredBlocks) { var newBlocks = requiredBlocks >= RecyclableDefaults.MinPooledArrayLength ? RecyclableArrayPool.Entry[]>.RentShared(requiredBlocks) : new RecyclableDictionary.Entry[requiredBlocks][]; Array.Copy(dictionary._entries, newBlocks, dictionary._entries.Length); if (dictionary._entries.Length >= RecyclableDefaults.MinPooledArrayLength) { RecyclableArrayPool.Entry[]>.ReturnShared(dictionary._entries, false); } dictionary._entries = newBlocks; } for (int i = 0; i < requiredBlocks; i++) { if (dictionary._entries[i] == null) { dictionary._entries[i] = dictionary._blockSize >= RecyclableDefaults.MinPooledArrayLength ? RecyclableArrayPool.Entry>.RentShared(dictionary._blockSize) : new RecyclableDictionary.Entry[dictionary._blockSize]; } } } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static void ResizeBuckets(RecyclableDictionary dictionary, int newSize) where TKey : notnull { var newBuckets = new int[newSize]; Array.Fill(newBuckets, -1); for (int i = 0; i < dictionary._count; i++) { ref var entry = ref GetEntry(dictionary, i); int bucket = entry.HashCode & (newSize - 1); entry.Next = newBuckets[bucket]; newBuckets[bucket] = i; } dictionary._buckets = newBuckets; } [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)] internal static void AddRange(this RecyclableDictionary dictionary, ReadOnlySpan> items) where TKey : notnull { int count = items.Length; if (count == 0) { return; } int requiredCount = dictionary._count + count; EnsureCapacity(dictionary, requiredCount); int bucketsLength = dictionary._buckets.Length; while (requiredCount >= (bucketsLength * 3) / 4) { bucketsLength <<= 1; } if (bucketsLength != dictionary._buckets.Length) { ResizeBuckets(dictionary, bucketsLength); } int bucketMask = dictionary._buckets.Length - 1; int startIndex = dictionary._count; for (int i = 0; i < count; i++) { var kvp = items[i]; TKey key = kvp.Key; TValue value = kvp.Value; int hash = key.GetHashCode() & int.MaxValue; int bucket = hash & bucketMask; int index = dictionary._buckets[bucket]; while (index >= 0) { ref var check = ref GetEntry(dictionary, index); if (check.HashCode == hash && EqualityComparer.Default.Equals(check.Key, key)) { throw new ArgumentException("An element with the same key already exists.", nameof(items)); } index = check.Next; } ref var entry = ref GetEntry(dictionary, startIndex + i); entry.HashCode = hash; entry.Key = key; entry.Value = value; entry.Next = dictionary._buckets[bucket]; dictionary._buckets[bucket] = startIndex + i; } dictionary._count = requiredCount; } [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)] internal static void AddRange(this RecyclableDictionary dictionary, Span> items) where TKey : notnull => AddRange(dictionary, (ReadOnlySpan>)items); [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)] internal static void AddRange(this RecyclableDictionary dictionary, KeyValuePair[] items) where TKey : notnull => AddRange(dictionary, (ReadOnlySpan>)items); [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)] internal static void AddRange(this RecyclableDictionary dictionary, RecyclableDictionary items) where TKey : notnull { int count = items._count; if (count == 0) { return; } int requiredCount = dictionary._count + count; EnsureCapacity(dictionary, requiredCount); int bucketsLength = dictionary._buckets.Length; while (requiredCount >= (bucketsLength * 3) / 4) { bucketsLength <<= 1; } if (bucketsLength != dictionary._buckets.Length) { ResizeBuckets(dictionary, bucketsLength); } int bucketMask = dictionary._buckets.Length - 1; int shift = items._blockShift; int mask = items._blockSizeMinus1; var sourceBlocks = items._entries; int startIndex = dictionary._count; for (int i = 0; i < count; i++) { ref var sourceEntry = ref sourceBlocks[i >> shift][i & mask]; TKey key = sourceEntry.Key; TValue value = sourceEntry.Value; int hash = sourceEntry.HashCode; int bucket = hash & bucketMask; int index = dictionary._buckets[bucket]; while (index >= 0) { ref var check = ref GetEntry(dictionary, index); if (check.HashCode == hash && EqualityComparer.Default.Equals(check.Key, key)) { throw new ArgumentException("An element with the same key already exists.", nameof(items)); } index = check.Next; } ref var entry = ref GetEntry(dictionary, startIndex + i); entry.HashCode = hash; entry.Key = key; entry.Value = value; entry.Next = dictionary._buckets[bucket]; dictionary._buckets[bucket] = startIndex + i; } dictionary._count = requiredCount; } [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)] internal static void AddRange(this RecyclableDictionary dictionary, in Array items) where TKey : notnull { int count = items.Length; if (count == 0) { return; } KeyValuePair[] buffer; int lower = items.GetLowerBound(0); if (items is KeyValuePair[] array && lower == 0) { buffer = array; } else { buffer = count >= RecyclableDefaults.MinPooledArrayLength ? RecyclableArrayPool>.RentShared(checked((int)BitOperations.RoundUpToPowerOf2((uint)count))) : new KeyValuePair[count]; Array.Copy(items, lower, buffer, 0, count); } int requiredCount = dictionary._count + count; EnsureCapacity(dictionary, requiredCount); int bucketsLength = dictionary._buckets.Length; while (requiredCount >= (bucketsLength * 3) / 4) { bucketsLength <<= 1; } if (bucketsLength != dictionary._buckets.Length) { ResizeBuckets(dictionary, bucketsLength); } int bucketMask = dictionary._buckets.Length - 1; int startIndex = dictionary._count; for (int i = 0; i < count; i++) { var kvp = buffer[i]; TKey key = kvp.Key; TValue value = kvp.Value; int hash = key.GetHashCode() & int.MaxValue; int bucket = hash & bucketMask; int index = dictionary._buckets[bucket]; while (index >= 0) { ref var check = ref GetEntry(dictionary, index); if (check.HashCode == hash && EqualityComparer.Default.Equals(check.Key, key)) { throw new ArgumentException("An element with the same key already exists.", nameof(items)); } index = check.Next; } ref var entry = ref GetEntry(dictionary, startIndex + i); entry.HashCode = hash; entry.Key = key; entry.Value = value; entry.Next = dictionary._buckets[bucket]; dictionary._buckets[bucket] = startIndex + i; } dictionary._count = requiredCount; if (!ReferenceEquals(buffer, items) && count >= RecyclableDefaults.MinPooledArrayLength) { RecyclableArrayPool>.ReturnShared(buffer, RecyclableDictionary._needsClearing); } } [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)] internal static void AddRange(this RecyclableDictionary dictionary, List> items) where TKey : notnull { int count = items.Count; if (count == 0) { return; } int requiredCount = dictionary._count + count; EnsureCapacity(dictionary, requiredCount); int bucketsLength = dictionary._buckets.Length; while (requiredCount >= (bucketsLength * 3) / 4) { bucketsLength <<= 1; } if (bucketsLength != dictionary._buckets.Length) { ResizeBuckets(dictionary, bucketsLength); } int bucketMask = dictionary._buckets.Length - 1; int startIndex = dictionary._count; var span = CollectionsMarshal.AsSpan(items); for (int i = 0; i < count; i++) { var kvp = span[i]; TKey key = kvp.Key; TValue value = kvp.Value; int hash = key.GetHashCode() & int.MaxValue; int bucket = hash & bucketMask; int index = dictionary._buckets[bucket]; while (index >= 0) { ref var check = ref GetEntry(dictionary, index); if (check.HashCode == hash && EqualityComparer.Default.Equals(check.Key, key)) { throw new ArgumentException("An element with the same key already exists.", nameof(items)); } index = check.Next; } ref var entry = ref GetEntry(dictionary, startIndex + i); entry.HashCode = hash; entry.Key = key; entry.Value = value; entry.Next = dictionary._buckets[bucket]; dictionary._buckets[bucket] = startIndex + i; } dictionary._count = requiredCount; } [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)] internal static void AddRange(this RecyclableDictionary dictionary, ICollection items) where TKey : notnull { int count = items.Count; if (count == 0) { return; } KeyValuePair[] buffer = count >= RecyclableDefaults.MinPooledArrayLength ? RecyclableArrayPool>.RentShared(checked((int)BitOperations.RoundUpToPowerOf2((uint)count))) : new KeyValuePair[count]; items.CopyTo(buffer, 0); int requiredCount = dictionary._count + count; EnsureCapacity(dictionary, requiredCount); int bucketsLength = dictionary._buckets.Length; while (requiredCount >= (bucketsLength * 3) / 4) { bucketsLength <<= 1; } if (bucketsLength != dictionary._buckets.Length) { ResizeBuckets(dictionary, bucketsLength); } int bucketMask = dictionary._buckets.Length - 1; int startIndex = dictionary._count; for (int i = 0; i < count; i++) { var kvp = buffer[i]; TKey key = kvp.Key; TValue value = kvp.Value; int hash = key.GetHashCode() & int.MaxValue; int bucket = hash & bucketMask; int index = dictionary._buckets[bucket]; while (index >= 0) { ref var check = ref GetEntry(dictionary, index); if (check.HashCode == hash && EqualityComparer.Default.Equals(check.Key, key)) { throw new ArgumentException("An element with the same key already exists.", nameof(items)); } index = check.Next; } ref var entry = ref GetEntry(dictionary, startIndex + i); entry.HashCode = hash; entry.Key = key; entry.Value = value; entry.Next = dictionary._buckets[bucket]; dictionary._buckets[bucket] = startIndex + i; } dictionary._count = requiredCount; if (count >= RecyclableDefaults.MinPooledArrayLength) { RecyclableArrayPool>.ReturnShared(buffer, RecyclableDictionary._needsClearing); } } [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)] internal static void AddRange(this RecyclableDictionary dictionary, ICollection> items) where TKey : notnull { int count = items.Count; if (count == 0) { return; } KeyValuePair[] buffer = count >= RecyclableDefaults.MinPooledArrayLength ? RecyclableArrayPool>.RentShared(checked((int)BitOperations.RoundUpToPowerOf2((uint)count))) : new KeyValuePair[count]; items.CopyTo(buffer, 0); int requiredCount = dictionary._count + count; EnsureCapacity(dictionary, requiredCount); int bucketsLength = dictionary._buckets.Length; while (requiredCount >= (bucketsLength * 3) / 4) { bucketsLength <<= 1; } if (bucketsLength != dictionary._buckets.Length) { ResizeBuckets(dictionary, bucketsLength); } int bucketMask = dictionary._buckets.Length - 1; int startIndex = dictionary._count; for (int i = 0; i < count; i++) { var kvp = buffer[i]; TKey key = kvp.Key; TValue value = kvp.Value; int hash = key.GetHashCode() & int.MaxValue; int bucket = hash & bucketMask; int index = dictionary._buckets[bucket]; while (index >= 0) { ref var check = ref GetEntry(dictionary, index); if (check.HashCode == hash && EqualityComparer.Default.Equals(check.Key, key)) { throw new ArgumentException("An element with the same key already exists.", nameof(items)); } index = check.Next; } ref var entry = ref GetEntry(dictionary, startIndex + i); entry.HashCode = hash; entry.Key = key; entry.Value = value; entry.Next = dictionary._buckets[bucket]; dictionary._buckets[bucket] = startIndex + i; } dictionary._count = requiredCount; if (count >= RecyclableDefaults.MinPooledArrayLength) { RecyclableArrayPool>.ReturnShared(buffer, RecyclableDictionary._needsClearing); } } [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)] internal static void AddRange(this RecyclableDictionary dictionary, RecyclableList> items) where TKey : notnull { int count = items._count; if (count == 0) { return; } int requiredCount = dictionary._count + count; EnsureCapacity(dictionary, requiredCount); int bucketsLength = dictionary._buckets.Length; while (requiredCount >= (bucketsLength * 3) / 4) { bucketsLength <<= 1; } if (bucketsLength != dictionary._buckets.Length) { ResizeBuckets(dictionary, bucketsLength); } int bucketMask = dictionary._buckets.Length - 1; int startIndex = dictionary._count; var source = items._memoryBlock; for (int i = 0; i < count; i++) { var kvp = source[i]; TKey key = kvp.Key; TValue value = kvp.Value; int hash = key.GetHashCode() & int.MaxValue; int bucket = hash & bucketMask; int index = dictionary._buckets[bucket]; while (index >= 0) { ref var check = ref GetEntry(dictionary, index); if (check.HashCode == hash && EqualityComparer.Default.Equals(check.Key, key)) { throw new ArgumentException("An element with the same key already exists.", nameof(items)); } index = check.Next; } ref var entry = ref GetEntry(dictionary, startIndex + i); entry.HashCode = hash; entry.Key = key; entry.Value = value; entry.Next = dictionary._buckets[bucket]; dictionary._buckets[bucket] = startIndex + i; } dictionary._count = requiredCount; } [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)] internal static void AddRange(this RecyclableDictionary dictionary, RecyclableLongList> items) where TKey : notnull { long longCount = items._longCount; if (longCount == 0) { return; } if (longCount > int.MaxValue - dictionary._count) { ThrowHelper.ThrowArgumentOutOfRangeException(nameof(items), $"The total number of items exceeds {int.MaxValue}"); } int count = (int)longCount; int blockSize = items._blockSize; int fullBlocks = (int)(longCount >> items._blockSizePow2BitShift); int lastBlockLength = (int)(longCount & items._blockSizeMinus1); int requiredCount = dictionary._count + count; EnsureCapacity(dictionary, requiredCount); int bucketsLength = dictionary._buckets.Length; while (requiredCount >= (bucketsLength * 3) / 4) { bucketsLength <<= 1; } if (bucketsLength != dictionary._buckets.Length) { ResizeBuckets(dictionary, bucketsLength); } int bucketMask = dictionary._buckets.Length - 1; int destIndex = dictionary._count; var blocks = items._memoryBlocks; for (int block = 0; block < fullBlocks; block++) { var source = blocks[block]; for (int j = 0; j < blockSize; j++) { var kvp = source[j]; TKey key = kvp.Key; TValue value = kvp.Value; int hash = key.GetHashCode() & int.MaxValue; int bucket = hash & bucketMask; int index = dictionary._buckets[bucket]; while (index >= 0) { ref var check = ref GetEntry(dictionary, index); if (check.HashCode == hash && EqualityComparer.Default.Equals(check.Key, key)) { throw new ArgumentException("An element with the same key already exists.", nameof(items)); } index = check.Next; } ref var entry = ref GetEntry(dictionary, destIndex); entry.HashCode = hash; entry.Key = key; entry.Value = value; entry.Next = dictionary._buckets[bucket]; dictionary._buckets[bucket] = destIndex++; } } if (lastBlockLength > 0) { var source = blocks[fullBlocks]; for (int j = 0; j < lastBlockLength; j++) { var kvp = source[j]; TKey key = kvp.Key; TValue value = kvp.Value; int hash = key.GetHashCode() & int.MaxValue; int bucket = hash & bucketMask; int index = dictionary._buckets[bucket]; while (index >= 0) { ref var check = ref GetEntry(dictionary, index); if (check.HashCode == hash && EqualityComparer.Default.Equals(check.Key, key)) { throw new ArgumentException("An element with the same key already exists.", nameof(items)); } index = check.Next; } ref var entry = ref GetEntry(dictionary, destIndex); entry.HashCode = hash; entry.Key = key; entry.Value = value; entry.Next = dictionary._buckets[bucket]; dictionary._buckets[bucket] = destIndex++; } } dictionary._count = requiredCount; } [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)] internal static void AddRange(this RecyclableDictionary dictionary, RecyclableSortedDictionary items) where TKey : notnull { int count = items.Count; if (count == 0) { return; } int requiredCount = dictionary._count + count; EnsureCapacity(dictionary, requiredCount); int bucketsLength = dictionary._buckets.Length; while (requiredCount >= (bucketsLength * 3) / 4) { bucketsLength <<= 1; } if (bucketsLength != dictionary._buckets.Length) { ResizeBuckets(dictionary, bucketsLength); } int bucketMask = dictionary._buckets.Length - 1; int startIndex = dictionary._count; for (int i = 0; i < count; i++) { TKey key = items.GetKey(i); TValue value = items.GetValue(i); int hash = key.GetHashCode() & int.MaxValue; int bucket = hash & bucketMask; int index = dictionary._buckets[bucket]; while (index >= 0) { ref var check = ref GetEntry(dictionary, index); if (check.HashCode == hash && EqualityComparer.Default.Equals(check.Key, key)) { throw new ArgumentException("An element with the same key already exists.", nameof(items)); } index = check.Next; } ref var entry = ref GetEntry(dictionary, startIndex + i); entry.HashCode = hash; entry.Key = key; entry.Value = value; entry.Next = dictionary._buckets[bucket]; dictionary._buckets[bucket] = startIndex + i; } dictionary._count = requiredCount; } [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)] internal static void AddRange(this RecyclableDictionary dictionary, RecyclableSortedList items) where TKey : notnull { int count = items._count; if (count == 0) { return; } int requiredCount = dictionary._count + count; EnsureCapacity(dictionary, requiredCount); int bucketsLength = dictionary._buckets.Length; while (requiredCount >= (bucketsLength * 3) / 4) { bucketsLength <<= 1; } if (bucketsLength != dictionary._buckets.Length) { ResizeBuckets(dictionary, bucketsLength); } int bucketMask = dictionary._buckets.Length - 1; int startIndex = dictionary._count; TKey[] keys = items._keys; TValue[] values = items._values; for (int i = 0; i < count; i++) { TKey key = keys[i]; TValue value = values[i]; int hash = key.GetHashCode() & int.MaxValue; int bucket = hash & bucketMask; int index = dictionary._buckets[bucket]; while (index >= 0) { ref var check = ref GetEntry(dictionary, index); if (check.HashCode == hash && EqualityComparer.Default.Equals(check.Key, key)) { throw new ArgumentException("An element with the same key already exists.", nameof(items)); } index = check.Next; } ref var entry = ref GetEntry(dictionary, startIndex + i); entry.HashCode = hash; entry.Key = key; entry.Value = value; entry.Next = dictionary._buckets[bucket]; dictionary._buckets[bucket] = startIndex + i; } dictionary._count = requiredCount; } [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)] internal static void AddRange(this RecyclableDictionary dictionary, RecyclableQueue> items) where TKey : notnull { long longCount = items._count; if (longCount == 0) { return; } if (longCount > int.MaxValue - dictionary._count) { ThrowHelper.ThrowArgumentOutOfRangeException(nameof(items), $"The total number of items exceeds {int.MaxValue}"); } int count = (int)longCount; int requiredCount = dictionary._count + count; EnsureCapacity(dictionary, requiredCount); int bucketsLength = dictionary._buckets.Length; while (requiredCount >= (bucketsLength * 3) / 4) { bucketsLength <<= 1; } if (bucketsLength != dictionary._buckets.Length) { ResizeBuckets(dictionary, bucketsLength); } int bucketMask = dictionary._buckets.Length - 1; int destIndex = dictionary._count; var chunk = items._head; while (chunk != null) { int sourceIndex = chunk.Bottom; int sourceTop = chunk.Top; var source = chunk.Value; while (sourceIndex < sourceTop) { var kvp = source[sourceIndex++]; TKey key = kvp.Key; TValue value = kvp.Value; int hash = key.GetHashCode() & int.MaxValue; int bucket = hash & bucketMask; int index = dictionary._buckets[bucket]; while (index >= 0) { ref var check = ref GetEntry(dictionary, index); if (check.HashCode == hash && EqualityComparer.Default.Equals(check.Key, key)) { throw new ArgumentException("An element with the same key already exists.", nameof(items)); } index = check.Next; } ref var entry = ref GetEntry(dictionary, destIndex); entry.HashCode = hash; entry.Key = key; entry.Value = value; entry.Next = dictionary._buckets[bucket]; dictionary._buckets[bucket] = destIndex++; } chunk = chunk.Next; } dictionary._count = requiredCount; } [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)] internal static void AddRange(this RecyclableDictionary dictionary, RecyclableStack> items) where TKey : notnull { long longCount = items._count; if (longCount == 0) { return; } if (longCount > int.MaxValue - dictionary._count) { ThrowHelper.ThrowArgumentOutOfRangeException(nameof(items), $"The total number of items exceeds {int.MaxValue}"); } int count = (int)longCount; int requiredCount = dictionary._count + count; EnsureCapacity(dictionary, requiredCount); int bucketsLength = dictionary._buckets.Length; while (requiredCount >= (bucketsLength * 3) / 4) { bucketsLength <<= 1; } if (bucketsLength != dictionary._buckets.Length) { ResizeBuckets(dictionary, bucketsLength); } int bucketMask = dictionary._buckets.Length - 1; int destIndex = dictionary._count; var sourceChunk = items._current; while (sourceChunk.Previous != null) { sourceChunk = sourceChunk.Previous; } while (sourceChunk != null) { var source = sourceChunk.Value; int sourceCount = sourceChunk.Index; int sourceIndex = 0; while (sourceIndex < sourceCount) { var kvp = source[sourceIndex++]; TKey key = kvp.Key; TValue value = kvp.Value; int hash = key.GetHashCode() & int.MaxValue; int bucket = hash & bucketMask; int index = dictionary._buckets[bucket]; while (index >= 0) { ref var check = ref GetEntry(dictionary, index); if (check.HashCode == hash && EqualityComparer.Default.Equals(check.Key, key)) { throw new ArgumentException("An element with the same key already exists.", nameof(items)); } index = check.Next; } ref var entry = ref GetEntry(dictionary, destIndex); entry.HashCode = hash; entry.Key = key; entry.Value = value; entry.Next = dictionary._buckets[bucket]; dictionary._buckets[bucket] = destIndex++; } sourceChunk = sourceChunk.Next; } dictionary._count = requiredCount; } [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)] internal static void AddRange(this RecyclableDictionary dictionary, RecyclableLinkedList> items) where TKey : notnull { long longCount = items._count; if (longCount == 0) { return; } if (longCount > int.MaxValue - dictionary._count) { ThrowHelper.ThrowArgumentOutOfRangeException(nameof(items), $"The total number of items exceeds {int.MaxValue}"); } int count = (int)longCount; int requiredCount = dictionary._count + count; EnsureCapacity(dictionary, requiredCount); int bucketsLength = dictionary._buckets.Length; while (requiredCount >= (bucketsLength * 3) / 4) { bucketsLength <<= 1; } if (bucketsLength != dictionary._buckets.Length) { ResizeBuckets(dictionary, bucketsLength); } int bucketMask = dictionary._buckets.Length - 1; int destIndex = dictionary._count; var chunk = items._head; while (chunk != null) { int sourceIndex = chunk.Bottom; int sourceTop = chunk.Top; var source = chunk.Value; while (sourceIndex < sourceTop) { var kvp = source[sourceIndex++]; TKey key = kvp.Key; TValue value = kvp.Value; int hash = key.GetHashCode() & int.MaxValue; int bucket = hash & bucketMask; int index = dictionary._buckets[bucket]; while (index >= 0) { ref var check = ref GetEntry(dictionary, index); if (check.HashCode == hash && EqualityComparer.Default.Equals(check.Key, key)) { throw new ArgumentException("An element with the same key already exists.", nameof(items)); } index = check.Next; } ref var entry = ref GetEntry(dictionary, destIndex); entry.HashCode = hash; entry.Key = key; entry.Value = value; entry.Next = dictionary._buckets[bucket]; dictionary._buckets[bucket] = destIndex++; } chunk = chunk.Next; } dictionary._count = requiredCount; } [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)] internal static void AddRange(this RecyclableDictionary dictionary, RecyclablePriorityQueue> items) where TKey : notnull { int count = items._size; if (count == 0) { return; } int requiredCount = dictionary._count + count; EnsureCapacity(dictionary, requiredCount); int bucketsLength = dictionary._buckets.Length; while (requiredCount >= (bucketsLength * 3) / 4) { bucketsLength <<= 1; } if (bucketsLength != dictionary._buckets.Length) { ResizeBuckets(dictionary, bucketsLength); } int bucketMask = dictionary._buckets.Length - 1; int startIndex = dictionary._count; var source = items._heap; for (int i = 0; i < count; i++) { var kvp = source[i]; TKey key = kvp.Key; TValue value = kvp.Value; int hash = key.GetHashCode() & int.MaxValue; int bucket = hash & bucketMask; int index = dictionary._buckets[bucket]; while (index >= 0) { ref var check = ref GetEntry(dictionary, index); if (check.HashCode == hash && EqualityComparer.Default.Equals(check.Key, key)) { throw new ArgumentException("An element with the same key already exists.", nameof(items)); } index = check.Next; } ref var entry = ref GetEntry(dictionary, startIndex + i); entry.HashCode = hash; entry.Key = key; entry.Value = value; entry.Next = dictionary._buckets[bucket]; dictionary._buckets[bucket] = startIndex + i; } dictionary._count = requiredCount; } [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)] internal static void AddRange(this RecyclableDictionary dictionary, IReadOnlyList> items) where TKey : notnull { int count = items.Count; if (count == 0) { return; } int requiredCount = dictionary._count + count; EnsureCapacity(dictionary, requiredCount); int bucketsLength = dictionary._buckets.Length; while (requiredCount >= (bucketsLength * 3) / 4) { bucketsLength <<= 1; } if (bucketsLength != dictionary._buckets.Length) { ResizeBuckets(dictionary, bucketsLength); } int bucketMask = dictionary._buckets.Length - 1; int startIndex = dictionary._count; for (int i = 0; i < count; i++) { var kvp = items[i]; TKey key = kvp.Key; TValue value = kvp.Value; int hash = key.GetHashCode() & int.MaxValue; int bucket = hash & bucketMask; int index = dictionary._buckets[bucket]; while (index >= 0) { ref var check = ref GetEntry(dictionary, index); if (check.HashCode == hash && EqualityComparer.Default.Equals(check.Key, key)) { throw new ArgumentException("An element with the same key already exists.", nameof(items)); } index = check.Next; } ref var entry = ref GetEntry(dictionary, startIndex + i); entry.HashCode = hash; entry.Key = key; entry.Value = value; entry.Next = dictionary._buckets[bucket]; dictionary._buckets[bucket] = startIndex + i; } dictionary._count = requiredCount; } [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)] internal static void AddRange(this RecyclableDictionary dictionary, IEnumerable> items) where TKey : notnull { if (items is RecyclableDictionary recyclableDictionary) { AddRange(dictionary, recyclableDictionary); } else if (items is RecyclableList> recyclableList) { AddRange(dictionary, recyclableList); } else if (items is RecyclableLongList> recyclableLongList) { AddRange(dictionary, recyclableLongList); } else if (items is KeyValuePair[] array) { AddRange(dictionary, array); } else if (items is List> list) { AddRange(dictionary, list); } else if (items is ICollection> iCollection) { AddRange(dictionary, iCollection); } else if (items is ICollection collection) { AddRange(dictionary, collection); } else if (items is IReadOnlyList> readOnlyList) { AddRange(dictionary, readOnlyList); } else { foreach (var kvp in items) { dictionary.Add(kvp.Key, kvp.Value); } } } } }