Skip to content

Instantly share code, notes, and snippets.

@airbreather
Created November 24, 2017 17:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save airbreather/8a87e30aaf46ade5ceae5f2b904b3f7e to your computer and use it in GitHub Desktop.
Save airbreather/8a87e30aaf46ade5ceae5f2b904b3f7e to your computer and use it in GitHub Desktop.
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace AirBreather.Madness
{
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct SlenderList<T>
{
private const int MAX_CNT = 4;
private T _0;
private T _1;
private T _2;
private T _3;
private int cnt;
private T[] residue;
public T this[int index]
{
get => At(ref this, index);
set => At(ref this, index) = value;
}
public int Count => this.cnt;
public void Add(T item) => At(ref this, this.cnt++) = item;
public Enumerator GetEnumerator() => new Enumerator(ref this);
private static ref T At(ref SlenderList<T> @this, int offset)
{
if (offset < MAX_CNT)
{
return ref Unsafe.Add(ref @this._0, offset);
}
// put this (hopefully) unlikely slow path into a separate method.
// the JIT will be more likely to inline this method that way.
return ref At_Residue(ref @this, offset);
}
private static ref T At_Residue(ref SlenderList<T> @this, int offset)
{
if (@this.residue == null)
{
@this.residue = new T[4];
}
int residueOffset = offset - MAX_CNT;
#if PARANOID
if (residueOffset >= (Unsafe.SizeOf<T>() == 1 ? 2147483591 : 2146435071))
{
throw new NotSupportedException("Way too big.");
}
#endif
int residueLength = @this.residue.Length;
if (residueLength <= residueOffset)
{
do
{
residueLength = residueLength * 2;
}
while (residueLength <= residueOffset);
Array.Resize(ref @this.residue, residueLength);
}
return ref @this.residue[residueOffset];
}
public struct Enumerator
{
private SlenderList<T> lst;
private int idx;
internal Enumerator(ref SlenderList<T> lst)
{
this.lst = lst;
this.idx = -1;
}
public bool MoveNext() => this.idx < this.lst.cnt &&
++this.idx < this.lst.cnt;
public T Current => this.lst[this.idx];
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment