/LanguageExt.Core/DataTypes/Stack/Stck.cs

https://github.com/louthy/language-ext · C# · 314 lines · 133 code · 36 blank · 145 comment · 9 complexity · d0701fb2b340d580b0422f060962297f MD5 · raw file

  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.Diagnostics.Contracts;
  5. using System.Linq;
  6. using System.Runtime.CompilerServices;
  7. using LanguageExt.ClassInstances;
  8. using static LanguageExt.Prelude;
  9. namespace LanguageExt
  10. {
  11. /// <summary>
  12. /// Immutable stack
  13. /// </summary>
  14. /// <typeparam name="A">Stack element type</typeparam>
  15. [Serializable]
  16. public struct Stck<A> :
  17. IEnumerable<A>,
  18. IEnumerable,
  19. IEquatable<Stck<A>>
  20. {
  21. public readonly static Stck<A> Empty = new Stck<A>(StckInternal<A>.Empty);
  22. int hashCode;
  23. readonly StckInternal<A> value;
  24. StckInternal<A> Value => value ?? StckInternal<A>.Empty;
  25. /// <summary>
  26. /// Default ctor
  27. /// </summary>
  28. internal Stck(StckInternal<A> value)
  29. {
  30. this.value = value;
  31. this.hashCode = 0;
  32. }
  33. /// <summary>
  34. /// Ctor that takes an initial state as an IEnumerable T
  35. /// </summary>
  36. public Stck(IEnumerable<A> initial)
  37. {
  38. value = initial.Any() ? new StckInternal<A>(initial) : StckInternal<A>.Empty;
  39. this.hashCode = 0;
  40. }
  41. /// <summary>
  42. /// Reference version for use in pattern-matching
  43. /// </summary>
  44. [Pure]
  45. public SeqCase<A> Case =>
  46. Seq(Value).Case;
  47. /// <summary>
  48. /// Number of items in the stack
  49. /// </summary>
  50. [Pure]
  51. public int Count => Value.Count;
  52. /// <summary>
  53. /// Reverses the order of the items in the stack
  54. /// </summary>
  55. /// <returns></returns>
  56. [Pure]
  57. public Stck<A> Reverse() =>
  58. new Stck<A>(Value.Reverse());
  59. /// <summary>
  60. /// True if the stack is empty
  61. /// </summary>
  62. [Pure]
  63. public bool IsEmpty =>
  64. Count == 0;
  65. /// <summary>
  66. /// Clear the stack (returns Empty)
  67. /// </summary>
  68. /// <returns>Stck.Empty of T</returns>
  69. [Pure]
  70. public Stck<A> Clear() =>
  71. Empty;
  72. /// <summary>
  73. /// Get enumerator
  74. /// </summary>
  75. /// <returns>IEnumerator of T</returns>
  76. [Pure]
  77. public IEnumerator<A> GetEnumerator() =>
  78. AsEnumerable().GetEnumerator();
  79. /// <summary>
  80. /// Returns the stack as a Sq. The first item in the sequence
  81. /// will be the item at the top of the stack.
  82. /// </summary>
  83. /// <returns>IEnumerable of T</returns>
  84. [Pure]
  85. public Seq<A> ToSeq() =>
  86. Seq(Value);
  87. /// <summary>
  88. /// Format the collection as `[a, b, c, ...]`
  89. /// The elipsis is used for collections over 50 items
  90. /// To get a formatted string with all the items, use `ToFullString`
  91. /// or `ToFullArrayString`.
  92. /// </summary>
  93. [Pure]
  94. public override string ToString() =>
  95. CollectionFormat.ToShortArrayString(this, Count);
  96. /// <summary>
  97. /// Format the collection as `a, b, c, ...`
  98. /// </summary>
  99. [Pure]
  100. public string ToFullString(string separator = ", ") =>
  101. CollectionFormat.ToFullString(this, separator);
  102. /// <summary>
  103. /// Format the collection as `[a, b, c, ...]`
  104. /// </summary>
  105. [Pure]
  106. public string ToFullArrayString(string separator = ", ") =>
  107. CollectionFormat.ToFullArrayString(this, separator);
  108. /// <summary>
  109. /// Returns the stack as an IEnumerable. The first item in the enumerable
  110. /// will be the item at the top of the stack.
  111. /// </summary>
  112. /// <returns>IEnumerable of T</returns>
  113. [Pure]
  114. public IEnumerable<A> AsEnumerable() =>
  115. Value;
  116. /// <summary>
  117. /// Impure iteration of the bound value in the structure
  118. /// </summary>
  119. /// <returns>
  120. /// Returns the original unmodified structure
  121. /// </returns>
  122. public Stck<A> Do(Action<A> f)
  123. {
  124. this.Iter(f);
  125. return this;
  126. }
  127. /// <summary>
  128. /// Return the item on the top of the stack without affecting the stack itself
  129. /// NOTE: Will throw an InvalidOperationException if the stack is empty
  130. /// </summary>
  131. /// <exception cref="InvalidOperationException">Stack is empty</exception>
  132. /// <returns>Top item value</returns>
  133. [Pure]
  134. public A Peek() =>
  135. Value.Peek();
  136. /// <summary>
  137. /// Peek and match
  138. /// </summary>
  139. /// <param name="Some">Handler if there is a value on the top of the stack</param>
  140. /// <param name="None">Handler if the stack is empty</param>
  141. /// <returns>Untouched stack (this)</returns>
  142. [Pure]
  143. public Stck<A> Peek(Action<A> Some, Action None) =>
  144. new Stck<A>(Value.Peek(Some, None));
  145. /// <summary>
  146. /// Peek and match
  147. /// </summary>
  148. /// <typeparam name="R">Return type</typeparam>
  149. /// <param name="Some">Handler if there is a value on the top of the stack</param>
  150. /// <param name="None">Handler if the stack is empty</param>
  151. /// <returns>Return value from Some or None</returns>
  152. [Pure]
  153. public R Peek<R>(Func<A, R> Some, Func<R> None) =>
  154. Value.Peek(Some, None);
  155. /// <summary>
  156. /// Safely return the item on the top of the stack without affecting the stack itself
  157. /// </summary>
  158. /// <returns>Returns the top item value, or None</returns>
  159. [Pure]
  160. public Option<A> TryPeek() =>
  161. Value.TryPeek();
  162. /// <summary>
  163. /// Pop an item off the top of the stack
  164. /// NOTE: Will throw an InvalidOperationException if the stack is empty
  165. /// </summary>
  166. /// <exception cref="InvalidOperationException">Stack is empty</exception>
  167. /// <returns>Stack with the top item popped</returns>
  168. [Pure]
  169. public Stck<A> Pop() =>
  170. new Stck<A>(Value.Pop());
  171. /// <summary>
  172. /// Safe pop
  173. /// </summary>
  174. /// <returns>Tuple of popped stack and optional top-of-stack value</returns>
  175. [Pure]
  176. public (Stck<A> Stack, Option<A> Value) TryPop() =>
  177. Value.TryPop().MapFirst(x => new Stck<A>(x));
  178. /// <summary>
  179. /// Pop and match
  180. /// </summary>
  181. /// <param name="Some">Handler if there is a value on the top of the stack</param>
  182. /// <param name="None">Handler if the stack is empty</param>
  183. /// <returns>Popped stack</returns>
  184. [Pure]
  185. public Stck<A> Pop(Action<A> Some, Action None) =>
  186. new Stck<A>(Value.Pop(Some, None));
  187. /// <summary>
  188. /// Pop and match
  189. /// </summary>
  190. /// <typeparam name="R">Return type</typeparam>
  191. /// <param name="Some">Handler if there is a value on the top of the stack</param>
  192. /// <param name="None">Handler if the stack is empty</param>
  193. /// <returns>Return value from Some or None</returns>
  194. [Pure]
  195. public R Pop<R>(Func<Stck<A>, A, R> Some, Func<R> None) =>
  196. Value.Pop((s, t) => Some(new Stck<A>(s), t), None);
  197. /// <summary>
  198. /// Push an item onto the stack
  199. /// </summary>
  200. /// <param name="value">Item to push</param>
  201. /// <returns>New stack with the pushed item on top</returns>
  202. [Pure]
  203. public Stck<A> Push(A value) =>
  204. new Stck<A>(Value.Push(value));
  205. /// <summary>
  206. /// Get enumerator
  207. /// </summary>
  208. /// <returns>IEnumerator of T</returns>
  209. [Pure]
  210. IEnumerator IEnumerable.GetEnumerator() =>
  211. AsEnumerable().GetEnumerator();
  212. /// <summary>
  213. /// Implicit conversion from an untyped empty list
  214. /// </summary>
  215. [Pure]
  216. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  217. public static implicit operator Stck<A>(SeqEmpty _) =>
  218. Empty;
  219. /// <summary>
  220. /// Append another stack to the top of this stack
  221. /// The rhs will be reversed and pushed onto 'this' stack. That will
  222. /// maintain the order of the items in the resulting stack. So the top
  223. /// of 'rhs' will be the top of the newly created stack. 'this' stack
  224. /// will be under the 'rhs' stack.
  225. /// </summary>
  226. [Pure]
  227. public static Stck<A> operator +(Stck<A> lhs, Stck<A> rhs) =>
  228. lhs.Append(rhs);
  229. /// <summary>
  230. /// Append another stack to the top of this stack
  231. /// The rhs will be reversed and pushed onto 'this' stack. That will
  232. /// maintain the order of the items in the resulting stack. So the top
  233. /// of 'rhs' will be the top of the newly created stack. 'this' stack
  234. /// will be under the 'rhs' stack.
  235. /// </summary>
  236. /// <param name="rhs">Stack to append</param>
  237. /// <returns>Appended stacks</returns>
  238. [Pure]
  239. public Stck<A> Append(Stck<A> rhs) =>
  240. new Stck<A>(Value.Append(rhs.Value));
  241. /// <summary>
  242. /// Subtract one stack from another: lhs except rhs
  243. /// </summary>
  244. [Pure]
  245. public static Stck<A> operator -(Stck<A> lhs, Stck<A> rhs) =>
  246. lhs.Subtract(rhs);
  247. /// <summary>
  248. /// Append another stack to the top of this stack
  249. /// The rhs will be reversed and pushed onto 'this' stack. That will
  250. /// maintain the order of the items in the resulting stack. So the top
  251. /// of 'rhs' will be the top of the newly created stack. 'this' stack
  252. /// will be under the 'rhs' stack.
  253. /// </summary>
  254. /// <param name="rhs">Stack to append</param>
  255. /// <returns>Appended stacks</returns>
  256. [Pure]
  257. public Stck<A> Subtract(Stck<A> rhs) =>
  258. new Stck<A>(Enumerable.Except(this, rhs));
  259. [Pure]
  260. public static bool operator ==(Stck<A> lhs, Stck<A> rhs) =>
  261. lhs.Equals(rhs);
  262. [Pure]
  263. public static bool operator !=(Stck<A> lhs, Stck<A> rhs) =>
  264. !(lhs == rhs);
  265. [Pure]
  266. public override int GetHashCode() =>
  267. hashCode == 0
  268. ? hashCode = FNV32.Hash<HashableDefault<A>, A>(this)
  269. : hashCode;
  270. [Pure]
  271. public override bool Equals(object obj) =>
  272. obj is Stck<A> && Equals((Stck<A>)obj);
  273. [Pure]
  274. public bool Equals(Stck<A> other) =>
  275. (hashCode == 0 || other.hashCode == 0 || hashCode == other.hashCode) &&
  276. default(EqEnumerable<A>).Equals(this.Value, other.Value);
  277. }
  278. }