Selaa lähdekoodia

Improved performance of the mechanism behind LogicalIndex property used by most glTF objects.

Vicente Penades 5 vuotta sitten
vanhempi
sitoutus
7fb235ef9f

+ 0 - 1
README.md

@@ -4,7 +4,6 @@
 
 ![GitHub](https://img.shields.io/github/license/vpenades/SharpGLTF)
 [![Nuget (with prereleases)](https://img.shields.io/nuget/vpre/SharpGLTF.Core)](https://www.nuget.org/packages?q=sharpgltf)
-
 [![Join the chat at https://discord.gg/y9mnJQY](https://img.shields.io/discord/750776153681166467?color=%237289DA&label=SharpGLTF&logo=discord&logoColor=white)](https://discord.gg/y9mnJQY)
 ---
 

+ 0 - 13
src/Shared/_Extensions.cs

@@ -287,19 +287,6 @@ namespace SharpGLTF
             return -1;
         }
 
-        internal static int IndexOfReference<T>(this IReadOnlyList<T> collection, T value)
-            where T : class
-        {
-            var l = collection.Count;
-
-            for (int i = 0; i < l; ++i)
-            {
-                if (Object.ReferenceEquals(collection[i], value)) return i;
-            }
-
-            return -1;
-        }
-
         internal static int IndexOf<T>(this IReadOnlyList<T> collection, T[] subset)
             where T : IEquatable<T>
         {

+ 39 - 21
src/SharpGLTF.Core/Collections/ChildrenCollection.cs

@@ -52,12 +52,23 @@ namespace SharpGLTF.Collections
                 if (_Collection[index] == value) return; // nothing to do
 
                 // orphan the current child
-                if (_Collection[index] != null) { _Collection[index]._SetLogicalParent(null); }
+                if (_Collection[index] != null)
+                {
+                    _Collection[index]._SetLogicalParent(null, -1);
+                    System.Diagnostics.Debug.Assert(_Collection[index].LogicalParent == null);
+                    System.Diagnostics.Debug.Assert(_Collection[index].LogicalIndex == -1);
+                }
+
                 _Collection[index] = null;
 
                 // adopt the new child
                 _Collection[index] = value;
-                if (_Collection[index] != null) { _Collection[index]._SetLogicalParent(_Parent); }
+                if (_Collection[index] != null)
+                {
+                    _Collection[index]._SetLogicalParent(_Parent, index);
+                    System.Diagnostics.Debug.Assert(_Collection[index].LogicalParent == _Parent);
+                    System.Diagnostics.Debug.Assert(_Collection[index].LogicalIndex == index);
+                }
             }
         }
 
@@ -75,10 +86,13 @@ namespace SharpGLTF.Collections
             // new value must be an orphan
             Guard.NotNull(item, nameof(item));
             Guard.MustBeNull(item.LogicalParent, nameof(item.LogicalParent));
+            Guard.MustBeEqualTo(-1, item.LogicalIndex, nameof(item.LogicalIndex));
 
             if (_Collection == null) _Collection = new List<T>();
 
-            item._SetLogicalParent(_Parent);
+            item._SetLogicalParent(_Parent, _Collection.Count);
+            System.Diagnostics.Debug.Assert(item.LogicalParent == _Parent);
+            System.Diagnostics.Debug.Assert(item.LogicalIndex == _Collection.Count);
 
             _Collection.Add(item);
         }
@@ -89,7 +103,9 @@ namespace SharpGLTF.Collections
 
             foreach (var item in _Collection)
             {
-                item._SetLogicalParent(null);
+                item._SetLogicalParent(null, -1);
+                System.Diagnostics.Debug.Assert(item.LogicalParent == null);
+                System.Diagnostics.Debug.Assert(item.LogicalIndex == -1);
             }
 
             _Collection = null;
@@ -116,10 +132,19 @@ namespace SharpGLTF.Collections
             // new value must be an orphan
             Guard.NotNull(item, nameof(item));
             Guard.MustBeNull(item.LogicalParent, nameof(item.LogicalParent));
+            Guard.MustBeEqualTo(-1, item.LogicalIndex, nameof(item.LogicalIndex));
 
             if (_Collection == null) _Collection = new List<T>();
 
             _Collection.Insert(index, item);
+
+            // fix indices of upper items
+            for (int i = index; i < _Collection.Count; ++i)
+            {
+                _Collection[i]._SetLogicalParent(_Parent, i);
+                System.Diagnostics.Debug.Assert(_Collection[i].LogicalParent == _Parent);
+                System.Diagnostics.Debug.Assert(_Collection[i].LogicalIndex == i);
+            }
         }
 
         public bool Remove(T item)
@@ -136,12 +161,21 @@ namespace SharpGLTF.Collections
         public void RemoveAt(int index)
         {
             if (_Collection == null) throw new ArgumentOutOfRangeException(nameof(index));
+            if (index < 0 || index >= _Collection.Count) throw new ArgumentOutOfRangeException(nameof(index));
 
             // orphan the current child
-            if (_Collection[index] != null) { _Collection[index]._SetLogicalParent(null); }
+            if (_Collection[index] != null) { _Collection[index]._SetLogicalParent(null, -1); }
 
             _Collection.RemoveAt(index);
 
+            // fix indices of upper items
+            for (int i = index; i < _Collection.Count; ++i)
+            {
+                _Collection[i]._SetLogicalParent(_Parent, i);
+                System.Diagnostics.Debug.Assert(_Collection[i].LogicalParent == _Parent);
+                System.Diagnostics.Debug.Assert(_Collection[i].LogicalIndex == i);
+            }
+
             if (_Collection.Count == 0) _Collection = null;
         }
 
@@ -155,22 +189,6 @@ namespace SharpGLTF.Collections
             return _Collection == null ? Enumerable.Empty<T>().GetEnumerator() : _Collection.GetEnumerator();
         }
 
