Code/Concurrent/ConcurrentArray.cs
using System;
using System.Collections;
using System.Collections.Generic;
namespace ExtendedCollections.Concurrent;
public class ConcurrentArray<T> : IEnumerable<T>
{
public int Length { get; }
private readonly T[] _values;
private readonly object[] _locks;
public ConcurrentArray(int size)
{
Length = size;
_values = new T[size];
_locks = new object[size];
for(int i = 0; i < size; ++i)
_locks[i] = new();
}
public void Clear()
{
lock(_locks)
{
Array.Clear(_values);
}
}
public void CopyTo(T[] array, int arrayIndex)
{
ArgumentNullException.ThrowIfNull(array);
if(arrayIndex < 0)
throw new ArgumentOutOfRangeException(nameof(arrayIndex), "Index is less than 0.");
if(array.Length - arrayIndex < Length)
throw new ArgumentException("Array has not enough space to copy to.", nameof(array));
lock(_locks)
{
_values.CopyTo(array, arrayIndex);
}
}
public int IndexOf(T item)
{
lock(_locks)
{
return Array.IndexOf(_values, item);
}
}
public T GetOrAdd(int index, Func<T> provider)
{
lock(_locks)
{
lock(_locks[index])
{
var value = _values[index];
if(value is null)
{
value = provider();
_values[index] = value;
}
return value;
}
}
}
public T GetOrAdd(int index, T value)
{
lock(_locks)
{
lock(_locks[index])
{
var oldValue = _values[index];
if(oldValue is null)
{
_values[index] = value;
return value;
}
return oldValue;
}
}
}
public T this[int index]
{
get
{
lock(_locks)
{
lock(_locks[index])
{
return _values[index];
}
}
}
set
{
lock(_locks)
{
lock(_locks[index])
{
_values[index] = value;
}
}
}
}
public IEnumerator<T> GetEnumerator()
{
for(int i = 0; i < Length; ++i)
{
lock(_locks)
{
lock(_locks[i])
{
yield return _values[i];
}
}
}
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}