SparseArrays.cs 3.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. namespace SharpGLTF.Memory
  6. {
  7. /// <summary>
  8. /// Special accessor to wrap over a base accessor and a sparse accessor
  9. /// </summary>
  10. /// <typeparam name="T">An unmanage structure type.</typeparam>
  11. [System.Diagnostics.DebuggerDisplay("Sparse {typeof(T).Name} Accessor {Count}")]
  12. public sealed class SparseArray<T> : IAccessorArray<T>
  13. where T : unmanaged
  14. {
  15. #region lifecycle
  16. public SparseArray(IReadOnlyList<T> denseValues, IReadOnlyList<T> sparseValues, IReadOnlyList<uint> sparseKeys)
  17. {
  18. Guard.NotNull(denseValues, nameof(denseValues));
  19. Guard.NotNull(sparseValues, nameof(sparseValues));
  20. Guard.NotNull(sparseKeys, nameof(sparseKeys));
  21. Guard.MustBeEqualTo(sparseKeys.Count, sparseValues.Count, nameof(sparseKeys.Count));
  22. Guard.MustBeLessThanOrEqualTo(sparseKeys.Count, denseValues.Count, nameof(sparseKeys.Count));
  23. _DenseItems = denseValues;
  24. _SparseItems = sparseValues;
  25. // expand indices for fast access
  26. _SparseIndices = new Dictionary<int, int>();
  27. for (int val = 0; val < sparseKeys.Count; ++val)
  28. {
  29. var key = (int)sparseKeys[val];
  30. if (key >= denseValues.Count)
  31. {
  32. throw new ArgumentOutOfRangeException(nameof(sparseKeys));
  33. }
  34. _SparseIndices[key] = val;
  35. }
  36. }
  37. #endregion
  38. #region data
  39. [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
  40. private readonly IReadOnlyList<T> _DenseItems;
  41. [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
  42. private readonly IReadOnlyList<T> _SparseItems;
  43. [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
  44. private readonly Dictionary<int, int> _SparseIndices;
  45. [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.RootHidden)]
  46. private T[] _DebugItems => this.ToArray();
  47. #endregion
  48. #region API
  49. [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
  50. public int Count => _DenseItems.Count;
  51. public bool IsReadOnly => true;
  52. public T this[int index]
  53. {
  54. get => _SparseIndices.TryGetValue(index, out int topIndex) ? _SparseItems[topIndex] : _DenseItems[index];
  55. set => throw new NotSupportedException("Collection is read only.");
  56. }
  57. public IEnumerator<T> GetEnumerator() { return new EncodedArrayEnumerator<T>(this); }
  58. IEnumerator IEnumerable.GetEnumerator() { return new EncodedArrayEnumerator<T>(this); }
  59. public bool Contains(T item) { return IndexOf(item) >= 0; }
  60. public int IndexOf(T item) { return this._FirstIndexOf(item); }
  61. public void CopyTo(T[] array, int arrayIndex) { Guard.NotNull(array, nameof(array)); this._CopyTo(array, arrayIndex); }
  62. void IList<T>.Insert(int index, T item) { throw new NotSupportedException(); }
  63. void IList<T>.RemoveAt(int index) { throw new NotSupportedException(); }
  64. void ICollection<T>.Add(T item) { throw new NotSupportedException(); }
  65. void ICollection<T>.Clear() { throw new NotSupportedException(); }
  66. bool ICollection<T>.Remove(T item) { throw new NotSupportedException(); }
  67. #endregion
  68. }
  69. }