Slice.cs 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. // RichTextKit
  2. // Copyright © 2019-2020 Topten Software. All Rights Reserved.
  3. //
  4. // Licensed under the Apache License, Version 2.0 (the "License"); you may
  5. // not use this product except in compliance with the License. You may obtain
  6. // a copy of the License at
  7. //
  8. // http://www.apache.org/licenses/LICENSE-2.0
  9. //
  10. // Unless required by applicable law or agreed to in writing, software
  11. // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  12. // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  13. // License for the specific language governing permissions and limitations
  14. // under the License.
  15. using System;
  16. using System.Collections.Generic;
  17. using System.Diagnostics;
  18. using System.Linq;
  19. using System.Runtime.CompilerServices;
  20. using System.Text;
  21. using System.Threading.Tasks;
  22. namespace Topten.RichTextKit.Utils
  23. {
  24. /// <summary>
  25. /// Represents a slice of an array
  26. /// </summary>
  27. /// <typeparam name="T">The array type</typeparam>
  28. [DebuggerDisplay("Length = {Length}")]
  29. public readonly struct Slice<T> : IEnumerable<T>, System.Collections.IEnumerable
  30. {
  31. /// <summary>
  32. /// Constructs a new slice covering the entire passed array.
  33. /// </summary>
  34. /// <param name="array"></param>
  35. public Slice(T[] array)
  36. : this(array, 0, array.Length)
  37. {
  38. }
  39. /// <summary>
  40. /// Constructs a new slice for part of the passed array.
  41. /// </summary>
  42. /// <param name="array"></param>
  43. /// <param name="start"></param>
  44. /// <param name="length"></param>
  45. public Slice(T[] array, int start, int length)
  46. {
  47. if (start < 0 || start + length > array.Length)
  48. throw new ArgumentOutOfRangeException($"Invalid sub-slice range ({start},{length}) with array length of {array.Length}");
  49. _array = array;
  50. _start = start;
  51. _length = length;
  52. }
  53. /// <summary>
  54. /// Gets the length of the array slice.
  55. /// </summary>
  56. public int Length
  57. {
  58. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  59. get
  60. {
  61. return _length;
  62. }
  63. }
  64. /// <summary>
  65. /// Clears the entire slice content
  66. /// </summary>
  67. public void Clear()
  68. {
  69. System.Array.Clear(_array, _start, _length);
  70. }
  71. /// <summary>
  72. /// Fill the slice with a specified value
  73. /// </summary>
  74. /// <param name="value"></param>
  75. public void Fill(T value)
  76. {
  77. for (int i = 0; i < _length; i++)
  78. {
  79. _array[i + _start] = value;
  80. }
  81. }
  82. /// <summary>
  83. /// Copy data from another slice into this one
  84. /// </summary>
  85. /// <param name="Source">The source data</param>
  86. public void Set(Slice<T> Source)
  87. {
  88. if (Source.Length != this.Length)
  89. throw new ArgumentException("Slices must have the same length");
  90. Array.Copy(Source.Underlying, Source.Start, Underlying, Start, Source.Length);
  91. }
  92. /// <summary>
  93. /// Gets a reference to an element in the slice
  94. /// </summary>
  95. /// <param name="index">The element index</param>
  96. /// <returns>A reference to the element value.</returns>
  97. public ref T this[int index]
  98. {
  99. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  100. get
  101. {
  102. if (index < 0 || index >= _length)
  103. throw new ArgumentOutOfRangeException(nameof(index));
  104. return ref _array[_start + index];
  105. }
  106. }
  107. [DebuggerBrowsable(DebuggerBrowsableState.Never)]
  108. readonly T[] _array;
  109. [DebuggerBrowsable(DebuggerBrowsableState.Never)]
  110. readonly int _start;
  111. [DebuggerBrowsable(DebuggerBrowsableState.Never)]
  112. readonly int _length;
  113. /// <summary>
  114. /// Creates a sub-slice of this slice
  115. /// </summary>
  116. /// <param name="start">The slice start index</param>
  117. /// <param name="length">The slice length</param>
  118. /// <returns>A new array slice</returns>
  119. public Slice<T> SubSlice(int start, int length)
  120. {
  121. return new Slice<T>(_array, _start + start, length);
  122. }
  123. /// <summary>
  124. /// Creates a subslice of an array slice, from a specified position to the end
  125. /// </summary>
  126. /// <param name="start">The slice start index</param>
  127. /// <returns>A new array slice</returns>
  128. public Slice<T> SubSlice(int start)
  129. {
  130. return SubSlice(start, Length - start);
  131. }
  132. /// <summary>
  133. /// Gets the slice contents as a new array
  134. /// </summary>
  135. /// <returns></returns>
  136. public T[] ToArray()
  137. {
  138. var array = new T[_length];
  139. System.Array.Copy(_array, _start, array, 0, _length);
  140. return array;
  141. }
  142. /// <summary>
  143. /// Creates a copy of this slice on a new underlying array
  144. /// </summary>
  145. /// <returns>A slice representing the copy</returns>
  146. public Slice<T> Copy()
  147. {
  148. return new Slice<T>(ToArray());
  149. }
  150. /// <summary>
  151. /// Gets the underlying array
  152. /// </summary>
  153. public T[] Underlying => _array;
  154. /// <summary>
  155. /// Gets the offset of this slice within the underlying array
  156. /// </summary>
  157. public int Start => _start;
  158. IEnumerator<T> IEnumerable<T>.GetEnumerator()
  159. {
  160. return new ArraySliceEnumerator<T>(_array, _start, _length);
  161. }
  162. System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
  163. {
  164. return new ArraySliceEnumerator<T>(_array, _start, _length);
  165. }
  166. /// <summary>
  167. /// Split this slice on a delimiter
  168. /// </summary>
  169. /// <param name="delimiter">The delimiter</param>
  170. /// <returns>An enumeration of slices</returns>
  171. public IEnumerable<Slice<T>> Split(T delimiter)
  172. {
  173. int start = 0;
  174. for (int i = 0; i < Length; i++)
  175. {
  176. if (this[i].Equals(delimiter))
  177. {
  178. yield return SubSlice(start, i - start);
  179. start = i + 1;
  180. }
  181. }
  182. yield return SubSlice(start, Length - start);
  183. }
  184. /// <summary>
  185. /// Find the first index of a specified value
  186. /// </summary>
  187. /// <param name="value">The value to search for</param>
  188. /// <returns>The index of the first occurance, or -1 if not found</returns>
  189. public int IndexOf(T value)
  190. {
  191. for (int i = 0; i < Length; i++)
  192. {
  193. if (this[i].Equals(value))
  194. {
  195. return i;
  196. }
  197. }
  198. return -1;
  199. }
  200. /// <summary>
  201. /// Find the first index of one or more valus
  202. /// </summary>
  203. /// <param name="values">The value to search for</param>
  204. /// <returns>The index of the first occurance, of -1 if not found</returns>
  205. public int IndexOfAny(params T[] values)
  206. {
  207. for (int i = 0; i < Length; i++)
  208. {
  209. if (values.Contains(this[i]))
  210. return i;
  211. }
  212. return -1;
  213. }
  214. /// <summary>
  215. /// Replace all instances of a value with another
  216. /// </summary>
  217. /// <param name="replace">The value to replace</param>
  218. /// <param name="with">The replacement value</param>
  219. public void Replace(T replace, T with)
  220. {
  221. for (int i = 0; i < Length; i++)
  222. {
  223. if (this[i].Equals(replace))
  224. this[i] = with;
  225. }
  226. }
  227. /// <summary>
  228. /// A shared empty slice of type T
  229. /// </summary>
  230. public static Slice<T> Empty => new Slice<T>();
  231. /// <summary>
  232. /// Get the slice as a Span
  233. /// </summary>
  234. /// <returns></returns>
  235. public Span<T> AsSpan() => new Span<T>(_array, _start, _length);
  236. }
  237. }