using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
#if USINGZ
namespace Clipper2ZLib
#else
namespace Clipper2Lib
#endif
{
internal class VertexPoolList : PooledList<Vertex>
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vertex Add(Point64 point, VertexFlags flags, Vertex? prev)
{
TryGrow();
Vertex poolVtx = _items[_size];
if (poolVtx == null)
{
poolVtx = new Vertex(point, flags, prev);
_items[_size] = poolVtx;
}
else
{
poolVtx.pt = point;
poolVtx.flags = flags;
poolVtx.prev = prev;
poolVtx.next = null;
}
_size++;
return poolVtx;
}
}
internal class OutPtPoolList : PooledList<OutPt>
{
public static bool UseOutPtPool = true;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public OutPt Add(Point64 pt, OutRec outrec)
{
TryGrow();
OutPt poolPt = _items[_size];
if (poolPt == null)
{
poolPt = new OutPt(pt, outrec);
_items[_size] = poolPt;
}
else
{
poolPt.pt = pt;
poolPt.outrec = outrec;
poolPt.next = poolPt;
poolPt.prev = poolPt;
poolPt.horz = null;
}
_size++;
outrec.outPtCount++;
return poolPt;
}
}
internal class OutRecPoolList : PooledList<OutRec>
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public OutRec Add()
{
TryGrow();
OutRec outRec = _items[_size];
if (outRec == null)
{
outRec = new OutRec();
_items[_size] = outRec;
}
else
{
outRec.idx = 0;
outRec.outPtCount = 0;
outRec.owner = null;
outRec.frontEdge = null;
outRec.backEdge = null;
outRec.pts = null;
outRec.bounds = new Rect64();
outRec.path = new Path64();
outRec.polypath = null;
outRec.isOpen = false;
outRec.splits?.Clear();
outRec.recursiveSplit = null;
}
_size++;
return outRec;
}
private static readonly Path64 tombStone = new Path64();
public override void Clear()
{
base.Clear();
for (int i = 0; i < _items.Length; i++)
{
OutRec active = _items[i];
if (active == null || active.path == tombStone) break;
active.path = tombStone;
active.owner = null;
active.frontEdge = null;
active.backEdge = null;
active.pts = null;
active.polypath = null;
active.recursiveSplit = null;
}
}
}
internal class HorzJoinPoolList : PooledList<HorzJoin>
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public HorzJoin Add(OutPt ltor, OutPt rtol)
{
TryGrow();
HorzJoin hJoin = _items[_size];
if (hJoin == null)
{
hJoin = new HorzJoin(ltor, rtol);
_items[_size] = hJoin;
}
else
{
hJoin.op1 = ltor;
hJoin.op2 = rtol;
}
_size++;
return hJoin;
}
}
internal abstract class PooledList<T> : IReadOnlyList<T> where T : class
{
private const int DefaultCapacity = 4;
protected T[] _items;
protected int _size;
public T this[int index]
{
get
{
if ((uint) index >= (uint) _size)
{
throw new ArgumentOutOfRangeException("index must be greater or equal to zero and less than the size of the collection");
};
return _items[index];
}
}
public int Count => _size;
public PooledList()
{
_items = Array.Empty<T>();
}
public PooledList(int capacity)
{
_items = new T[capacity];
}
public int Capacity
{
get => _items.Length;
set
{
if (value > _items.Length)
{
value = (int)RoundUpToPowerOf2((uint)value);
T[] newItems = new T[value];
if (_size > 0)
{
Array.Copy(_items, newItems, _size);
}
_items = newItems;
}
}
}
private static uint RoundUpToPowerOf2(uint value)
{
--value;
value |= value >> 1;
value |= value >> 2;
value |= value >> 4;
value |= value >> 8;
value |= value >> 16;
return value + 1;
}
public void EnsureCapacity(int capacity) { Capacity = capacity; }
protected void TryGrow()
{
int newSize = _size + 1;
if (newSize > _items.Length)
{
int newCapacity = _items.Length == 0 ? DefaultCapacity : 2 * _items.Length;
Capacity = newCapacity;
}
}
public virtual void Clear()
{
_size = 0;
}
public ListEnumerator<T> GetEnumerator()
{
return new ListEnumerator<T>(this);
}
IEnumerator<T> IEnumerable<T>.GetEnumerator()
{
return new ListEnumerator<T>(this);
}
IEnumerator IEnumerable.GetEnumerator()
{
return new ListEnumerator<T>(this);
}
internal struct ListEnumerator<T2> : IEnumerator<T2> where T2 : class
{
private readonly PooledList<T2> _list;
private int _index;
private T2? _current;
public ListEnumerator(PooledList<T2> list)
{
_list = list;
_index = 0;
_current = default;
}
public T2 Current => _current!;
object IEnumerator.Current => _current!;
public void Dispose()
{
}
public bool MoveNext()
{
int count = _list._size;
if ((uint) _index < (uint) count)
{
_current = _list[_index];
_index++;
return true;
}
return MoveNextRare(count);
}
private bool MoveNextRare(int count)
{
_index = count + 1;
_current = default;
return false;
}
public void Reset()
{
_index = 0;
_current = default;
}
}
}
}