// RichTextKit // Copyright © 2019-2020 Topten Software. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); you may // not use this product except in compliance with the License. You may obtain // a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations // under the License. using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Runtime.CompilerServices; using System.Text; using System.Threading.Tasks; namespace Topten.RichTextKit.Utils { /// /// Represents a slice of an array /// /// The array type [DebuggerDisplay("Length = {Length}")] public readonly struct Slice : IEnumerable, System.Collections.IEnumerable { /// /// Constructs a new slice covering the entire passed array. /// /// public Slice(T[] array) : this(array, 0, array.Length) { } /// /// Constructs a new slice for part of the passed array. /// /// /// /// public Slice(T[] array, int start, int length) { if (start < 0 || start + length > array.Length) throw new ArgumentOutOfRangeException($"Invalid sub-slice range ({start},{length}) with array length of {array.Length}"); _array = array; _start = start; _length = length; } /// /// Gets the length of the array slice. /// public int Length { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return _length; } } /// /// Clears the entire slice content /// public void Clear() { System.Array.Clear(_array, _start, _length); } /// /// Fill the slice with a specified value /// /// public void Fill(T value) { for (int i = 0; i < _length; i++) { _array[i + _start] = value; } } /// /// Copy data from another slice into this one /// /// The source data public void Set(Slice Source) { if (Source.Length != this.Length) throw new ArgumentException("Slices must have the same length"); Array.Copy(Source.Underlying, Source.Start, Underlying, Start, Source.Length); } /// /// Gets a reference to an element in the slice /// /// The element index /// A reference to the element value. public ref T this[int index] { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { if (index < 0 || index >= _length) throw new ArgumentOutOfRangeException(nameof(index)); return ref _array[_start + index]; } } [DebuggerBrowsable(DebuggerBrowsableState.Never)] readonly T[] _array; [DebuggerBrowsable(DebuggerBrowsableState.Never)] readonly int _start; [DebuggerBrowsable(DebuggerBrowsableState.Never)] readonly int _length; /// /// Creates a sub-slice of this slice /// /// The slice start index /// The slice length /// A new array slice public Slice SubSlice(int start, int length) { return new Slice(_array, _start + start, length); } /// /// Creates a subslice of an array slice, from a specified position to the end /// /// The slice start index /// A new array slice public Slice SubSlice(int start) { return SubSlice(start, Length - start); } /// /// Gets the slice contents as a new array /// /// public T[] ToArray() { var array = new T[_length]; System.Array.Copy(_array, _start, array, 0, _length); return array; } /// /// Creates a copy of this slice on a new underlying array /// /// A slice representing the copy public Slice Copy() { return new Slice(ToArray()); } /// /// Gets the underlying array /// public T[] Underlying => _array; /// /// Gets the offset of this slice within the underlying array /// public int Start => _start; IEnumerator IEnumerable.GetEnumerator() { return new ArraySliceEnumerator(_array, _start, _length); } System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return new ArraySliceEnumerator(_array, _start, _length); } /// /// Split this slice on a delimiter /// /// The delimiter /// An enumeration of slices public IEnumerable> Split(T delimiter) { int start = 0; for (int i = 0; i < Length; i++) { if (this[i].Equals(delimiter)) { yield return SubSlice(start, i - start); start = i + 1; } } yield return SubSlice(start, Length - start); } /// /// Find the first index of a specified value /// /// The value to search for /// The index of the first occurance, or -1 if not found public int IndexOf(T value) { for (int i = 0; i < Length; i++) { if (this[i].Equals(value)) { return i; } } return -1; } /// /// Find the first index of one or more valus /// /// The value to search for /// The index of the first occurance, of -1 if not found public int IndexOfAny(params T[] values) { for (int i = 0; i < Length; i++) { if (values.Contains(this[i])) return i; } return -1; } /// /// Replace all instances of a value with another /// /// The value to replace /// The replacement value public void Replace(T replace, T with) { for (int i = 0; i < Length; i++) { if (this[i].Equals(replace)) this[i] = with; } } /// /// A shared empty slice of type T /// public static Slice Empty => new Slice(); /// /// Get the slice as a Span /// /// public Span AsSpan() => new Span(_array, _start, _length); } }