ImmutableArray<TKey, TValue>
class ImmutableArray<TKey, TValue> : IImmutableArray<TKey, TValue>, IEnumerable<TValue>, IEnumerable
using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
namespace Stashbox.Utils.Data.Immutable
{
internal class ImmutableArray<TKey, TValue> : IImmutableArray<TKey, TValue>, IEnumerable<TValue>, IEnumerable
{
private class ImmutableBucket : IImmutableArray<TKey, TValue>, IEnumerable<TValue>, IEnumerable
{
public readonly int Length;
private readonly KeyValue<TKey, TValue>[] repository;
public ref KeyValue<TKey, TValue> this[int i] {
get {
return ref repository[i];
}
}
public ImmutableBucket(KeyValue<TKey, TValue>[] repository)
{
this.repository = repository;
Length = repository.Length;
}
public IImmutableArray<TKey, TValue> Add(TKey key, TValue value)
{
if (Length < 32)
return AddInternal(key, value);
return new ImmutableArray<TKey, TValue>(new ImmutableBucket[1] {
this
}).AddInternal(key, value);
}
public IImmutableArray<TKey, TValue> AddOrUpdate(TKey key, TValue value, bool byRef, Func<TValue, TValue, TValue> update = null)
{
if (Length >= 32)
return new ImmutableArray<TKey, TValue>(new ImmutableBucket[1] {
this
}).AddOrUpdate(key, value, byRef, update);
if (!TryUpdate(key, value, byRef, out ImmutableBucket updated, update))
return AddInternal(key, value);
return updated;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public TValue GetOrDefault(TKey key, bool byRef)
{
int num = repository.Length;
for (int i = 0; i < num; i++) {
ref KeyValue<TKey, TValue> reference = ref repository[i];
if ((byRef && (object)reference.Key == (object)key) || (!byRef && object.Equals(reference.Key, key)))
return reference.Value;
}
return default(TValue);
}
internal ImmutableBucket AddInternal(TKey key, TValue value)
{
KeyValue<TKey, TValue>[] array = new KeyValue<TKey, TValue>[Length + 1];
Array.Copy(repository, array, Length);
array[Length] = new KeyValue<TKey, TValue>(key, value);
return new ImmutableBucket(array);
}
internal bool TryUpdate(TKey key, TValue value, bool byRef, out ImmutableBucket updated, Func<TValue, TValue, TValue> update = null)
{
updated = null;
int length = Length;
int num;
for (num = length - 1; num >= 0; num--) {
ref KeyValue<TKey, TValue> reference = ref repository[num];
if ((byRef && (object)reference.Key == (object)key) || (!byRef && object.Equals(reference.Key, key)))
break;
}
if (num == -1)
return false;
KeyValue<TKey, TValue>[] array = new KeyValue<TKey, TValue>[length];
Array.Copy(repository, array, length);
value = ((update == null) ? value : update(array[num].Value, value));
array[num] = new KeyValue<TKey, TValue>(key, value);
updated = new ImmutableBucket(array);
return true;
}
public IEnumerable<KeyValue<TKey, TValue>> Walk()
{
for (int i = 0; i < this.Length; i++) {
yield return this.repository[i];
}
}
public IEnumerator<TValue> GetEnumerator()
{
for (int i = 0; i < this.Length; i++) {
yield return this.repository[i].Value;
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
public static readonly IImmutableArray<TKey, TValue> Empty = new ImmutableArray<TKey, TValue>(Constants.EmptyArray<ImmutableBucket>());
private const int BucketLength = 32;
public readonly int Length;
private readonly ImmutableBucket[] repository;
private ImmutableArray(ImmutableBucket[] repository)
{
this.repository = repository;
Length = ((repository.Length != 0) ? ((repository.Length - 1) * 32 + repository[repository.Length - 1].Length) : 0);
}
public IImmutableArray<TKey, TValue> Add(TKey key, TValue value)
{
if (Length == 0)
return new ImmutableBucket(new KeyValue<TKey, TValue>[1] {
new KeyValue<TKey, TValue>(key, value)
});
return AddInternal(key, value);
}
public IImmutableArray<TKey, TValue> AddOrUpdate(TKey key, TValue value, bool byRef, Func<TValue, TValue, TValue> update = null)
{
if (Length == 0)
return new ImmutableBucket(new KeyValue<TKey, TValue>[1] {
new KeyValue<TKey, TValue>(key, value)
});
int num = repository.Length;
int num2 = num - 1;
ImmutableBucket updated = null;
while (num2 >= 0 && !repository[num2].TryUpdate(key, value, byRef, out updated, update)) {
num2--;
}
if (num2 == -1)
return AddInternal(key, value);
ImmutableBucket[] array = new ImmutableBucket[num];
Array.Copy(repository, array, num);
array[num2] = updated;
return new ImmutableArray<TKey, TValue>(array);
}
private IImmutableArray<TKey, TValue> AddInternal(TKey key, TValue value)
{
int num = repository.Length;
int num2 = num - 1;
ImmutableBucket immutableBucket = repository[num2];
if (immutableBucket.Length >= 32) {
ImmutableBucket[] array = new ImmutableBucket[num + 1];
Array.Copy(repository, array, num);
array[num] = new ImmutableBucket(new KeyValue<TKey, TValue>[1] {
new KeyValue<TKey, TValue>(key, value)
});
return new ImmutableArray<TKey, TValue>(array);
}
ImmutableBucket[] array2 = new ImmutableBucket[num];
Array.Copy(repository, array2, num);
array2[num2] = immutableBucket.AddInternal(key, value);
return new ImmutableArray<TKey, TValue>(array2);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public TValue GetOrDefault(TKey key, bool byRef)
{
int num = repository.Length;
for (int i = 0; i < num; i++) {
int length = repository[i].Length;
for (int j = 0; j < length; j++) {
ref KeyValue<TKey, TValue> reference = ref repository[i][j];
if ((byRef && (object)reference.Key == (object)key) || (!byRef && object.Equals(reference.Key, key)))
return reference.Value;
}
}
return default(TValue);
}
public IEnumerable<KeyValue<TKey, TValue>> Walk()
{
int length = this.repository.Length;
for (int j = 0; j < length; j++) {
int bucketLength = this.repository[j].Length;
for (int i = 0; i < bucketLength; i++) {
yield return this.repository[j][i];
}
}
}
public IEnumerator<TValue> GetEnumerator()
{
int length = this.repository.Length;
for (int j = 0; j < length; j++) {
int bucketLength = this.repository[j].Length;
for (int i = 0; i < bucketLength; i++) {
yield return this.repository[j][i].Value;
}
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}