Peekable.cs (5291B)
1 using Std.Cmp; 2 using Std.Convert; 3 using Std.Maybe; 4 using Std.Num; 5 using Std.Ops; 6 using Std.Result; 7 using System; 8 using System.Diagnostics; 9 using System.Runtime.InteropServices; 10 #region Namespaces 11 namespace Std.Iter { 12 #region Types 13 [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Pack = 0)] 14 public struct Peekable<T, TIter>: IInto<Peekable<T, TIter>>, IIterator<T> where T: notnull where TIter: notnull, IIterator<T> { 15 16 #region Type-level Constructors 17 #endregion 18 19 #region Instance Constructors 20 public Peekable() => throw new InvalidOperationException("Parameterless constructor is not allowed to be called!"); 21 internal Peekable(TIter iter) => (_iter, _peeked) = (iter, Maybe<Maybe<T>>.None()); 22 #endregion 23 24 #region Type-level Fields 25 #endregion 26 27 #region Instance Fields 28 [System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE0044:Add readonly modifier", Justification = "Can't be readonly since we call mutable methods on it.")] 29 TIter _iter; 30 Maybe<Maybe<T>> _peeked; 31 #endregion 32 33 #region Type-level Properties 34 #endregion 35 36 #region Instance Properties 37 #endregion 38 39 #region Type-level Functions 40 #endregion 41 42 #region Instance Functions 43 public Result<Unit, ulong> AdvanceBy(ulong n) { 44 45 if (n == ulong.MinValue) { 46 return new(new Unit()); 47 } else { 48 var mbe = _peeked; 49 _peeked = Maybe<Maybe<T>>.None(); 50 return mbe.IsSome ? (mbe._some.IsNone ? new(ulong.MinValue) : _iter.AdvanceBy(n - 1ul)) : _iter.AdvanceBy(n); 51 } 52 } 53 public ulong Count() { 54 55 var mbe = _peeked; 56 _peeked = Maybe<Maybe<T>>.None(); 57 return mbe.IsSome ? (mbe._some.IsSome ? 1ul + _iter.Count() : ulong.MinValue) : _iter.Count(); 58 } 59 public override readonly bool Equals(object? _) => false; 60 public TInit Fold<TInit>(TInit init, Fn<TInit, T, TInit> f) where TInit: notnull { 61 62 var mbe = _peeked; 63 _peeked = Maybe<Maybe<T>>.None(); 64 65 if (mbe.IsSome) { 66 67 if (mbe._some.IsNone) { 68 return init; 69 } else { 70 init = f(init, mbe._some._some); 71 } 72 } 73 return _iter.Fold(init, f); 74 } 75 public override readonly int GetHashCode() => 0; 76 public readonly Peekable<T, TIter> Into() => this; 77 public Maybe<T> Last() { 78 79 var mbe = _peeked; 80 _peeked = Maybe<Maybe<T>>.None(); 81 Maybe<T> val; 82 83 if (mbe.IsSome) { 84 85 if (mbe._some.IsNone) { 86 return Maybe<T>.None(); 87 } else { 88 val = mbe._some; 89 } 90 } else { 91 val = Maybe<T>.None(); 92 } 93 return _iter.Last().Or(val); 94 } 95 public Maybe<T> Next() { 96 97 var mbe = _peeked; 98 _peeked = Maybe<Maybe<T>>.None(); 99 return mbe.IsSome ? mbe._some : _iter.Next(); 100 } 101 public Maybe<T> NextIf(FnIn<T, bool> f) { 102 103 var val = Next(); 104 105 if (val.IsSome && f(in val._some)) { 106 return new(val._some); 107 } else { 108 Trace.Assert(_peeked.IsNone); 109 _peeked = new(val); 110 return Maybe<T>.None(); 111 } 112 } 113 public Maybe<T> Peek() { 114 115 if (_peeked.IsNone) { 116 _peeked = new(_iter.Next()); 117 } 118 return _peeked._some; 119 } 120 public Prod<ulong, Maybe<ulong>> SizeHint() { 121 122 ulong len; 123 124 if (_peeked.IsSome) { 125 126 if (_peeked._some.IsNone) { 127 return new(ulong.MinValue, new(ulong.MinValue)); 128 } else { 129 len = 1ul; 130 } 131 } else { 132 len = ulong.MinValue; 133 } 134 var val = _iter.SizeHint(); 135 return new(val.Item0.SaturatingAdd(len), val.Item1.IsSome ? val.Item1._some.CheckedAdd(len) : Maybe<ulong>.None()); 136 } 137 public override readonly string ToString() => string.Empty; 138 public Result<TInit, TErr> TryFold<TInit, TErr>(TInit init, Fn<TInit, T, Result<TInit, TErr>> f) where TInit: notnull where TErr: notnull { 139 140 var mbe = _peeked; 141 _peeked = Maybe<Maybe<T>>.None(); 142 143 if (mbe.IsSome) { 144 145 if (mbe._some.IsNone) { 146 return new(init); 147 } else { 148 var res = f(init, mbe._some._some); 149 150 if (res.IsErr) { 151 return res; 152 } else { 153 init = res._ok; 154 } 155 } 156 } 157 return _iter.TryFold(init, f); 158 } 159 readonly Result<Peekable<T, TIter>, Bottom> ITryInto<Peekable<T, TIter>, Bottom>.TryInto() => new(this); 160 #endregion 161 162 #region Operators 163 #endregion 164 165 #region Types 166 #endregion 167 } 168 #endregion 169 170 #region Namespaces 171 #endregion 172 } 173 #endregion