-        public int Use(T item)
-        {
-            Guard.NotNull(item, nameof(item));
-
-            // in this case we delay the LogicalParent==null check to the "Add" method below
-
-            var idx = this.IndexOf(item);
-            if (idx >= 0) return idx;
-
-            idx = this.Count;
-
-            Add(item);
-
-            return idx;
-        }
-
         #endregion
     }
 }

+ 3 - 1
src/SharpGLTF.Core/Collections/IChildOf.cs

@@ -7,8 +7,10 @@ namespace SharpGLTF.Collections
     interface IChildOf<TParent>
         where TParent : class
     {
+        int LogicalIndex { get; }
+
         TParent LogicalParent { get; }
 
-        void _SetLogicalParent(TParent parent);
+        void _SetLogicalParent(TParent parent, int index);
     }
 }

+ 2 - 2
src/SharpGLTF.Core/Collections/SingleChild.cs

@@ -41,12 +41,12 @@ namespace SharpGLTF.Collections
                 }
 
                 // orphan the current child
-                if (this._Child != null) { this._Child._SetLogicalParent(null); }
+                if (this._Child != null) { this._Child._SetLogicalParent(null, -1); }
                 this._Child = null;
 
                 // adopt the new child
                 this._Child = value;
-                if (this._Child != null) { this._Child._SetLogicalParent(_Parent); }
+                if (this._Child != null) { this._Child._SetLogicalParent(_Parent, 0); }
             }
         }
 

+ 1 - 1
src/SharpGLTF.Core/Debug/DebugViews.cs

