first commit
This commit is contained in:
87
Core/Collections/DataMap.cs
Normal file
87
Core/Collections/DataMap.cs
Normal 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();
|
||||
}
|
||||
10
Core/Collections/IDataMap.cs
Normal file
10
Core/Collections/IDataMap.cs
Normal 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
12
Core/Collections/IMap.cs
Normal 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
172
Core/Collections/Map.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
9
Core/Collections/MapPoint.cs
Normal file
9
Core/Collections/MapPoint.cs
Normal 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;
|
||||
}
|
||||
Reference in New Issue
Block a user