123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266 |
- // 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
- {
- /// <summary>
- /// Represents a slice of an array
- /// </summary>
- /// <typeparam name="T">The array type</typeparam>
- [DebuggerDisplay("Length = {Length}")]
- public readonly struct Slice<T> : IEnumerable<T>, System.Collections.IEnumerable
- {
- /// <summary>
- /// Constructs a new slice covering the entire passed array.
- /// </summary>
- /// <param name="array"></param>
- public Slice(T[] array)
- : this(array, 0, array.Length)
- {
- }
- /// <summary>
- /// Constructs a new slice for part of the passed array.
- /// </summary>
- /// <param name="array"></param>
- /// <param name="start"></param>
- /// <param name="length"></param>
- 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;
- }
- /// <summary>
- /// Gets the length of the array slice.
- /// </summary>
- public int Length
- {
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- get
- {
- return _length;
- }
- }
- /// <summary>
- /// Clears the entire slice content
- /// </summary>
- public void Clear()
- {
- System.Array.Clear(_array, _start, _length);
- }
- /// <summary>
- /// Fill the slice with a specified value
- /// </summary>
- /// <param name="value"></param>
- public void Fill(T value)
- {
- for (int i = 0; i < _length; i++)
- {
- _array[i + _start] = value;
- }
- }
- /// <summary>
- /// Copy data from another slice into this one
- /// </summary>
- /// <param name="Source">The source data</param>
- public void Set(Slice<T> 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);
- }
- /// <summary>
- /// Gets a reference to an element in the slice
- /// </summary>
- /// <param name="index">The element index</param>
- /// <returns>A reference to the element value.</returns>
- 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;
- /// <summary>
- /// Creates a sub-slice of this slice
- /// </summary>
- /// <param name="start">The slice start index</param>
- /// <param name="length">The slice length</param>
- /// <returns>A new array slice</returns>
- public Slice<T> SubSlice(int start, int length)
- {
- return new Slice<T>(_array, _start + start, length);
- }
- /// <summary>
- /// Creates a subslice of an array slice, from a specified position to the end
- /// </summary>
- /// <param name="start">The slice start index</param>
- /// <returns>A new array slice</returns>
- public Slice<T> SubSlice(int start)
- {
- return SubSlice(start, Length - start);
- }
- /// <summary>
- /// Gets the slice contents as a new array
- /// </summary>
- /// <returns></returns>
- public T[] ToArray()
- {
- var array = new T[_length];
- System.Array.Copy(_array, _start, array, 0, _length);
- return array;
- }
- /// <summary>
- /// Creates a copy of this slice on a new underlying array
- /// </summary>
- /// <returns>A slice representing the copy</returns>
- public Slice<T> Copy()
- {
- return new Slice<T>(ToArray());
- }
- /// <summary>
- /// Gets the underlying array
- /// </summary>
- public T[] Underlying => _array;
- /// <summary>
- /// Gets the offset of this slice within the underlying array
- /// </summary>
- public int Start => _start;
- IEnumerator<T> IEnumerable<T>.GetEnumerator()
- {
- return new ArraySliceEnumerator<T>(_array, _start, _length);
- }
- System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
- {
- return new ArraySliceEnumerator<T>(_array, _start, _length);
- }
- /// <summary>
- /// Split this slice on a delimiter
- /// </summary>
- /// <param name="delimiter">The delimiter</param>
- /// <returns>An enumeration of slices</returns>
- public IEnumerable<Slice<T>> 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);
- }
- /// <summary>
- /// Find the first index of a specified value
- /// </summary>
- /// <param name="value">The value to search for</param>
- /// <returns>The index of the first occurance, or -1 if not found</returns>
- public int IndexOf(T value)
- {
- for (int i = 0; i < Length; i++)
- {
- if (this[i].Equals(value))
- {
- return i;
- }
- }
- return -1;
- }
- /// <summary>
- /// Find the first index of one or more valus
- /// </summary>
- /// <param name="values">The value to search for</param>
- /// <returns>The index of the first occurance, of -1 if not found</returns>
- public int IndexOfAny(params T[] values)
- {
- for (int i = 0; i < Length; i++)
- {
- if (values.Contains(this[i]))
- return i;
- }
- return -1;
- }
- /// <summary>
- /// Replace all instances of a value with another
- /// </summary>
- /// <param name="replace">The value to replace</param>
- /// <param name="with">The replacement value</param>
- public void Replace(T replace, T with)
- {
- for (int i = 0; i < Length; i++)
- {
- if (this[i].Equals(replace))
- this[i] = with;
- }
- }
- /// <summary>
- /// A shared empty slice of type T
- /// </summary>
- public static Slice<T> Empty => new Slice<T>();
- /// <summary>
- /// Get the slice as a Span
- /// </summary>
- /// <returns></returns>
- public Span<T> AsSpan() => new Span<T>(_array, _start, _length);
- }
- }
|