@@ -33,7 +33,7 @@ namespace SharpGLTF.Debug
     {
         public _BufferViewDebugProxy(Schema2.BufferView value) { _Value = value; }
 
-        public int LogicalIndex => _Value.LogicalParent.LogicalBufferViews.IndexOfReference(_Value);
+        public int LogicalIndex => _Value.LogicalIndex;
 
         private readonly Schema2.BufferView _Value;
 

+ 0 - 5
src/SharpGLTF.Core/Schema2/gltf.Accessors.cs

@@ -36,11 +36,6 @@ namespace SharpGLTF.Schema2
 
         #region properties
 
-        /// <summary>
-        /// Gets the zero-based index of this <see cref="Accessor"/> at <see cref="ModelRoot.LogicalAccessors"/>
-        /// </summary>
-        public int LogicalIndex                 => this.LogicalParent.LogicalAccessors.IndexOfReference(this);
-
         internal int _SourceBufferViewIndex => this._bufferView.AsValue(-1);
 
         /// <summary>

+ 6 - 2
src/SharpGLTF.Core/Schema2/gltf.AnimationSampler.cs

@@ -75,9 +75,13 @@ namespace SharpGLTF.Schema2
         /// <summary>
         /// Gets the zero-based index of this <see cref="AnimationSampler"/> at <see cref="Animation._samplers"/>.
         /// </summary>
-        public int LogicalIndex => LogicalParent._Samplers.IndexOfReference(this);
+        public int LogicalIndex { get; private set; } = -1;
 
-        void IChildOf<Animation>._SetLogicalParent(Animation parent) { LogicalParent = parent; }
+        void IChildOf<Animation>._SetLogicalParent(Animation parent, int index)
+        {
+            LogicalParent = parent;
+            LogicalIndex = index;
+        }
 
         public AnimationInterpolationMode InterpolationMode
         {

+ 10 - 6
src/SharpGLTF.Core/Schema2/gltf.Animations.cs

@@ -26,11 +26,6 @@ namespace SharpGLTF.Schema2
 
         #region properties
 
-        /// <summary>
-        /// Gets the zero-based index of this <see cref="Animation"/> at <see cref="ModelRoot.LogicalAnimations"/>
-        /// </summary>
-        public int LogicalIndex => this.LogicalParent.LogicalAnimations.IndexOfReference(this);
-
         internal IReadOnlyList<AnimationSampler> _Samplers => _samplers;
 
         internal IReadOnlyList<AnimationChannel> _Channels => _channels;
@@ -297,13 +292,22 @@ namespace SharpGLTF.Schema2
 
         #region properties
 
+        /// <summary>
+        /// Gets the zero-based index of this <see cref="Animation"/> at <see cref="ModelRoot.LogicalAnimations"/>
+        /// </summary>
+        public int LogicalIndex { get; private set; } = -1;
+
         /// <summary>
         /// Gets the <see cref="Animation"/> instance that owns this object.
         /// </summary>
         [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
         public Animation LogicalParent { get; private set; }
 
-        void IChildOf<Animation>._SetLogicalParent(Animation parent) { LogicalParent = parent; }
+        void IChildOf<Animation>._SetLogicalParent(Animation parent, int index)
+        {
+            LogicalParent = parent;
+            LogicalIndex = index;
+        }
 
         /// <summary>
         /// Gets the <see cref="AnimationSampler"/> instance used by this <see cref="AnimationChannel"/>.

+ 0 - 5
src/SharpGLTF.Core/Schema2/gltf.Buffer.cs

@@ -28,11 +28,6 @@ namespace SharpGLTF.Schema2
 
         #region properties
 
-        /// <summary>
-        /// Gets the zero-based index of this <see cref="Buffer"/> at <see cref="ModelRoot.LogicalBuffers"/>
-        /// </summary>
-        public int LogicalIndex => this.LogicalParent.LogicalBuffers.IndexOfReference(this);
-
         #pragma warning disable CA1819 // Properties should not return arrays
         public Byte[] Content => _Content;
         #pragma warning restore CA1819 // Properties should not return arrays

+ 0 - 5
src/SharpGLTF.Core/Schema2/gltf.BufferView.cs

@@ -61,11 +61,6 @@ namespace SharpGLTF.Schema2
 
         #region properties
 
-        /// <summary>
-        /// Gets the zero-based index of this <see cref="BufferView"/> at <see cref="ModelRoot.LogicalBufferViews"/>
-        /// </summary>
-        public int LogicalIndex                 => this.LogicalParent.LogicalBufferViews.IndexOfReference(this);
-
         /// <summary>
         /// Gets a value indicating whether this <see cref="BufferView"/> defines a GPU Ready Vertex Buffer.
         /// </summary>

+ 0 - 6
src/SharpGLTF.Core/Schema2/gltf.Camera.cs

@@ -14,12 +14,6 @@ namespace SharpGLTF.Schema2
         #endregion
 
         #region properties
-
-        /// <summary>
-        /// Gets the zero-based index of this <see cref="Camera"/> at <see cref="ModelRoot.LogicalCameras"/>
-        /// </summary>
-        public int LogicalIndex => this.LogicalParent.LogicalCameras.IndexOfReference(this);
-
         public ICamera Settings => GetCamera();
 
         /// <summary>

+ 0 - 5
src/SharpGLTF.Core/Schema2/gltf.Images.cs

@@ -43,11 +43,6 @@ namespace SharpGLTF.Schema2
 
         #region properties
 
-        /// <summary>
-        /// Gets the zero-based index of this <see cref="Image"/> at <see cref="ModelRoot.LogicalImages"/>
-        /// </summary>
-        public int LogicalIndex => this.LogicalParent.LogicalImages.IndexOfReference(this);
-
         /// <summary>
         /// Gets or sets the in-memory representation of the image file.
         /// </summary>

+ 10 - 1
src/SharpGLTF.Core/Schema2/gltf.LogicalChildOfRoot.cs

@@ -28,7 +28,16 @@ namespace SharpGLTF.Schema2
         /// </summary>
         public ModelRoot LogicalParent { get; private set; }
 
-        void IChildOf<ModelRoot>._SetLogicalParent(ModelRoot parent) { LogicalParent = parent; }
+        /// <summary>
+        /// Gets the zero-based index of this object in the Logical resources of <see cref="ModelRoot"/>.
+        /// </summary>
+        public int LogicalIndex { get; private set; } = -1;
+
+        void IChildOf<ModelRoot>._SetLogicalParent(ModelRoot parent, int index)
+        {
+            LogicalParent = parent;
+            LogicalIndex = index;
+        }
 
         #endregion
 

+ 0 - 5
src/SharpGLTF.Core/Schema2/gltf.Material.cs

@@ -17,11 +17,6 @@ namespace SharpGLTF.Schema2
 
         #region properties
 
-        /// <summary>
-        /// Gets the zero-based index of this <see cref="Material"/> at <see cref="ModelRoot.LogicalMaterials"/>
-        /// </summary>
-        public int LogicalIndex => this.LogicalParent.LogicalMaterials.IndexOfReference(this);
-
         /// <summary>
         /// Gets or sets the <see cref="AlphaMode"/>.
         /// </summary>

+ 0 - 5
src/SharpGLTF.Core/Schema2/gltf.Mesh.cs

@@ -37,11 +37,6 @@ namespace SharpGLTF.Schema2
 
         #region properties
 
-        /// <summary>
-        /// Gets the zero-based index of this <see cref="Mesh"/> at <see cref="ModelRoot.LogicalMeshes"/>
-        /// </summary>
-        public int LogicalIndex => this.LogicalParent.LogicalMeshes.IndexOfReference(this);
-
         public IEnumerable<Node> VisualParents => Node.FindNodesUsingMesh(this);
 
         public IReadOnlyList<MeshPrimitive> Primitives => _primitives;

+ 6 - 2
src/SharpGLTF.Core/Schema2/gltf.MeshPrimitive.cs

@@ -35,14 +35,18 @@ namespace SharpGLTF.Schema2
         /// <summary>
         /// Gets the zero-based index of this <see cref="MeshPrimitive"/> at <see cref="Mesh.Primitives"/>.
         /// </summary>
-        public int LogicalIndex => this.LogicalParent.Primitives.IndexOfReference(this);
+        public int LogicalIndex { get; private set; } = -1;
 
         /// <summary>
         /// Gets the <see cref="Mesh"/> instance that owns this <see cref="MeshPrimitive"/> instance.
         /// </summary>
         public Mesh LogicalParent { get; private set; }
 
-        void IChildOf<Mesh>._SetLogicalParent(Mesh parent) { LogicalParent = parent; }
+        void IChildOf<Mesh>._SetLogicalParent(Mesh parent, int index)
+        {
+            LogicalParent = parent;
+            LogicalIndex = index;
+        }
 
         /// <summary>
         /// Gets or sets the <see cref="Material"/> instance, or null.

+ 0 - 5
src/SharpGLTF.Core/Schema2/gltf.Node.cs

@@ -74,11 +74,6 @@ namespace SharpGLTF.Schema2
 
         #region properties - hierarchy
 
-        /// <summary>
-        /// Gets the zero-based index of this <see cref="Node"/> at <see cref="ModelRoot.LogicalNodes"/>
-        /// </summary>
-        public int LogicalIndex => this.LogicalParent.LogicalNodes.IndexOfReference(this);
-
         /// <summary>
         /// Gets the visual parent <see cref="Node"/> instance that contains this <see cref="Node"/>.
         /// </summary>

+ 0 - 6
src/SharpGLTF.Core/Schema2/gltf.Scene.cs

@@ -17,12 +17,6 @@ namespace SharpGLTF.Schema2
         #endregion
 
         #region properties
-
-        /// <summary>
-        /// Gets the zero-based index of this <see cref="Scene"/> at <see cref="ModelRoot.LogicalScenes"/>
-        /// </summary>
-        public int LogicalIndex => this.LogicalParent.LogicalScenes.IndexOfReference(this);
-
         internal IReadOnlyList<int> _VisualChildrenIndices => _nodes;
 
         public IEnumerable<Node> VisualChildren => _nodes.Select(idx => LogicalParent.LogicalNodes[idx]);

+ 0 - 5
src/SharpGLTF.Core/Schema2/gltf.Skin.cs

@@ -27,11 +27,6 @@ namespace SharpGLTF.Schema2
 
         #region properties
 
-        /// <summary>
-        /// Gets the zero-based index of this <see cref="Skin"/> at <see cref="ModelRoot.LogicalSkins"/>
-        /// </summary>
-        public int LogicalIndex => this.LogicalParent.LogicalSkins.IndexOfReference(this);
-
         /// <summary>
         /// Gets a collection of <see cref="Node"/> instances using this <see cref="Skin"/>.
         /// </summary>

+ 0 - 10
src/SharpGLTF.Core/Schema2/gltf.Textures.cs

@@ -22,11 +22,6 @@ namespace SharpGLTF.Schema2
 
         #region properties
 
-        /// <summary>
-        /// Gets the zero-based index of this <see cref="Texture"/> at <see cref="ModelRoot.LogicalTextures"/>
-        /// </summary>
-        public int LogicalIndex => this.LogicalParent.LogicalTextures.IndexOfReference(this);
-
         public TextureSampler Sampler
         {
             get => _sampler.HasValue ? LogicalParent.LogicalTextureSamplers[_sampler.Value] : null;
@@ -233,11 +228,6 @@ namespace SharpGLTF.Schema2
 
         #region properties
 
-        /// <summary>
-        /// Gets the zero-based index of this <see cref="TextureSampler"/> at <see cref="ModelRoot.LogicalTextureSamplers"/>
-        /// </summary>
-        public int LogicalIndex => this.LogicalParent.LogicalTextureSamplers.IndexOfReference(this);
-
         /// <summary>
         /// Gets the texture minification filter.
         /// </summary>

+ 0 - 5
src/SharpGLTF.Core/Schema2/khr.lights.cs

@@ -120,11 +120,6 @@ namespace SharpGLTF.Schema2
         /// </remarks>
         public static Vector3 LocalDirection => -Vector3.UnitZ;
 
-        /// <summary>
-        /// Gets the zero-based index of this <see cref="PunctualLight"/> at <see cref="ModelRoot.LogicalPunctualLights"/>
-        /// </summary>
-        public int LogicalIndex => this.LogicalParent.LogicalPunctualLights.IndexOfReference(this);
-
         /// <summary>
         /// Gets the type of light.
         /// </summary>

+ 35 - 8
tests/SharpGLTF.Tests/Collections/ChildrenCollectionTests.cs

@@ -14,9 +14,12 @@ namespace SharpGLTF.Collections
         {
             public ChildrenCollectionTests LogicalParent { get; private set; }
 
-            public void _SetLogicalParent(ChildrenCollectionTests parent)
+            public int LogicalIndex { get; private set; } = -1;
+
+            public void _SetLogicalParent(ChildrenCollectionTests parent, int index)
             {
                 LogicalParent = parent;
+                LogicalIndex = index;
             }
         }
 
@@ -29,16 +32,40 @@ namespace SharpGLTF.Collections
             
             Assert.Throws<ArgumentNullException>(() => list.Add(null));
 
-            var item = new TestChild();
-            Assert.IsNull(item.LogicalParent);
+            var item1 = new TestChild();
+            Assert.IsNull(item1.LogicalParent);
+            Assert.AreEqual(-1, item1.LogicalIndex);
+
+            var item2 = new TestChild();
+            Assert.IsNull(item2.LogicalParent);
+            Assert.AreEqual(-1, item2.LogicalIndex);
+
+            list.Add(item1);
+            Assert.AreSame(this, item1.LogicalParent);
+            Assert.AreEqual(0, item1.LogicalIndex);
+
+            Assert.Throws<ArgumentException>(() => list.Add(item1));
+
+            list.Remove(item1);
+            Assert.IsNull(item1.LogicalParent);
+            Assert.AreEqual(-1, item1.LogicalIndex);
+
+            list.Add(item1);
+            Assert.AreSame(this, item1.LogicalParent);
+            Assert.AreEqual(0, item1.LogicalIndex);
 
-            list.Add(item);
-            Assert.AreSame(item.LogicalParent, this);
+            list.Insert(0, item2);
+            Assert.AreSame(this, item2.LogicalParent);
+            Assert.AreEqual(0, item2.LogicalIndex);
+            Assert.AreSame(this, item1.LogicalParent);
+            Assert.AreEqual(1, item1.LogicalIndex);
 
-            Assert.Throws<ArgumentException>(() => list.Add(item));
+            list.RemoveAt(0);
+            Assert.IsNull(item2.LogicalParent);
+            Assert.AreEqual(-1, item2.LogicalIndex);
+            Assert.AreSame(this, item1.LogicalParent);
+            Assert.AreEqual(0, item1.LogicalIndex);
 
-            list.Remove(item);
-            Assert.IsNull(item.LogicalParent);
         }
 
     }