155 lines
4.5 KiB
C#
155 lines
4.5 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using KitsuneCafe.Sys.Numerics;
|
|
|
|
namespace KitsuneCafe.Sys
|
|
{
|
|
public record Index(int Value, bool IsFromEnd = false)
|
|
{
|
|
public static Index Start = new(0);
|
|
public static Index End = new(0, true);
|
|
public static Index NegativeInfinity = new(int.MinValue);
|
|
public static Index Infinity = new(int.MaxValue);
|
|
|
|
public static Index FromStart(int value) => new(value);
|
|
public static Index FromEnd(int value) => new(value, true);
|
|
|
|
public int GetOffset(int length) => IsFromEnd ? length - Value : Value;
|
|
|
|
public static implicit operator int(Index value) => value.IsFromEnd ? -value.Value : value.Value;
|
|
public static implicit operator Index(int value) => new(value, value < 0);
|
|
public static implicit operator global::System.Index(Index index) => new(index.Value, index.IsFromEnd);
|
|
public static implicit operator Index(global::System.Index index) => new(index.Value, index.IsFromEnd);
|
|
}
|
|
|
|
public record Range(Index Start, Index End)
|
|
{
|
|
public static Range All = new(Index.Start, Index.End);
|
|
|
|
public static Range StartAt(Index start) => new(start, Index.End);
|
|
public static Range EndAt(Index end) => new(Index.Start, end);
|
|
public static Range OfLength(Index offset, int length) => new(offset, offset + length);
|
|
|
|
public ClampingRange Clamp() => new(Start, End);
|
|
public ShiftingRange Shift() => new(Start, End);
|
|
public WrappingRange Wrap() => new(Start, End);
|
|
|
|
public static implicit operator System.Range(Range range) => new(range.Start, range.End);
|
|
public static implicit operator Range(System.Range range) => new(range.Start, range.End);
|
|
|
|
public virtual (int Offset, int Length) GetOffsetAndLength(int length)
|
|
{
|
|
var start = Start.GetOffset(length);
|
|
var end = End.GetOffset(length);
|
|
return (start, end - start);
|
|
}
|
|
|
|
public virtual bool Contains(int length, Index index)
|
|
{
|
|
var start = Start.GetOffset(length);
|
|
var end = End.GetOffset(length);
|
|
return index >= start && index < end;
|
|
}
|
|
|
|
public virtual IEnumerable<int> Indices(int length)
|
|
{
|
|
var (start, len) = GetOffsetAndLength(length);
|
|
UnityEngine.Debug.Log($"making indices: start {start}, length {len}");
|
|
|
|
for (int i = start; i < start + len; i++)
|
|
{
|
|
yield return i;
|
|
}
|
|
}
|
|
|
|
public virtual int[] ToArray(int length)
|
|
{
|
|
UnityEngine.Debug.Log($"making array of indices of length {length}");
|
|
return Indices(length).ToArray();
|
|
}
|
|
|
|
public void Deconstruct(out Index start, out Index end)
|
|
{
|
|
start = Start;
|
|
end = End;
|
|
}
|
|
}
|
|
|
|
public record ClampingRange(Index Start, Index End) : Range(Start, End)
|
|
{
|
|
public override (int Offset, int Length) GetOffsetAndLength(int length)
|
|
{
|
|
var (start, len) = base.GetOffsetAndLength(length);
|
|
return (start, Math.Clamp(len, 0, length - 1));
|
|
}
|
|
}
|
|
|
|
public record ShiftingRange(Index Start, Index End) : Range(Start, End)
|
|
{
|
|
public override (int Offset, int Length) GetOffsetAndLength(int length)
|
|
{
|
|
|
|
var (start, len) = base.GetOffsetAndLength(length);
|
|
|
|
int newStart = start;
|
|
int newEnd = start + len;
|
|
|
|
if (newEnd > length)
|
|
{
|
|
int offset = newEnd - length;
|
|
newStart -= offset;
|
|
newEnd -= offset;
|
|
}
|
|
|
|
if (newStart < 0)
|
|
{
|
|
int shiftAmount = 0 - newStart;
|
|
newStart += shiftAmount;
|
|
newEnd += shiftAmount;
|
|
}
|
|
|
|
int newLength = Math.Min(newEnd - newStart, length);
|
|
|
|
int newOffset = newStart;
|
|
|
|
return (newOffset, newLength);
|
|
}
|
|
};
|
|
|
|
public record WrappingRange(Index Start, Index End) : Range(Start, End)
|
|
{
|
|
public static WrappingRange WrapFrom(Index start) => new(start, Index.Infinity);
|
|
public static WrappingRange WrapUntil(Index end) => new(Index.NegativeInfinity, end);
|
|
|
|
public override (int Offset, int Length) GetOffsetAndLength(int length)
|
|
{
|
|
var start = Start.GetOffset(length);
|
|
var end = End.GetOffset(length);
|
|
var len = start + Math.Abs(end - start);
|
|
return (start, len);
|
|
}
|
|
|
|
public override bool Contains(int length, Index index)
|
|
{
|
|
if (Start <= End)
|
|
{
|
|
return base.Contains(length, index);
|
|
}
|
|
else
|
|
{
|
|
return (Start <= index && index < length) || (0 <= index && index < End);
|
|
}
|
|
}
|
|
|
|
public override IEnumerable<int> Indices(int length)
|
|
{
|
|
var (start, len) = GetOffsetAndLength(length);
|
|
|
|
for (int i = start; i < len; i++)
|
|
{
|
|
yield return i % length;
|
|
}
|
|
}
|
|
}
|
|
}
|