Add more AddRange overloads for RecyclableHashSet
This commit is contained in:
1 parent
12b01c32ba
commit
1dc6c479ae
2 files changed
+311
No files matched your search
@@ -454,6 +454,281 @@ namespace Recyclable.Collections
|
||||
insertIndex++;
|
||||
}
|
||||
|
||||
set._count = insertIndex;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
internal static void AddRange<T>(this RecyclableHashSet<T> set, RecyclableLongList<T> items)
|
||||
where T : notnull
|
||||
{
|
||||
long longCount = items._longCount;
|
||||
if (longCount == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (longCount > int.MaxValue - set._count)
|
||||
{
|
||||
ThrowHelper.ThrowArgumentOutOfRangeException(nameof(items), $"The total number of items exceeds {int.MaxValue}");
|
||||
}
|
||||
|
||||
int count = (int)longCount;
|
||||
int fullBlocks = (int)(longCount >> items._blockSizePow2BitShift);
|
||||
int lastBlockLength = (int)(longCount & items._blockSizeMinus1);
|
||||
int requiredCount = set._count + count;
|
||||
EnsureCapacity(set, requiredCount);
|
||||
|
||||
int bucketsLength = set._buckets.Length;
|
||||
while (requiredCount >= (bucketsLength * 3) / 4)
|
||||
{
|
||||
bucketsLength <<= 1;
|
||||
}
|
||||
|
||||
if (bucketsLength != set._buckets.Length)
|
||||
{
|
||||
ResizeBuckets(set, bucketsLength);
|
||||
}
|
||||
|
||||
int bucketMask = set._buckets.Length - 1;
|
||||
int insertIndex = set._count;
|
||||
var blocks = items._memoryBlocks;
|
||||
int blockSize = items._blockSize;
|
||||
|
||||
for (int block = 0; block < fullBlocks; block++)
|
||||
{
|
||||
var source = blocks[block];
|
||||
for (int j = 0; j < blockSize; j++)
|
||||
{
|
||||
T value = source[j];
|
||||
int hash = value?.GetHashCode() & int.MaxValue ?? 0;
|
||||
int bucket = hash & bucketMask;
|
||||
|
||||
int index = set._buckets[bucket];
|
||||
bool exists = false;
|
||||
while (index >= 0)
|
||||
{
|
||||
ref var check = ref GetEntry(set, index);
|
||||
if (check.HashCode == hash && EqualityComparer<T>.Default.Equals(check.Value, value))
|
||||
{
|
||||
exists = true;
|
||||
break;
|
||||
}
|
||||
|
||||
index = check.Next;
|
||||
}
|
||||
|
||||
if (exists)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
ref var entry = ref GetEntry(set, insertIndex);
|
||||
entry.HashCode = hash;
|
||||
entry.Value = value!;
|
||||
entry.Next = set._buckets[bucket];
|
||||
set._buckets[bucket] = insertIndex;
|
||||
insertIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
if (lastBlockLength > 0)
|
||||
{
|
||||
var source = blocks[fullBlocks];
|
||||
for (int j = 0; j < lastBlockLength; j++)
|
||||
{
|
||||
T value = source[j];
|
||||
int hash = value?.GetHashCode() & int.MaxValue ?? 0;
|
||||
int bucket = hash & bucketMask;
|
||||
|
||||
int index = set._buckets[bucket];
|
||||
bool exists = false;
|
||||
while (index >= 0)
|
||||
{
|
||||
ref var check = ref GetEntry(set, index);
|
||||
if (check.HashCode == hash && EqualityComparer<T>.Default.Equals(check.Value, value))
|
||||
{
|
||||
exists = true;
|
||||
break;
|
||||
}
|
||||
|
||||
index = check.Next;
|
||||
}
|
||||
|
||||
if (exists)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
ref var entry = ref GetEntry(set, insertIndex);
|
||||
entry.HashCode = hash;
|
||||
entry.Value = value!;
|
||||
entry.Next = set._buckets[bucket];
|
||||
set._buckets[bucket] = insertIndex;
|
||||
insertIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
set._count = insertIndex;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
internal static void AddRange<T>(this RecyclableHashSet<T> set, RecyclableStack<T> items)
|
||||
where T : notnull
|
||||
{
|
||||
long longCount = items._count;
|
||||
if (longCount == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (longCount > int.MaxValue - set._count)
|
||||
{
|
||||
ThrowHelper.ThrowArgumentOutOfRangeException(nameof(items), $"The total number of items exceeds {int.MaxValue}");
|
||||
}
|
||||
|
||||
int count = (int)longCount;
|
||||
int requiredCount = set._count + count;
|
||||
EnsureCapacity(set, requiredCount);
|
||||
|
||||
int bucketsLength = set._buckets.Length;
|
||||
while (requiredCount >= (bucketsLength * 3) / 4)
|
||||
{
|
||||
bucketsLength <<= 1;
|
||||
}
|
||||
|
||||
if (bucketsLength != set._buckets.Length)
|
||||
{
|
||||
ResizeBuckets(set, bucketsLength);
|
||||
}
|
||||
|
||||
int bucketMask = set._buckets.Length - 1;
|
||||
int insertIndex = set._count;
|
||||
|
||||
var sourceChunk = items._current;
|
||||
while (sourceChunk.Previous != null)
|
||||
{
|
||||
sourceChunk = sourceChunk.Previous;
|
||||
}
|
||||
|
||||
while (sourceChunk != null)
|
||||
{
|
||||
var source = sourceChunk.Value;
|
||||
int sourceCount = sourceChunk.Index;
|
||||
for (int i = 0; i < sourceCount; i++)
|
||||
{
|
||||
T value = source[i];
|
||||
int hash = value?.GetHashCode() & int.MaxValue ?? 0;
|
||||
int bucket = hash & bucketMask;
|
||||
|
||||
int idx = set._buckets[bucket];
|
||||
bool exists = false;
|
||||
while (idx >= 0)
|
||||
{
|
||||
ref var check = ref GetEntry(set, idx);
|
||||
if (check.HashCode == hash && EqualityComparer<T>.Default.Equals(check.Value, value))
|
||||
{
|
||||
exists = true;
|
||||
break;
|
||||
}
|
||||
|
||||
idx = check.Next;
|
||||
}
|
||||
|
||||
if (exists)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
ref var entry = ref GetEntry(set, insertIndex);
|
||||
entry.HashCode = hash;
|
||||
entry.Value = value!;
|
||||
entry.Next = set._buckets[bucket];
|
||||
set._buckets[bucket] = insertIndex;
|
||||
insertIndex++;
|
||||
}
|
||||
|
||||
sourceChunk = sourceChunk.Next!;
|
||||
}
|
||||
|
||||
set._count = insertIndex;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
internal static void AddRange<T>(this RecyclableHashSet<T> set, RecyclableQueue<T> items)
|
||||
where T : notnull
|
||||
{
|
||||
long longCount = items._count;
|
||||
if (longCount == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (longCount > int.MaxValue - set._count)
|
||||
{
|
||||
ThrowHelper.ThrowArgumentOutOfRangeException(nameof(items), $"The total number of items exceeds {int.MaxValue}");
|
||||
}
|
||||
|
||||
int count = (int)longCount;
|
||||
int requiredCount = set._count + count;
|
||||
EnsureCapacity(set, requiredCount);
|
||||
|
||||
int bucketsLength = set._buckets.Length;
|
||||
while (requiredCount >= (bucketsLength * 3) / 4)
|
||||
{
|
||||
bucketsLength <<= 1;
|
||||
}
|
||||
|
||||
if (bucketsLength != set._buckets.Length)
|
||||
{
|
||||
ResizeBuckets(set, bucketsLength);
|
||||
}
|
||||
|
||||
int bucketMask = set._buckets.Length - 1;
|
||||
int insertIndex = set._count;
|
||||
|
||||
var chunk = items._head;
|
||||
while (chunk != null)
|
||||
{
|
||||
int idx = chunk.Bottom;
|
||||
int top = chunk.Top;
|
||||
var source = chunk.Value;
|
||||
|
||||
while (idx < top)
|
||||
{
|
||||
T value = source[idx++];
|
||||
int hash = value?.GetHashCode() & int.MaxValue ?? 0;
|
||||
int bucket = hash & bucketMask;
|
||||
|
||||
int checkIndex = set._buckets[bucket];
|
||||
bool exists = false;
|
||||
while (checkIndex >= 0)
|
||||
{
|
||||
ref var check = ref GetEntry(set, checkIndex);
|
||||
if (check.HashCode == hash && EqualityComparer<T>.Default.Equals(check.Value, value))
|
||||
{
|
||||
exists = true;
|
||||
break;
|
||||
}
|
||||
|
||||
checkIndex = check.Next;
|
||||
}
|
||||
|
||||
if (exists)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
ref var entry = ref GetEntry(set, insertIndex);
|
||||
entry.HashCode = hash;
|
||||
entry.Value = value!;
|
||||
entry.Next = set._buckets[bucket];
|
||||
set._buckets[bucket] = insertIndex;
|
||||
insertIndex++;
|
||||
}
|
||||
|
||||
chunk = chunk.Next;
|
||||
}
|
||||
|
||||
set._count = insertIndex;
|
||||
}
|
||||
|
||||
|
||||
@@ -125,5 +125,41 @@ namespace Recyclable.CollectionsTests
|
||||
_ = set.Should().Contain(new[] { 1, 2, 3 });
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddRangeShouldAddItemsFromLongList()
|
||||
{
|
||||
using var set = new RecyclableHashSet<int>();
|
||||
using var list = new RecyclableLongList<int>(new[] { 1, 2, 3 });
|
||||
|
||||
set.AddRange(list);
|
||||
|
||||
_ = set.Count.Should().Be(3);
|
||||
_ = set.Should().Contain(new[] { 1, 2, 3 });
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddRangeShouldAddItemsFromStack()
|
||||
{
|
||||
using var set = new RecyclableHashSet<int>();
|
||||
using var stack = new RecyclableStack<int>(new[] { 1, 2, 3 });
|
||||
|
||||
set.AddRange(stack);
|
||||
|
||||
_ = set.Count.Should().Be(3);
|
||||
_ = set.Should().Contain(new[] { 1, 2, 3 });
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddRangeShouldAddItemsFromQueue()
|
||||
{
|
||||
using var set = new RecyclableHashSet<int>();
|
||||
using var queue = new RecyclableQueue<int>(new[] { 1, 2, 3 });
|
||||
|
||||
set.AddRange(queue);
|
||||
|
||||
_ = set.Count.Should().Be(3);
|
||||
_ = set.Should().Contain(new[] { 1, 2, 3 });
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user