using System; using System.Collections; using System.Collections.Generic; using System.Linq; namespace SharpGLTF.Memory { /// /// Special accessor to wrap over a base accessor and a sparse accessor /// /// An unmanage structure type. [System.Diagnostics.DebuggerDisplay("Sparse {typeof(T).Name} Accessor {Count}")] public sealed class SparseArray : IAccessorArray where T : unmanaged { #region lifecycle public SparseArray(IReadOnlyList denseValues, IReadOnlyList sparseValues, IReadOnlyList sparseKeys) { Guard.NotNull(denseValues, nameof(denseValues)); Guard.NotNull(sparseValues, nameof(sparseValues)); Guard.NotNull(sparseKeys, nameof(sparseKeys)); Guard.MustBeEqualTo(sparseKeys.Count, sparseValues.Count, nameof(sparseKeys.Count)); Guard.MustBeLessThanOrEqualTo(sparseKeys.Count, denseValues.Count, nameof(sparseKeys.Count)); _DenseItems = denseValues; _SparseItems = sparseValues; // expand indices for fast access _SparseIndices = new Dictionary(); for (int val = 0; val < sparseKeys.Count; ++val) { var key = (int)sparseKeys[val]; if (key >= denseValues.Count) { throw new ArgumentOutOfRangeException(nameof(sparseKeys)); } _SparseIndices[key] = val; } } #endregion #region data [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)] private readonly IReadOnlyList _DenseItems; [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)] private readonly IReadOnlyList _SparseItems; [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)] private readonly Dictionary _SparseIndices; [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.RootHidden)] private T[] _DebugItems => this.ToArray(); #endregion #region API [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)] public int Count => _DenseItems.Count; public bool IsReadOnly => true; public T this[int index] { get => _SparseIndices.TryGetValue(index, out int topIndex) ? _SparseItems[topIndex] : _DenseItems[index]; set => throw new NotSupportedException("Collection is read only."); } public IEnumerator GetEnumerator() { return new EncodedArrayEnumerator(this); } IEnumerator IEnumerable.GetEnumerator() { return new EncodedArrayEnumerator(this); } public bool Contains(T item) { return IndexOf(item) >= 0; } public int IndexOf(T item) { return this._FirstIndexOf(item); } public void CopyTo(T[] array, int arrayIndex) { Guard.NotNull(array, nameof(array)); this._CopyTo(array, arrayIndex); } void IList.Insert(int index, T item) { throw new NotSupportedException(); } void IList.RemoveAt(int index) { throw new NotSupportedException(); } void ICollection.Add(T item) { throw new NotSupportedException(); } void ICollection.Clear() { throw new NotSupportedException(); } bool ICollection.Remove(T item) { throw new NotSupportedException(); } #endregion } }