first commit

This commit is contained in:
2023-12-14 21:48:48 +04:00
commit ef5d53a67f
22 changed files with 1387 additions and 0 deletions

View File

@@ -0,0 +1,87 @@
using System.Numerics;
namespace Just.Core.Collections;
public class DataMap<T> : Map<T>, IDataMap<T>, ICloneable
where T : IComparisonOperators<T, T, bool>, IEqualityOperators<T, T, bool>
{
internal MapPoint<T> MinCache = default;
internal MapPoint<T> MaxCache = default;
internal DataMap(int width, int height, T[] values)
: base(width, height, values)
{
}
public DataMap(ReadOnlySpan<T> values, int width, int height)
: base(values, width, height)
{
}
public DataMap(T[] values, int width, int height)
: base(values, width, height)
{
}
public DataMap(T[,] values)
: base(values)
{
}
[Pure] public MapPoint<T> Min
{
get
{
if (MinCache.Map is null) FindMinMax();
return MinCache;
}
}
[Pure] public MapPoint<T> Max
{
get
{
if (MaxCache.Map is null) FindMinMax();
return MaxCache;
}
}
private void FindMinMax()
{
var data = _values.AsSpan();
T min = data[0];
T max = data[0];
int minId = 0;
int maxId = 0;
for (int i = 0; i < data.Length; i++)
{
if (data[i] < min)
{
min = data[i];
minId = i;
continue;
}
if (data[i] > max)
{
max = data[i];
maxId = i;
}
}
MinCache = new(min, minId % Width, minId / Width, this);
MaxCache = new(max, maxId % Width, maxId / Width, this);
}
[Pure] public DataMap<T> Clone()
{
var clone = new DataMap<T>(Width, Height, [.. _values]);
clone.MinCache = new(clone._values[(MinCache.Y * Width) + MinCache.X], MinCache.X, MinCache.Y, clone);
clone.MaxCache = new(clone._values[(MaxCache.Y * Width) + MaxCache.X], MaxCache.X, MaxCache.Y, clone);
return clone;
}
object ICloneable.Clone() => Clone();
}

View File

@@ -0,0 +1,10 @@
using System.Numerics;
namespace Just.Core.Collections;
public interface IDataMap<T> : IMap<T>, ICloneable
where T : IComparisonOperators<T, T, bool>, IEqualityOperators<T, T, bool>
{
MapPoint<T> Min { get; }
MapPoint<T> Max { get; }
}

12
Core/Collections/IMap.cs Normal file
View File

@@ -0,0 +1,12 @@
namespace Just.Core.Collections;
public interface IMap<T> : IReadOnlyCollection<MapPoint<T>>
{
int Width { get; }
int Height { get; }
ref readonly T this[int x, int y] { get; }
ref readonly T this[double x, double y] { get; }
MapPoint<T> Get(int x, int y);
MapPoint<T> Get(double x, double y);
T[,] ToArray();
}

172
Core/Collections/Map.cs Normal file
View File

@@ -0,0 +1,172 @@
using System.Collections;
namespace Just.Core.Collections;
public class Map<T> : IMap<T>
{
internal readonly T[] _values;
internal Map(int width, int height, T[] values)
{
Width = width;
Height = height;
_values = values;
}
public Map(ReadOnlySpan<T> values, int width, int height)
{
ArgumentOutOfRangeException.ThrowIfLessThan(width, 1);
ArgumentOutOfRangeException.ThrowIfLessThan(height, 1);
ArgumentOutOfRangeException.ThrowIfNotEqual(width * height, values.Length);
Width = width;
Height = height;
_values = new T[values.Length];
values.CopyTo(_values);
}
public Map(T[] values, int width, int height)
{
ArgumentNullException.ThrowIfNull(values);
ArgumentOutOfRangeException.ThrowIfLessThan(width, 1);
ArgumentOutOfRangeException.ThrowIfLessThan(height, 1);
ArgumentOutOfRangeException.ThrowIfNotEqual(width * height, values.Length);
Width = width;
Height = height;
_values = new T[Width * Height];
values.CopyTo(_values.AsSpan());
}
public Map(T[,] values)
{
ArgumentNullException.ThrowIfNull(values);
ArgumentOutOfRangeException.ThrowIfZero(values.Length);
Width = values.GetLength(0);
Height = values.GetLength(1);
_values = new T[Width * Height];
var data = _values.AsSpan();
for (int y = 0; y < Height; y++)
{
int idy = y * Width;
for (int x = 0; x < Width; x++)
{
int id = idy + x;
data[id] = values[x, y];
}
}
}
[Pure] public ReadOnlySpan<T> AsSpan() => _values;
[Pure] public ReadOnlyMemory<T> AsMemory() => _values;
public int Width { get; }
public int Height { get; }
public int Count => _values.Length;
[Pure] public ref readonly T this[int x, int y]
{
get
{
x = Math.Clamp(x, 0, Width);
y = Math.Clamp(y, 0, Height);
return ref _values[(y * Width) + x];
}
}
[Pure] public ref readonly T this[double x, double y]
{
get
{
int xi = Math.Clamp((int)x, 0, Width - 1);
int yi = Math.Clamp((int)y, 0, Height - 1);
return ref _values[(yi * Width) + xi];
}
}
[Pure] public MapPoint<T> Get(int x, int y)
{
x = Math.Clamp(x, 0, Width - 1);
y = Math.Clamp(y, 0, Height - 1);
return new(_values[(y * Width) + x], x, y, this);
}
[Pure] public MapPoint<T> Get(double x, double y)
{
int xi = Math.Clamp((int)x, 0, Width - 1);
int yi = Math.Clamp((int)y, 0, Height - 1);
return new(_values[(yi * Width) + xi], xi, yi, this);
}
[Pure] public T[,] ToArray()
{
T[,] arr = new T[Width, Height];
var data = _values.AsSpan();
for (int y = 0; y < Height; y++)
{
int idy = y * Width;
for (int x = 0; x < Width; x++)
{
int id = idy + x;
arr[x, y] = data[id];
}
}
return arr;
}
public Enumerator GetEnumerator() => new(this);
IEnumerator<MapPoint<T>> IEnumerable<MapPoint<T>>.GetEnumerator() => new Enumerator(this);
IEnumerator IEnumerable.GetEnumerator() => new Enumerator(this);
public struct Enumerator : IEnumerator<MapPoint<T>>, IEnumerator
{
private readonly Map<T> _map;
private int _index;
private MapPoint<T> _current;
internal Enumerator(Map<T> map)
{
_map = map;
_index = 0;
_current = default;
}
public readonly void Dispose() { }
public bool MoveNext()
{
if ((uint)_index < (uint)_map.Count)
{
_current = new(
_map._values[_index],
_index % _map.Width,
_index / _map.Width,
_map);
_index++;
return true;
}
_index = _map.Count + 1;
_current = default;
return false;
}
public readonly MapPoint<T> Current => _current!;
readonly object? IEnumerator.Current
{
get
{
if (_index == 0 || _index == _map.Count + 1)
{
throw new InvalidOperationException();
}
return Current;
}
}
void IEnumerator.Reset()
{
_index = 0;
_current = default;
}
}
}

View File

@@ -0,0 +1,9 @@
namespace Just.Core.Collections;
public readonly struct MapPoint<T>(T value, int x, int y, IMap<T> map)
{
public readonly T Value = value;
public IMap<T> Map { get; } = map;
public int X { get; } = x;
public int Y { get; } = y;
}