Created
November 24, 2017 17:24
-
-
Save airbreather/8a87e30aaf46ade5ceae5f2b904b3f7e to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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