From fa2eaf8a07067f1cceb2a73f2fc002fc8d57e7be Mon Sep 17 00:00:00 2001 From: DCFApixels <99481254+DCFApixels@users.noreply.github.com> Date: Tue, 1 Apr 2025 19:31:11 +0800 Subject: [PATCH 1/9] rework LayerList to LayersMap --- src/EcsPipeline.Builder.cs | 237 ++------------- src/Utils/LayersMap.cs | 585 +++++++++++++++++++++++++++++++++++++ 2 files changed, 604 insertions(+), 218 deletions(-) create mode 100644 src/Utils/LayersMap.cs diff --git a/src/EcsPipeline.Builder.cs b/src/EcsPipeline.Builder.cs index 55c5be4..2966088 100644 --- a/src/EcsPipeline.Builder.cs +++ b/src/EcsPipeline.Builder.cs @@ -1,12 +1,11 @@ #if DISABLE_DEBUG #undef DEBUG #endif +using DCFApixels.DragonECS.Core; using DCFApixels.DragonECS.Internal; using DCFApixels.DragonECS.RunnersCore; using System; -using System.Collections; using System.Collections.Generic; -using System.Linq; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Serialization; @@ -25,7 +24,7 @@ namespace DCFApixels.DragonECS public sealed partial class EcsPipeline { - public class Builder : IEcsModule + public partial class Builder : IEcsModule { private SystemNode[] _systemNodes = new SystemNode[256]; private int _startIndex = -1; @@ -37,7 +36,7 @@ namespace DCFApixels.DragonECS private readonly Dictionary _layerLists = new Dictionary(8); private readonly List _initDeclaredRunners = new List(4); - public readonly LayerList Layers; + public readonly LayersMap Layers; public readonly Injector.Builder Injector; public readonly Configurator Configs; @@ -64,7 +63,7 @@ namespace DCFApixels.DragonECS Injector.AddNode(); Injector.AddNode(); - Layers = new LayerList(this, PRE_BEGIN_LAYER, BEGIN_LAYER, BASIC_LAYER, END_LAYER, POST_END_LAYER); + Layers = new LayersMap(this, PRE_BEGIN_LAYER, BEGIN_LAYER, BASIC_LAYER, END_LAYER, POST_END_LAYER); } #endregion @@ -245,7 +244,7 @@ namespace DCFApixels.DragonECS } Layers.MergeWith(other.Layers); - foreach (ref readonly SystemNode otherRecord in new LinkedListIterator(_systemNodes, _systemNodesCount, _startIndex)) + foreach (ref readonly SystemNode otherRecord in new LinkedListCountIterator(_systemNodes, _systemNodesCount, _startIndex)) { AddNode_Internal(otherRecord.system, otherRecord.layerName, otherRecord.sortOrder, otherRecord.isUnique); } @@ -309,7 +308,7 @@ namespace DCFApixels.DragonECS #if DEBUG _buildMarker.Begin(); #endif - var it = new LinkedListIterator(_systemNodes, _systemNodesCount, _startIndex); + var it = new LinkedListCountIterator(_systemNodes, _systemNodesCount, _startIndex); LayerSystemsList basicLayerList; if (_layerLists.TryGetValue(BASIC_LAYER, out basicLayerList) == false) @@ -354,7 +353,7 @@ namespace DCFApixels.DragonECS IEcsProcess[] allSystems = new IEcsProcess[allSystemsLength]; { int i = 0; - foreach (var item in Layers) + foreach (var item in Layers.Build()) { if (_layerLists.TryGetValue(item, out var list) && list.IsInit) { @@ -413,217 +412,10 @@ namespace DCFApixels.DragonECS return _builder; } } + #endregion - #region LayerList - public class LayerList : IEnumerable - { - private Builder _source; - private List _layers; - private string _basicLayerName; - private string _addLayerName; - - #region Properties - public int Count { get { return _layers.Count; } } - public object this[int index] { get { return _layers[index]; } } - #endregion - - #region Constructors - public LayerList(Builder source, string basicLayerName) - { - _source = source; - _layers = new List(16) { basicLayerName }; - _basicLayerName = basicLayerName; - _addLayerName = _basicLayerName; - } - public LayerList(Builder source, string preBeginlayer, string beginlayer, string basicLayer, string endLayer, string postEndLayer) - { - _source = source; - _layers = new List(16) { preBeginlayer, beginlayer, basicLayer, endLayer, postEndLayer }; - _basicLayerName = basicLayer; - _addLayerName = _basicLayerName; - } - #endregion - - #region Edit - - #region Single - public Builder Add(string newLayer) - { - InsertAfter(_addLayerName, newLayer); - _addLayerName = newLayer; - return _source; - } - public Builder Insert(string targetLayer, string newLayer) - { - if (Contains(newLayer)) { return _source; } - - int index = _layers.IndexOf(targetLayer); - if (index < 0) - { - throw new KeyNotFoundException($"Layer {targetLayer} not found"); - } - _layers.Insert(index, newLayer); - return _source; - } - public Builder InsertAfter(string targetLayer, string newLayer) - { - if (Contains(newLayer)) { return _source; } - - int index = _layers.IndexOf(targetLayer); - if (index < 0) - { - throw new KeyNotFoundException($"Layer {targetLayer} not found"); - } - - _layers.Insert(++index, newLayer); - return _source; - } - public Builder Move(string targetLayer, string movingLayer) - { - _layers.Remove(movingLayer); - return Insert(targetLayer, movingLayer); - } - public Builder MoveAfter(string targetLayer, string movingLayer) - { - _layers.Remove(movingLayer); - return InsertAfter(targetLayer, movingLayer); - } - #endregion - - #region Range - public Builder Add(params string[] newLayers) - { - InsertAfter(_addLayerName, newLayers); - _addLayerName = newLayers[newLayers.Length - 1]; - return _source; - } - public Builder Insert(string targetLayer, params string[] newLayers) - { - int index = _layers.IndexOf(targetLayer); - if (index < 0) - { - throw new KeyNotFoundException($"Layer {targetLayer} not found"); - } - _layers.InsertRange(index, newLayers.Where(o => !Contains(o))); - return _source; - } - public Builder InsertAfter(string targetLayer, params string[] newLayers) - { - int index = _layers.IndexOf(targetLayer); - if (index < 0) - { - throw new KeyNotFoundException($"Layer {targetLayer} not found"); - } - - _layers.InsertRange(++index, newLayers.Where(o => !Contains(o))); - return _source; - } - public Builder Move(string targetLayer, params string[] movingLayers) - { - foreach (var movingLayer in movingLayers) - { - _layers.Remove(movingLayer); - } - return Insert(targetLayer, movingLayers); - } - public Builder MoveAfter(string targetLayer, params string[] movingLayers) - { - foreach (var movingLayer in movingLayers) - { - _layers.Remove(movingLayer); - } - return InsertAfter(targetLayer, movingLayers); - } - #endregion - - #endregion - - #region MergeWith - private static bool CheckOverlapsOrder(List listA, IReadOnlyList listB) - { - int lastIndexof = 0; - for (int i = 0; i < listB.Count; i++) - { - var a = listB[i]; - int indexof = listA.IndexOf(a); - - if (indexof < 0) { continue; } - if (indexof < lastIndexof) - { - return false; - } - lastIndexof = indexof; - } - return true; - } - public void MergeWith(IReadOnlyList other) - { - List listA = _layers; - IReadOnlyList listB = other; - - if (CheckOverlapsOrder(listA, listB) == false) - { - //Для слияния списков слоев, нужно чтобы в пересечении порядок записей совпадал - Throw.Exception("To merge layer lists, the names of the layers present in both lists must appear in the same order in both lists."); - } - - HashSet seen = new HashSet(); - List result = new List(); - - foreach (string item in listA) - { - seen.Add(item); - } - foreach (string item in listB) - { - if (seen.Add(item) == false) - { - seen.Remove(item); - } - } - - int i = 0, j = 0; - while (i < listA.Count || j < listB.Count) - { - while (i < listA.Count && seen.Contains(listA[i])) - { - result.Add(listA[i]); - i++; - } - while (j < listB.Count && seen.Contains(listB[j])) - { - result.Add(listB[j]); - j++; - } - - if (i < listA.Count) { i++; } - if (j < listB.Count) - { - result.Add(listB[j]); - j++; - } - } - - _layers = result; - } - public void MergeWith(LayerList other) - { - MergeWith(other._layers); - } - #endregion - - #region Other - public bool Contains(string layer) { return _layers.Contains(layer); } - - public List.Enumerator GetEnumerator() { return _layers.GetEnumerator(); } - IEnumerator IEnumerable.GetEnumerator() { return _layers.GetEnumerator(); } - IEnumerator IEnumerable.GetEnumerator() { return _layers.GetEnumerator(); } - #endregion - } - #endregion - - #region SystemsList + #region LayerSystemsList private class LayerSystemsList { public int lasyInitSystemsCount = 0; @@ -726,7 +518,7 @@ namespace DCFApixels.DragonECS #region SerializableTemplate public EcsPipelineTemplate GenerateSerializableTemplate() { - var it = new LinkedListIterator(_systemNodes, _systemNodesCount, _startIndex); + var it = new LinkedListCountIterator(_systemNodes, _systemNodesCount, _startIndex); EcsPipelineTemplate result = new EcsPipelineTemplate(); result.layers = new string[Layers.Count]; result.records = new EcsPipelineTemplate.Record[it.Count]; @@ -768,6 +560,15 @@ namespace DCFApixels.DragonECS } } #endregion + + #region Obsolete + [Obsolete("Use LayersMap")] + public class LayerList : LayersMap + { + public LayerList(Builder source, string basicLayerName) : base(source, basicLayerName) { } + public LayerList(Builder source, string preBeginlayer, string beginlayer, string basicLayer, string endLayer, string postEndLayer) : base(source, preBeginlayer, beginlayer, basicLayer, endLayer, postEndLayer) { } + } + #endregion } } diff --git a/src/Utils/LayersMap.cs b/src/Utils/LayersMap.cs new file mode 100644 index 0000000..6952bc2 --- /dev/null +++ b/src/Utils/LayersMap.cs @@ -0,0 +1,585 @@ +using DCFApixels.DragonECS.Internal; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; + +namespace DCFApixels.DragonECS.Core +{ + public partial class LayersMap : IEnumerable + { + private readonly Dictionary _layerIds = new Dictionary(32); + private StructList _layerInfos = new StructList(32); + private LayerID GetLayerID(string layer) + { + if (_layerIds.TryGetValue(layer, out LayerID layerID) == false) + { + layerID = (LayerID)_layerInfos.Count; + _layerInfos.Add(default); + + _layerIds[layer] = layerID; + ref var layerInfo = ref GetLayerInfo(layerID); + layerInfo.name = layer; + } + return layerID; + } + private ref LayerInfo GetLayerInfo(LayerID layerID) + { + return ref _layerInfos._items[(int)layerID]; + } + private struct LayerInfo + { + public string name; + public bool isLocked; + public bool isContained; + public int insertionIndex; + //build + public int inDegree; + public bool hasAnyDependency; + public LayerInfo(string name) : this() + { + this.name = name; + } + } + + private readonly EcsPipeline.Builder _source; + private StructList<(LayerID From, LayerID To)> _dependencies = new StructList<(LayerID, LayerID)>(16); + private readonly LayerID _basicLayerID; + private int _increment = 0; + private int _count; + + #region Properties + public int Count + { + get { return _count; } + } + #endregion + + #region Constructors + public LayersMap(EcsPipeline.Builder source = null) + { + GetLayerID(""); + _source = source; + } + public LayersMap(EcsPipeline.Builder source, string basicLayerName) + { + GetLayerID(""); + _source = source; + + Add(basicLayerName); + + _basicLayerID = GetLayerID(basicLayerName); + LockLayer(basicLayerName); + } + public LayersMap(EcsPipeline.Builder source, string preBeginlayer, string beginlayer, string basicLayer, string endLayer, string postEndLayer) + { + GetLayerID(""); + _source = source; + + Add(preBeginlayer) + .Before(beginlayer); + Add(beginlayer) + .After(preBeginlayer) + .Before(basicLayer); + Add(basicLayer) + .After(beginlayer) + .Before(endLayer); + Add(endLayer) + .After(basicLayer) + .Before(postEndLayer); + Add(postEndLayer) + .After(endLayer); + + _basicLayerID = GetLayerID(basicLayer); + LockLayer(preBeginlayer); + LockLayer(beginlayer); + LockLayer(basicLayer); + LockLayer(endLayer); + LockLayer(postEndLayer); + } + #endregion + + #region Methods + private void LockLayer(string layer) + { + GetLayerInfo(GetLayerID(layer)).isLocked = true; + } + private void Add_Internal(LayerID id) + { + ref var info = ref GetLayerInfo(id); + if (info.isLocked) { return; } + if (info.isContained == false) + { + _count++; + info.isContained = true; + } + info.insertionIndex = _increment++; + } + private void Remove_Internal(LayerID id) + { + ref var info = ref GetLayerInfo(id); + if (info.isLocked) { throw new Exception($"The {info.name} layer cannot be removed"); } + if (info.isContained) + { + _count--; + info.isContained = false; + } + info.insertionIndex = 0; + } + private void AddDependency_Internal(LayerID from, LayerID to) + { + GetLayerInfo(from).hasAnyDependency = true; + GetLayerInfo(to).hasAnyDependency = true; + _dependencies.Add((from, to)); + } + private void AddDependency_Internal(LayerID from, string to) + { + AddDependency_Internal(from, GetLayerID(to)); + } + private void AddDependency_Internal(string from, LayerID to) + { + AddDependency_Internal(GetLayerID(from), to); + } + private void AddDependency_Internal(string from, string to) + { + AddDependency_Internal(GetLayerID(from), GetLayerID(to)); + } + #endregion + + #region Add + public DependencyHandler Add(string layer) + { + var id = GetLayerID(layer); + Add_Internal(id); + return new DependencyHandler(this, (int)id); + } + public DependencyHandler Add(params string[] layers) + { + return Add(layersRange: layers); + } + public DependencyHandler Add(IEnumerable layersRange) + { + foreach (var layer in layersRange) + { + Add_Internal(GetLayerID(layer)); + } + return new DependencyHandler(this, layersRange); + } + #endregion + + #region Move + public DependencyHandler Move(string layer) + { + return new DependencyHandler(this, (int)GetLayerID(layer)); + } + public DependencyHandler Move(params string[] layers) + { + return new DependencyHandler(this, layers); + } + public DependencyHandler Move(IEnumerable layersRange) + { + return new DependencyHandler(this, layersRange); + } + #endregion + + #region Remove + public void Remove(string layer) + { + Remove_Internal(GetLayerID(layer)); + } + public void Remove(params string[] layers) + { + Remove(layersRange: layers); + } + public void Remove(IEnumerable layersRange) + { + foreach (var layer in layersRange) + { + Remove_Internal(GetLayerID(layer)); + } + } + #endregion + + #region MergeWith + public void MergeWith(LayersMap other) + { + foreach (var otherDependency in other._dependencies) + { + AddDependency_Internal(other.GetLayerInfo(otherDependency.From).name, other.GetLayerInfo(otherDependency.To).name); + } + for (int i = 0; i < other._layerInfos.Count; i++) + { + LayerID otherLayerID = (LayerID)i; + ref var otherLayerInfo = ref other.GetLayerInfo(otherLayerID); + Add(otherLayerInfo.name); + } + } + #endregion + + private enum LayerID : int { NULL = 0 } + public readonly ref struct DependencyHandler + { + private readonly LayersMap _source; + private readonly LayerID _id; + private readonly IEnumerable _layersRange; + + #region Properties + public EcsPipeline.Builder Back + { + get { return _source._source; } + } + #endregion + + #region Constructors + public DependencyHandler(LayersMap source, int id) + { + _source = source; + _id = (LayerID)id; + _layersRange = null; + } + public DependencyHandler(LayersMap source, IEnumerable layersRange) + { + _source = source; + _id = LayerID.NULL; + _layersRange = layersRange; + } + #endregion + + #region Before + public DependencyHandler Before(params string[] targets) + { + return Before(range: targets); + } + public DependencyHandler Before(IEnumerable range) + { + foreach (var target in range) + { + Before(target); + } + return this; + } + public DependencyHandler Before(string targetLayer) + { + if (_id != LayerID.NULL) + { + _source.AddDependency_Internal(_id, targetLayer); + } + if (_layersRange != null) + { + foreach (var layer in _layersRange) + { + _source.AddDependency_Internal(layer, targetLayer); + } + } + return this; + } + #endregion + + #region After + public DependencyHandler After(params string[] targets) + { + return After(range: targets); + } + public DependencyHandler After(IEnumerable range) + { + foreach (var target in range) + { + After(target); + } + return this; + } + public DependencyHandler After(string target) + { + if (_id != LayerID.NULL) + { + _source.AddDependency_Internal(target, _id); + } + if (_layersRange != null) + { + foreach (var id in _layersRange) + { + _source.AddDependency_Internal(target, id); + } + } + return this; + } + #endregion + } + + #region Build + public string[] Build() + { + LayerID[] nodes = new LayerID[_count]; + var adjacency = new List<(LayerID To, int DependencyIndex)>[_layerInfos.Count]; + + for (int i = 0, j = 0; i < _layerInfos.Count; i++) + { + LayerID layerID = (LayerID)i; + ref var info = ref GetLayerInfo(layerID); + adjacency[(int)layerID] = new List<(LayerID To, int DependencyIndex)>(); + _layerInfos._items[(int)layerID].inDegree = 0; + if (info.isContained) + { + nodes[j++] = layerID; + } + } + + for (int i = 0; i < _dependencies.Count; i++) + { + var (from, to) = _dependencies[i]; + ref var fromInfo = ref GetLayerInfo(from); + ref var toInfo = ref GetLayerInfo(to); + + if (fromInfo.isContained && toInfo.isContained) + { + adjacency[(int)from].Add((to, i)); + toInfo.inDegree += 1; + } + } + + if (_basicLayerID != LayerID.NULL) + { + int ind = _dependencies.Count; + var basicLayerAdjacencyList = adjacency[(int)_basicLayerID]; + for (int i = 0; i < _layerInfos.Count; i++) + { + ref var toInfo = ref _layerInfos._items[i]; + if(toInfo.isContained && toInfo.hasAnyDependency == false) + { + basicLayerAdjacencyList.Add(((LayerID)i, ind++)); + toInfo.inDegree += 1; + } + } + } + + + List zeroInDegree = new List(nodes.Length); + zeroInDegree.AddRange(nodes.Where(id => GetLayerInfo(id).inDegree == 0).OrderBy(id => GetLayerInfo(id).insertionIndex)); + + var result = new List(nodes.Length); + + while (zeroInDegree.Count > 0) + { + var current = zeroInDegree[0]; + zeroInDegree.RemoveAt(0); + result.Add(GetLayerInfo(current).name); + + foreach (var (neighbor, _) in adjacency[(int)current]) + { + ref var neighborInfo = ref GetLayerInfo(neighbor); + neighborInfo.inDegree--; + if (neighborInfo.inDegree == 0) + { + var neighborInsertionIndex = neighborInfo.insertionIndex; + int insertIndex = zeroInDegree.FindIndex(id => GetLayerInfo(id).insertionIndex < neighborInsertionIndex); + insertIndex = insertIndex < 0 ? 0 : insertIndex; + zeroInDegree.Insert(insertIndex, neighbor); + } + } + } + + if (result.Count != nodes.Length) + { + var cycle = FindCycle(adjacency, nodes); + string details = string.Empty; + if (cycle != null) + { + var cycleDependencies = GetCycleDependencies(cycle, adjacency); + details = $" Cycle edges path: {string.Join(", ", cycleDependencies)}"; + } + throw new InvalidOperationException("Cyclic dependency detected." + details); + } + + return result.ToArray(); + } + #endregion + + #region FindCycles + private List FindCycle( + List<(LayerID To, int DependencyIndex)>[] adjacency, + LayerID[] nodes) + { + var visited = new Dictionary(); + var recursionStack = new Stack(); + + foreach (var node in nodes) + { + if (FindCycleDFS(node, adjacency, visited, recursionStack)) + { + return recursionStack.Reverse().ToList(); + } + } + return null; + } + private bool FindCycleDFS( + LayerID node, + List<(LayerID To, int DependencyIndex)>[] adjacency, + Dictionary visited, + Stack recursionStack) + { + if (!visited.TryGetValue(node, out bool isVisited)) + { + visited[node] = true; + recursionStack.Push(node); + + foreach (var (neighbor, _) in adjacency[(int)node]) + { + if (!visited.ContainsKey(neighbor) && FindCycleDFS(neighbor, adjacency, visited, recursionStack)) + { + return true; + } + else if (recursionStack.Contains(neighbor)) + { + recursionStack.Push(neighbor); + return true; + } + } + + recursionStack.Pop(); + return false; + } + return isVisited && recursionStack.Contains(node); + } + + private string[] GetCycleDependencies( + List cycle, + List<(LayerID To, int DependencyIndex)>[] adjacency) + { + var cycleEdges = new HashSet<(LayerID, LayerID)>(); + for (int i = 0; i < cycle.Count - 1; i++) + { + cycleEdges.Add((cycle[i], cycle[i + 1])); + } + + var dependencies = new List(); + foreach (var from in cycle) + { + foreach (var (to, depIndex) in adjacency[(int)from]) + { + if (cycleEdges.Contains((from, to)) && _dependencies.Count > depIndex) + { + var dep = _dependencies[depIndex]; + dependencies.Add($"{GetLayerInfo(dep.From).name}->{GetLayerInfo(dep.To).name}"); + } + } + } + return dependencies.Distinct().ToArray(); + } + #endregion + + #region Other + public bool Contains(string layer) { return GetLayerInfo(GetLayerID(layer)).isContained; } + + public Enumerator GetEnumerator() { return new Enumerator(this); } + IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } + IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } + public struct Enumerator : IEnumerator + { + private LayersMap _map; + private int _index; + public Enumerator(LayersMap map) + { + _map = map; + _index = -1; + } + public string Current + { + get { return _map._layerInfos._items[_index].name; } + } + object IEnumerator.Current { get { return Current; } } + public bool MoveNext() + { + if (_index++ >= _map._layerInfos.Count) { return false; } + ref var info = ref _map._layerInfos._items[_index]; + if(info.isContained == false) + { + return MoveNext(); + } + else + { + return true; + } + } + public void Reset() { _index = -1; } + public void Dispose() { } + } + #endregion + + #region Obsolete + [Obsolete("Use " + nameof(LayersMap) + ".Add(layer).Before(targetLayer).Back;")] + public EcsPipeline.Builder Insert(string targetLayer, string newLayer) + { + Add(newLayer).Before(targetLayer); + return _source; + } + [Obsolete("Use " + nameof(LayersMap) + ".Add(layer).After(targetLayer).Back;")] + public EcsPipeline.Builder InsertAfter(string targetLayer, string newLayer) + { + Add(newLayer).After(targetLayer); + return _source; + } + [Obsolete("Use " + nameof(LayersMap) + ".Move(layer).Before(targetLayer).Back;")] + public EcsPipeline.Builder Move(string targetLayer, string newLayer) + { + Move(newLayer).Before(targetLayer); + return _source; + } + [Obsolete("Use " + nameof(LayersMap) + ".Move(layer).After(targetLayer).Back;")] + public EcsPipeline.Builder MoveAfter(string targetLayer, string newLayer) + { + Move(newLayer).After(targetLayer); + return _source; + } + [Obsolete("Use " + nameof(LayersMap) + ".Add(layers).Before(targetLayer).Back;")] + public EcsPipeline.Builder Insert(string targetLayer, params string[] newLayers) + { + Add(newLayers).Before(targetLayer); + return _source; + } + [Obsolete("Use " + nameof(LayersMap) + ".Add(layers).After(targetLayer).Back;")] + public EcsPipeline.Builder InsertAfter(string targetLayer, params string[] newLayers) + { + Add(newLayers).After(targetLayer); + return _source; + } + [Obsolete("Use " + nameof(LayersMap) + ".Move(layers).Before(targetLayer).Back;")] + public EcsPipeline.Builder Move(string targetLayer, params string[] movingLayers) + { + Move(movingLayers).Before(targetLayer); + return _source; + } + [Obsolete("Use " + nameof(LayersMap) + ".Move(layers).After(targetLayer).Back;")] + public EcsPipeline.Builder MoveAfter(string targetLayer, params string[] movingLayers) + { + Move(movingLayers).After(targetLayer); + return _source; + } + + [Obsolete] + public object this[int index] + { + get + { + int i = 0; + foreach (var item in this) + { + if (i == index) + { + return item; + } + i++; + } + return null; + } + } + [Obsolete("Use MergeWith(LayersMap)")] + public void MergeWith(IReadOnlyList other) + { + foreach (var layer in other) + { + Add(layer); + } + } + #endregion + } +} \ No newline at end of file From a46581f895912a16c5e4532f9f6898f0a92b7d7e Mon Sep 17 00:00:00 2001 From: DCFApixels <99481254+DCFApixels@users.noreply.github.com> Date: Wed, 2 Apr 2025 08:25:17 +0800 Subject: [PATCH 2/9] fix --- src/Utils/LayersMap.cs | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/Utils/LayersMap.cs b/src/Utils/LayersMap.cs index 6952bc2..1366e92 100644 --- a/src/Utils/LayersMap.cs +++ b/src/Utils/LayersMap.cs @@ -2,6 +2,7 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; namespace DCFApixels.DragonECS.Core @@ -27,6 +28,7 @@ namespace DCFApixels.DragonECS.Core { return ref _layerInfos._items[(int)layerID]; } + [DebuggerDisplay("{name}")] private struct LayerInfo { public string name; @@ -339,14 +341,17 @@ namespace DCFApixels.DragonECS.Core if (_basicLayerID != LayerID.NULL) { - int ind = _dependencies.Count; var basicLayerAdjacencyList = adjacency[(int)_basicLayerID]; + int inserIndex = basicLayerAdjacencyList.Count; + //for (int i = _layerInfos.Count - 1; i >= 0; i--) for (int i = 0; i < _layerInfos.Count; i++) { + var id = (LayerID)i; ref var toInfo = ref _layerInfos._items[i]; if(toInfo.isContained && toInfo.hasAnyDependency == false) { - basicLayerAdjacencyList.Add(((LayerID)i, ind++)); + toInfo.insertionIndex = -toInfo.insertionIndex; + basicLayerAdjacencyList.Insert(inserIndex, (id, toInfo.insertionIndex)); toInfo.inDegree += 1; } } @@ -362,10 +367,15 @@ namespace DCFApixels.DragonECS.Core { var current = zeroInDegree[0]; zeroInDegree.RemoveAt(0); + result.Add(GetLayerInfo(current).name); - foreach (var (neighbor, _) in adjacency[(int)current]) + + var adjacencyList = adjacency[(int)current]; + //for (int i = adjacencyList.Count - 1; i >= 0; i--) + for (int i = 0; i < adjacencyList.Count; i++) { + var (neighbor, _) = adjacencyList[i]; ref var neighborInfo = ref GetLayerInfo(neighbor); neighborInfo.inDegree--; if (neighborInfo.inDegree == 0) @@ -374,6 +384,9 @@ namespace DCFApixels.DragonECS.Core int insertIndex = zeroInDegree.FindIndex(id => GetLayerInfo(id).insertionIndex < neighborInsertionIndex); insertIndex = insertIndex < 0 ? 0 : insertIndex; zeroInDegree.Insert(insertIndex, neighbor); + + //zeroInDegree.Add(neighbor); + //zeroInDegree = zeroInDegree.OrderBy(id => GetLayerInfo(id).insertionIndex).ToList(); } } } From 8bab3107628cb1fc39cef51a3be7d5c7f82f6ee3 Mon Sep 17 00:00:00 2001 From: DCFApixels <99481254+DCFApixels@users.noreply.github.com> Date: Thu, 3 Apr 2025 21:21:24 +0800 Subject: [PATCH 3/9] stash --- src/Utils/LayersMap.cs | 37 +++++++++++++++++++++++++------------ 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/src/Utils/LayersMap.cs b/src/Utils/LayersMap.cs index 1366e92..0a2d369 100644 --- a/src/Utils/LayersMap.cs +++ b/src/Utils/LayersMap.cs @@ -45,7 +45,8 @@ namespace DCFApixels.DragonECS.Core } private readonly EcsPipeline.Builder _source; - private StructList<(LayerID From, LayerID To)> _dependencies = new StructList<(LayerID, LayerID)>(16); + private List<(LayerID From, LayerID To)> _dependencies = new List<(LayerID, LayerID)>(16); + private readonly LayerID _rootLayerID; private readonly LayerID _basicLayerID; private int _increment = 0; private int _count; @@ -62,6 +63,8 @@ namespace DCFApixels.DragonECS.Core { GetLayerID(""); _source = source; + _rootLayerID = LayerID.NULL; + _basicLayerID = LayerID.NULL; } public LayersMap(EcsPipeline.Builder source, string basicLayerName) { @@ -70,6 +73,7 @@ namespace DCFApixels.DragonECS.Core Add(basicLayerName); + _rootLayerID = LayerID.NULL; _basicLayerID = GetLayerID(basicLayerName); LockLayer(basicLayerName); } @@ -92,6 +96,7 @@ namespace DCFApixels.DragonECS.Core Add(postEndLayer) .After(endLayer); + _rootLayerID = GetLayerID(preBeginlayer); _basicLayerID = GetLayerID(basicLayer); LockLayer(preBeginlayer); LockLayer(beginlayer); @@ -128,23 +133,32 @@ namespace DCFApixels.DragonECS.Core } info.insertionIndex = 0; } - private void AddDependency_Internal(LayerID from, LayerID to) + private void AddDependency_Internal(LayerID from, LayerID to, bool isBefore = false) { GetLayerInfo(from).hasAnyDependency = true; + GetLayerInfo(to).hasAnyDependency = true; + if (isBefore) + { + GetLayerInfo(from).insertionIndex = int.MaxValue - (_increment++); + } + else + { + } _dependencies.Add((from, to)); + //_dependencies.Insert(0, (from, to)); } - private void AddDependency_Internal(LayerID from, string to) + private void AddDependency_Internal(LayerID from, string to, bool isBefore = false) { - AddDependency_Internal(from, GetLayerID(to)); + AddDependency_Internal(from, GetLayerID(to), isBefore); } - private void AddDependency_Internal(string from, LayerID to) + private void AddDependency_Internal(string from, LayerID to, bool isBefore = false) { - AddDependency_Internal(GetLayerID(from), to); + AddDependency_Internal(GetLayerID(from), to, isBefore); } - private void AddDependency_Internal(string from, string to) + private void AddDependency_Internal(string from, string to, bool isBefore = false) { - AddDependency_Internal(GetLayerID(from), GetLayerID(to)); + AddDependency_Internal(GetLayerID(from), GetLayerID(to), isBefore); } #endregion @@ -264,13 +278,13 @@ namespace DCFApixels.DragonECS.Core { if (_id != LayerID.NULL) { - _source.AddDependency_Internal(_id, targetLayer); + _source.AddDependency_Internal(_id, targetLayer, true); } if (_layersRange != null) { foreach (var layer in _layersRange) { - _source.AddDependency_Internal(layer, targetLayer); + _source.AddDependency_Internal(layer, targetLayer, true); } } return this; @@ -350,14 +364,13 @@ namespace DCFApixels.DragonECS.Core ref var toInfo = ref _layerInfos._items[i]; if(toInfo.isContained && toInfo.hasAnyDependency == false) { - toInfo.insertionIndex = -toInfo.insertionIndex; + //toInfo.insertionIndex = -toInfo.insertionIndex; basicLayerAdjacencyList.Insert(inserIndex, (id, toInfo.insertionIndex)); toInfo.inDegree += 1; } } } - List zeroInDegree = new List(nodes.Length); zeroInDegree.AddRange(nodes.Where(id => GetLayerInfo(id).inDegree == 0).OrderBy(id => GetLayerInfo(id).insertionIndex)); From 7a7c93fe8213918b9655ec8630716e83d0e4444e Mon Sep 17 00:00:00 2001 From: DCFApixels <99481254+DCFApixels@users.noreply.github.com> Date: Sat, 5 Apr 2025 00:53:33 +0800 Subject: [PATCH 4/9] stash --- src/Utils/LayersMap.cs | 96 +++++++++++++++++++++++++++++------------- 1 file changed, 66 insertions(+), 30 deletions(-) diff --git a/src/Utils/LayersMap.cs b/src/Utils/LayersMap.cs index 0a2d369..c4aa231 100644 --- a/src/Utils/LayersMap.cs +++ b/src/Utils/LayersMap.cs @@ -32,9 +32,10 @@ namespace DCFApixels.DragonECS.Core private struct LayerInfo { public string name; + public int insertionIndex; public bool isLocked; public bool isContained; - public int insertionIndex; + public bool isBefore; //build public int inDegree; public bool hasAnyDependency; @@ -51,6 +52,14 @@ namespace DCFApixels.DragonECS.Core private int _increment = 0; private int _count; + public IEnumerable<(string from, string to)> Deps + { + get + { + return _dependencies.Select(o => (GetLayerInfo(o.From).name, GetLayerInfo(o.To).name)); + } + } + #region Properties public int Count { @@ -82,17 +91,17 @@ namespace DCFApixels.DragonECS.Core GetLayerID(""); _source = source; - Add(preBeginlayer) - .Before(beginlayer); + Add(preBeginlayer); + //.Before(beginlayer); Add(beginlayer) - .After(preBeginlayer) - .Before(basicLayer); + //.Before(basicLayer) + .After(preBeginlayer); Add(basicLayer) - .After(beginlayer) - .Before(endLayer); + //.Before(endLayer) + .After(beginlayer); Add(endLayer) - .After(basicLayer) - .Before(postEndLayer); + //.Before(postEndLayer) + .After(basicLayer); Add(postEndLayer) .After(endLayer); @@ -136,17 +145,22 @@ namespace DCFApixels.DragonECS.Core private void AddDependency_Internal(LayerID from, LayerID to, bool isBefore = false) { GetLayerInfo(from).hasAnyDependency = true; - GetLayerInfo(to).hasAnyDependency = true; + if (isBefore) { - GetLayerInfo(from).insertionIndex = int.MaxValue - (_increment++); + //GetLayerInfo(from).insertionIndex = 1000 - (_increment++); + GetLayerInfo(from).isBefore = true; + //_dependencies.Insert(0, (from, to)); } else { + //GetLayerInfo(from).insertionIndex = _increment++; + GetLayerInfo(from).isBefore = false; + //_dependencies.Add((from, to)); } - _dependencies.Add((from, to)); //_dependencies.Insert(0, (from, to)); + _dependencies.Add((from, to)); } private void AddDependency_Internal(LayerID from, string to, bool isBefore = false) { @@ -353,23 +367,24 @@ namespace DCFApixels.DragonECS.Core } } - if (_basicLayerID != LayerID.NULL) - { - var basicLayerAdjacencyList = adjacency[(int)_basicLayerID]; - int inserIndex = basicLayerAdjacencyList.Count; - //for (int i = _layerInfos.Count - 1; i >= 0; i--) - for (int i = 0; i < _layerInfos.Count; i++) - { - var id = (LayerID)i; - ref var toInfo = ref _layerInfos._items[i]; - if(toInfo.isContained && toInfo.hasAnyDependency == false) - { - //toInfo.insertionIndex = -toInfo.insertionIndex; - basicLayerAdjacencyList.Insert(inserIndex, (id, toInfo.insertionIndex)); - toInfo.inDegree += 1; - } - } - } + //// добавление зависимостей для нод без зависимостей. + //if (_basicLayerID != LayerID.NULL) + //{ + // var basicLayerAdjacencyList = adjacency[(int)_basicLayerID]; + // int inserIndex = basicLayerAdjacencyList.Count; + // //for (int i = _layerInfos.Count - 1; i >= 0; i--) + // for (int i = 0; i < _layerInfos.Count; i++) + // { + // var id = (LayerID)i; + // ref var toInfo = ref _layerInfos._items[i]; + // if(toInfo.isContained && toInfo.hasAnyDependency == false) + // { + // //toInfo.insertionIndex = -toInfo.insertionIndex; + // basicLayerAdjacencyList.Insert(inserIndex, (id, toInfo.insertionIndex)); + // toInfo.inDegree += 1; + // } + // } + //} List zeroInDegree = new List(nodes.Length); zeroInDegree.AddRange(nodes.Where(id => GetLayerInfo(id).inDegree == 0).OrderBy(id => GetLayerInfo(id).insertionIndex)); @@ -397,11 +412,32 @@ namespace DCFApixels.DragonECS.Core int insertIndex = zeroInDegree.FindIndex(id => GetLayerInfo(id).insertionIndex < neighborInsertionIndex); insertIndex = insertIndex < 0 ? 0 : insertIndex; zeroInDegree.Insert(insertIndex, neighbor); - + //zeroInDegree.Add(neighbor); //zeroInDegree = zeroInDegree.OrderBy(id => GetLayerInfo(id).insertionIndex).ToList(); } } + + //var adjacencyList = adjacency[(int)current]; + ////var adjacencyListSort = adjacencyList.OrderBy(o => GetLayerInfo(o.To).insertionIndex); + //var adjacencyListSort = adjacencyList; + //foreach (var item in adjacencyListSort) + //{ + // var (neighbor, _) = item; + // ref var neighborInfo = ref GetLayerInfo(neighbor); + // neighborInfo.inDegree--; + // if (neighborInfo.inDegree == 0) + // { + // //var neighborInsertionIndex = neighborInfo.insertionIndex; + // //int insertIndex = zeroInDegree.FindIndex(id => GetLayerInfo(id).insertionIndex > neighborInsertionIndex); + // //insertIndex = insertIndex < 0 ? 0 : insertIndex; + // // + // //zeroInDegree.Insert(insertIndex, neighbor); + // + // zeroInDegree.Add(neighbor); + // zeroInDegree = zeroInDegree.OrderBy(id => GetLayerInfo(id).insertionIndex).ToList(); + // } + //} } if (result.Count != nodes.Length) From 20aff3a45268e5a1607e62ea83a8b3afefb47fab Mon Sep 17 00:00:00 2001 From: DCFApixels <99481254+DCFApixels@users.noreply.github.com> Date: Sat, 5 Apr 2025 18:08:07 +0800 Subject: [PATCH 5/9] update LayersMap stash --- src/EcsPipeline.Builder.cs | 40 +- src/Utils/DependencyGraph.cs | 816 +++++++++++++++++++++++++++++++ src/Utils/EcsPipelineTemplate.cs | 3 +- src/Utils/LayersMap.cs | 647 ------------------------ 4 files changed, 840 insertions(+), 666 deletions(-) create mode 100644 src/Utils/DependencyGraph.cs delete mode 100644 src/Utils/LayersMap.cs diff --git a/src/EcsPipeline.Builder.cs b/src/EcsPipeline.Builder.cs index 2966088..0beb97d 100644 --- a/src/EcsPipeline.Builder.cs +++ b/src/EcsPipeline.Builder.cs @@ -63,7 +63,7 @@ namespace DCFApixels.DragonECS Injector.AddNode(); Injector.AddNode(); - Layers = new LayersMap(this, PRE_BEGIN_LAYER, BEGIN_LAYER, BASIC_LAYER, END_LAYER, POST_END_LAYER); + //Layers = new DependencyGraph(this, PRE_BEGIN_LAYER, BEGIN_LAYER, BASIC_LAYER, END_LAYER, POST_END_LAYER); } #endregion @@ -233,21 +233,22 @@ namespace DCFApixels.DragonECS } private void MergeWith(Builder other) { - Injector.Add(other.Injector); - foreach (var declaredRunners in other._initDeclaredRunners) - { - _initDeclaredRunners.Add(declaredRunners); - } - foreach (var config in other.Configs.Instance.GetAllConfigs()) - { - Configs.Instance.Set(config.Key, config.Value); - } - Layers.MergeWith(other.Layers); - - foreach (ref readonly SystemNode otherRecord in new LinkedListCountIterator(_systemNodes, _systemNodesCount, _startIndex)) - { - AddNode_Internal(otherRecord.system, otherRecord.layerName, otherRecord.sortOrder, otherRecord.isUnique); - } + throw new NotImplementedException(); + //Injector.Add(other.Injector); + //foreach (var declaredRunners in other._initDeclaredRunners) + //{ + // _initDeclaredRunners.Add(declaredRunners); + //} + //foreach (var config in other.Configs.Instance.GetAllConfigs()) + //{ + // Configs.Instance.Set(config.Key, config.Value); + //} + //Layers.MergeWith(other.Layers); + // + //foreach (ref readonly SystemNode otherRecord in new LinkedListCountIterator(_systemNodes, _systemNodesCount, _startIndex)) + //{ + // AddNode_Internal(otherRecord.system, otherRecord.layerName, otherRecord.sortOrder, otherRecord.isUnique); + //} } #endregion @@ -565,8 +566,11 @@ namespace DCFApixels.DragonECS [Obsolete("Use LayersMap")] public class LayerList : LayersMap { - public LayerList(Builder source, string basicLayerName) : base(source, basicLayerName) { } - public LayerList(Builder source, string preBeginlayer, string beginlayer, string basicLayer, string endLayer, string postEndLayer) : base(source, preBeginlayer, beginlayer, basicLayer, endLayer, postEndLayer) { } + //public LayerList(Builder source, string basicLayerName) : base(source, basicLayerName) { } + //public LayerList(Builder source, string preBeginlayer, string beginlayer, string basicLayer, string endLayer, string postEndLayer) : base(source, preBeginlayer, beginlayer, basicLayer, endLayer, postEndLayer) { } + public LayerList(IDependencyGraph graph, Builder pipelineBuilder) : base(graph, pipelineBuilder) + { + } } #endregion } diff --git a/src/Utils/DependencyGraph.cs b/src/Utils/DependencyGraph.cs new file mode 100644 index 0000000..05080da --- /dev/null +++ b/src/Utils/DependencyGraph.cs @@ -0,0 +1,816 @@ +using DCFApixels.DragonECS.Internal; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +namespace DCFApixels.DragonECS.Core +{ + using VertextID = DependencyGraphVertextID; + public enum DependencyGraphVertextID : short { NULL = 0 } + public interface IDependencyGraph + { + int Count { get; } + VertextID AddVertex(T vertex, bool isLocked); + bool ContainsVertex(T vertex); + VertextID GetVertexID(T vertex); + bool RemoveVertex(T vertex); + void AddBeforeDependency(VertextID vertexID, VertextID otherVertexID); + void AddAfterDependency(VertextID vertexID, VertextID otherVertexID); + T[] Sort(); + } + public class LayersMap + { + private readonly IDependencyGraph _graph; + private readonly EcsPipeline.Builder _pipelineBuilder; + + #region Properties + public EcsPipeline.Builder Back + { + get { return _pipelineBuilder; } + } + public int Count + { + get { return _graph.Count; } + } + #endregion + + #region Constructors + public LayersMap(IDependencyGraph graph, EcsPipeline.Builder pipelineBuilder) + { + _graph = graph; + _pipelineBuilder = pipelineBuilder; + } + public LayersMap(IDependencyGraph graph, EcsPipeline.Builder pipelineBuilder, string preBeginlayer, string beginlayer, string basicLayer, string endLayer, string postEndLayer) + { + _graph = graph; + _pipelineBuilder = pipelineBuilder; + + graph.AddVertex(preBeginlayer, true); + graph.AddVertex(beginlayer, true); + graph.AddVertex(basicLayer, true); + graph.AddVertex(endLayer, true); + graph.AddVertex(postEndLayer, true); + + Move(preBeginlayer); + //.Before(beginlayer); + Move(beginlayer) + //.Before(basicLayer) + .After(preBeginlayer); + Move(basicLayer) + //.Before(endLayer) + .After(beginlayer); + Move(endLayer) + //.Before(postEndLayer) + .After(basicLayer); + Move(postEndLayer) + .After(endLayer); + } + #endregion + + #region Add + public MoveHandler Add(string layer) + { + VertextID id = _graph.AddVertex(layer, false); + return new MoveHandler(_graph, _pipelineBuilder, id); + } + public MoveHandler Add(params string[] layers) + { + return Add(layersRange: layers); + } + public MoveHandler Add(IEnumerable layersRange) + { + foreach (var layer in layersRange) + { + Add(layer); + } + return new MoveHandler(_graph, _pipelineBuilder, layersRange); + } + #endregion + + #region Move + public MoveHandler Move(string layer) + { + VertextID id = _graph.GetVertexID(layer); + return new MoveHandler(_graph, _pipelineBuilder, id); + } + public MoveHandler Move(params string[] layers) + { + return new MoveHandler(_graph, _pipelineBuilder, layers); + } + public MoveHandler Move(IEnumerable layersRange) + { + return new MoveHandler(_graph, _pipelineBuilder, layersRange); + } + #endregion + + public struct MoveHandler + { + private readonly IDependencyGraph _graph; + private readonly EcsPipeline.Builder _pipelineBuilder; + private readonly VertextID _layerID; + private readonly IEnumerable _layersRange; + + #region Properties + public EcsPipeline.Builder Back + { + get { return _pipelineBuilder; } + } + #endregion + + #region Constructors + public MoveHandler(IDependencyGraph graph, EcsPipeline.Builder pipelineBuilder, VertextID id) + { + _graph = graph; + _pipelineBuilder = pipelineBuilder; + _layerID = id; + _layersRange = null; + } + public MoveHandler(IDependencyGraph graph, EcsPipeline.Builder pipelineBuilder, IEnumerable layersRange) + { + _graph = graph; + _pipelineBuilder = pipelineBuilder; + _layerID = VertextID.NULL; + _layersRange = layersRange; + } + #endregion + + #region Before + public MoveHandler Before(params string[] targets) + { + return Before(targetsRange: targets); + } + public MoveHandler Before(IEnumerable targetsRange) + { + foreach (var target in targetsRange) + { + Before(target); + } + return this; + } + public MoveHandler Before(string targetLayer) + { + if (_layerID != VertextID.NULL) + { + _graph.AddBeforeDependency(_layerID, _graph.GetVertexID(targetLayer)); + } + if (_layersRange != null) + { + foreach (var layer in _layersRange) + { + _graph.AddBeforeDependency(_graph.GetVertexID(layer), _graph.GetVertexID(targetLayer)); + } + } + return this; + } + #endregion + + #region After + public MoveHandler After(params string[] targets) + { + return After(targetsRange: targets); + } + public MoveHandler After(IEnumerable targetsRange) + { + foreach (var target in targetsRange) + { + After(target); + } + return this; + } + public MoveHandler After(string targetLayer) + { + if (_layerID != VertextID.NULL) + { + _graph.AddAfterDependency(_graph.GetVertexID(targetLayer), _layerID); + } + if (_layersRange != null) + { + foreach (var layer in _layersRange) + { + _graph.AddBeforeDependency(_graph.GetVertexID(targetLayer), _graph.GetVertexID(layer)); + } + } + return this; + } + #endregion + } + + #region Other + public bool Contains(string layer) { return _graph.ContainsVertex(layer); } + + //public Enumerator GetEnumerator() { return new Enumerator(this); } + //IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } + //IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } + //public struct Enumerator : IEnumerator + //{ + // private DependencyGraph _map; + // private int _index; + // public Enumerator(DependencyGraph map) + // { + // _map = map; + // _index = -1; + // } + // public string Current + // { + // get { return _map._vertexInfos._items[_index].name; } + // } + // object IEnumerator.Current { get { return Current; } } + // public bool MoveNext() + // { + // if (_index++ >= _map._vertexInfos.Count) { return false; } + // ref var info = ref _map._vertexInfos._items[_index]; + // if (info.isContained == false) + // { + // return MoveNext(); + // } + // else + // { + // return true; + // } + // } + // public void Reset() { _index = -1; } + // public void Dispose() { } + //} + #endregion + + #region Build + public string[] Build() + { + return _graph.Sort(); + } + #endregion + + #region Obsolete + [Obsolete("Use " + nameof(DependencyGraph) + ".Add(layer).Before(targetLayer).Back;")] + public EcsPipeline.Builder Insert(string targetLayer, string newLayer) + { + Add(newLayer).Before(targetLayer); + return _pipelineBuilder; + } + [Obsolete("Use " + nameof(DependencyGraph) + ".Add(layer).After(targetLayer).Back;")] + public EcsPipeline.Builder InsertAfter(string targetLayer, string newLayer) + { + Add(newLayer).After(targetLayer); + return _pipelineBuilder; + } + [Obsolete("Use " + nameof(DependencyGraph) + ".Move(layer).Before(targetLayer).Back;")] + public EcsPipeline.Builder Move(string targetLayer, string newLayer) + { + Move(newLayer).Before(targetLayer); + return _pipelineBuilder; + } + [Obsolete("Use " + nameof(DependencyGraph) + ".Move(layer).After(targetLayer).Back;")] + public EcsPipeline.Builder MoveAfter(string targetLayer, string newLayer) + { + Move(newLayer).After(targetLayer); + return _pipelineBuilder; + } + [Obsolete("Use " + nameof(DependencyGraph) + ".Add(layers).Before(targetLayer).Back;")] + public EcsPipeline.Builder Insert(string targetLayer, params string[] newLayers) + { + Add(newLayers).Before(targetLayer); + return _pipelineBuilder; + } + [Obsolete("Use " + nameof(DependencyGraph) + ".Add(layers).After(targetLayer).Back;")] + public EcsPipeline.Builder InsertAfter(string targetLayer, params string[] newLayers) + { + Add(newLayers).After(targetLayer); + return _pipelineBuilder; + } + [Obsolete("Use " + nameof(DependencyGraph) + ".Move(layers).Before(targetLayer).Back;")] + public EcsPipeline.Builder Move(string targetLayer, params string[] movingLayers) + { + Move(movingLayers).Before(targetLayer); + return _pipelineBuilder; + } + [Obsolete("Use " + nameof(DependencyGraph) + ".Move(layers).After(targetLayer).Back;")] + public EcsPipeline.Builder MoveAfter(string targetLayer, params string[] movingLayers) + { + Move(movingLayers).After(targetLayer); + return _pipelineBuilder; + } + + [Obsolete] + public object this[int index] + { + get + { + //int i = 0; + //foreach (var item in this) + //{ + // if (i == index) + // { + // return item; + // } + // i++; + //} + return null; + } + } + [Obsolete("Use MergeWith(LayersMap)")] + public void MergeWith(IReadOnlyList other) + { + foreach (var layer in other) + { + Add(layer); + } + } + #endregion + } + + + + public partial class DependencyGraph : IEnumerable, IDependencyGraph + { + #region IDependencyGraph + VertextID IDependencyGraph.AddVertex(string vertex, bool isLocked) + { + var result = GetVertexID(vertex); + Add_Internal(result); + if (isLocked) + { + LockVertex(vertex); + } + return result; + } + bool IDependencyGraph.ContainsVertex(string vertex) + { + return GetVertexInfo(GetVertexID(vertex)).isContained; + } + VertextID IDependencyGraph.GetVertexID(string vertex) + { + return GetVertexID(vertex); + } + bool IDependencyGraph.RemoveVertex(string vertex) + { + var result = GetVertexID(vertex); + return Remove_Internal(result); + } + void IDependencyGraph.AddAfterDependency(VertextID fromoVertexID, VertextID toVertexID) + { + AddDependency_Internal(fromoVertexID, toVertexID, false); + } + void IDependencyGraph.AddBeforeDependency(VertextID fromoVertexID, VertextID toVertexID) + { + AddDependency_Internal(fromoVertexID, toVertexID, true); + } + string[] IDependencyGraph.Sort() + { + return Build(); + } + #endregion + + private readonly Dictionary _vertexIDs = new Dictionary(32); + private StructList _vertexInfos = new StructList(32); + private VertextID GetVertexID(string vertext) + { + if (_vertexIDs.TryGetValue(vertext, out VertextID layerID) == false) + { + layerID = (VertextID)_vertexInfos.Count; + _vertexInfos.Add(default); + + _vertexIDs[vertext] = layerID; + ref var layerInfo = ref GetVertexInfo(layerID); + layerInfo.name = vertext; + } + return layerID; + } + private ref VertexInfo GetVertexInfo(VertextID vertexID) + { + return ref _vertexInfos._items[(int)vertexID]; + } + [DebuggerDisplay("{name}")] + private struct VertexInfo + { + public string name; + public int insertionIndex; + public bool isLocked; + public bool isContained; + public bool isBefore; + //build + public bool hasAnyDependency; + public int inDegree; + public int sortingIndex; + public int leftBeforeIndex; + public VertexInfo(string name) : this() + { + this.name = name; + } + } + + private List<(VertextID from, VertextID to)> _dependencies = new List<(VertextID, VertextID)>(16); + private readonly VertextID _basicVertexID; + private int _increment = 0; + private int _count; + + public IEnumerable<(string from, string to)> Deps + { + get + { + return _dependencies.Select(o => (GetVertexInfo(o.from).name, GetVertexInfo(o.to).name)); + } + } + + #region Properties + public int Count + { + get { return _count; } + } + #endregion + + #region Constructors + public DependencyGraph() + { + GetVertexID(""); + _basicVertexID = VertextID.NULL; + } + public DependencyGraph(string basicVertexName) + { + GetVertexID(""); + _basicVertexID = GetVertexID(basicVertexName); + LockVertex(basicVertexName); + } + #endregion + + #region Methods + private void LockVertex(string veretex) + { + GetVertexInfo(GetVertexID(veretex)).isLocked = true; + } + private void Add_Internal(VertextID id) + { + ref var info = ref GetVertexInfo(id); + if (info.isContained == false || info.isLocked == false) + { + _count++; + info.isContained = true; + info.insertionIndex = _increment++; + } + } + private bool Remove_Internal(VertextID id) + { + ref var info = ref GetVertexInfo(id); + bool result = false; + if (info.isLocked) { throw new Exception($"The {info.name} vertex cannot be removed"); } + if (info.isContained) + { + _count--; + info.isContained = false; + result = true; + } + info.insertionIndex = 0; + return result; + } + private void AddDependency_Internal(VertextID from, VertextID to, bool isBefore = false) + { + + ref var fromInfo = ref GetVertexInfo(from); + ref var toInfo = ref GetVertexInfo(to); + fromInfo.hasAnyDependency = true; + toInfo.hasAnyDependency = true; + + if (isBefore) + { + //GetLayerInfo(from).insertionIndex = 1000 - (_increment++); + fromInfo.isBefore = true; + //_dependencies.Insert(0, (from, to)); + } + else + { + //GetLayerInfo(from).insertionIndex = _increment++; + fromInfo.isBefore = false; + //_dependencies.Add((from, to)); + } + //_dependencies.Insert(0, (from, to)); + _dependencies.Add((from, to)); + } + private void AddDependency_Internal(string from, string to, bool isBefore = false) + { + AddDependency_Internal(GetVertexID(from), GetVertexID(to), isBefore); + } + #endregion + + #region MergeWith + public void MergeWith(DependencyGraph other) + { + foreach (var otherDependency in other._dependencies) + { + AddDependency_Internal(other.GetVertexInfo(otherDependency.from).name, other.GetVertexInfo(otherDependency.to).name); + } + for (int i = 0; i < other._vertexInfos.Count; i++) + { + VertextID otherLayerID = (VertextID)i; + ref var otherLayerInfo = ref other.GetVertexInfo(otherLayerID); + Add_Internal(GetVertexID(otherLayerInfo.name)); + } + } + #endregion + + #region Build + private unsafe void TopoSorting(UnsafeArray sortingBuffer) + { + VertextID[] nodes = new VertextID[_count]; + var adjacency = new List<(VertextID To, int DependencyIndex)>[_vertexInfos.Count]; + + for (int i = 0, j = 0; i < _vertexInfos.Count; i++) + { + VertextID layerID = (VertextID)i; + ref var info = ref GetVertexInfo(layerID); + adjacency[(int)layerID] = new List<(VertextID To, int DependencyIndex)>(); + _vertexInfos._items[(int)layerID].inDegree = 0; + if (info.isContained) + { + nodes[j++] = layerID; + } + } + + for (int i = 0; i < _dependencies.Count; i++) + { + var (from, to) = _dependencies[i]; + ref var fromInfo = ref GetVertexInfo(from); + ref var toInfo = ref GetVertexInfo(to); + + if (fromInfo.isContained && toInfo.isContained) + { + adjacency[(int)from].Add((to, i)); + toInfo.inDegree += 1; + } + } + + //// добавление зависимостей для нод без зависимостей. + //if (_basicLayerID != LayerID.NULL) + //{ + // var basicLayerAdjacencyList = adjacency[(int)_basicLayerID]; + // int inserIndex = basicLayerAdjacencyList.Count; + // //for (int i = _layerInfos.Count - 1; i >= 0; i--) + // for (int i = 0; i < _layerInfos.Count; i++) + // { + // var id = (LayerID)i; + // ref var toInfo = ref _layerInfos._items[i]; + // if(toInfo.isContained && toInfo.hasAnyDependency == false) + // { + // //toInfo.insertionIndex = -toInfo.insertionIndex; + // basicLayerAdjacencyList.Insert(inserIndex, (id, toInfo.insertionIndex)); + // toInfo.inDegree += 1; + // } + // } + //} + + List zeroInDegree = new List(nodes.Length); + zeroInDegree.AddRange(nodes.Where(id => GetVertexInfo(id).inDegree == 0).OrderBy(id => GetVertexInfo(id).insertionIndex)); + + //List result = new List(nodes.Length); + int resultCount = 0; + + while (zeroInDegree.Count > 0) + { + var current = zeroInDegree[0]; + zeroInDegree.RemoveAt(0); + + //result.Add(GetVertexInfo(current).name); + GetVertexInfo(current).sortingIndex = resultCount; + sortingBuffer.ptr[resultCount++] = current; + + var adjacencyList = adjacency[(int)current]; + //for (int i = adjacencyList.Count - 1; i >= 0; i--) + for (int i = 0; i < adjacencyList.Count; i++) + { + var (neighbor, _) = adjacencyList[i]; + ref var neighborInfo = ref GetVertexInfo(neighbor); + neighborInfo.inDegree--; + if (neighborInfo.inDegree == 0) + { + var neighborInsertionIndex = neighborInfo.insertionIndex; + int insertIndex = zeroInDegree.FindIndex(id => GetVertexInfo(id).insertionIndex < neighborInsertionIndex); + insertIndex = insertIndex < 0 ? 0 : insertIndex; + zeroInDegree.Insert(insertIndex, neighbor); + + //zeroInDegree.Add(neighbor); + //zeroInDegree = zeroInDegree.OrderBy(id => GetLayerInfo(id).insertionIndex).ToList(); + } + } + } + + if (resultCount != nodes.Length) + { + var cycle = FindCycle(adjacency, nodes); + string details = string.Empty; + if (cycle != null) + { + var cycleDependencies = GetCycleDependencies(cycle, adjacency); + details = $" Cycle edges path: {string.Join(", ", cycleDependencies)}"; + } + throw new InvalidOperationException("Cyclic dependency detected." + details); + } + } + private unsafe void ReoderInsertionIndexes(UnsafeArray sortingBuffer) + { + for (int i = 0; i < _vertexInfos.Count; i++) + { + ref var info = ref _vertexInfos._items[i]; + if (info.isContained == false) { continue; } + info.leftBeforeIndex = info.isBefore ? int.MaxValue : 0; + } + + foreach (var dependency in _dependencies) + { + ref var fromInfo = ref GetVertexInfo(dependency.from); + if (fromInfo.isBefore) + { + ref var toInfo = ref GetVertexInfo(dependency.to); + fromInfo.leftBeforeIndex = Math.Min(toInfo.sortingIndex, fromInfo.leftBeforeIndex); + } + } + + for (int i = sortingBuffer.Length - 1; i >= 0; i--) + { + var id = sortingBuffer.ptr[i]; + ref var info = ref GetVertexInfo(id); + if (info.isBefore) + { + if (info.leftBeforeIndex < sortingBuffer.Length) + { + MoveElement(ref sortingBuffer, i, info.leftBeforeIndex - 1); + } + } + } + + for (int i = 0; i < sortingBuffer.Length; i++) + { + ref var info = ref GetVertexInfo(sortingBuffer.ptr[i]); + info.insertionIndex = i; + + } + } + private static unsafe void MoveElement(ref UnsafeArray array, int oldIndex, int newIndex) where T : unmanaged + { + var ptr = array.ptr; + if (oldIndex == newIndex) return; + + // Сохраняем элемент для перемещения + T item = ptr[oldIndex]; + + int elementSize = sizeof(T); + int copyLength = Math.Abs(newIndex - oldIndex); + + byte* source; + byte* destination; + long bytesToCopy = copyLength * elementSize; + + if (oldIndex < newIndex) + { + // Сдвиг вправо: копируем блок [oldIndex+1 ... newIndex] в [oldIndex ... newIndex-1] + source = (byte*)(ptr + oldIndex + 1); + destination = (byte*)(ptr + oldIndex); + } + else + { + // Сдвиг влево: копируем блок [newIndex ... oldIndex-1] в [newIndex+1 ... oldIndex] + source = (byte*)(ptr + newIndex); + destination = (byte*)(ptr + newIndex + 1); + } + + // Копируем память + Buffer.MemoryCopy(source: source, destination: destination, destinationSizeInBytes: bytesToCopy, sourceBytesToCopy: bytesToCopy); + + // Вставляем сохраненный элемент + ptr[newIndex] = item; + } + + public unsafe string[] Build() + { + const int BUFFER_THRESHOLD = 256; + if(_count <= BUFFER_THRESHOLD) + { + var ptr = stackalloc VertextID[_count]; + var buffer = UnsafeArray.Manual(ptr, _count); + TopoSorting(buffer); + ReoderInsertionIndexes(buffer); + TopoSorting(buffer); + return buffer.Select(id => GetVertexInfo(id).name).ToArray(); + } + else + { + var ptr = TempBuffer.Get(_count); + var buffer = UnsafeArray.Manual(ptr, _count); + TopoSorting(buffer); + ReoderInsertionIndexes(buffer); + TopoSorting(buffer); + return buffer.Select(id => GetVertexInfo(id).name).ToArray(); + } + } + #endregion + + #region FindCycles + private List FindCycle( + List<(VertextID To, int DependencyIndex)>[] adjacency, + VertextID[] nodes) + { + var visited = new Dictionary(); + var recursionStack = new Stack(); + + foreach (var node in nodes) + { + if (FindCycleDFS(node, adjacency, visited, recursionStack)) + { + return recursionStack.Reverse().ToList(); + } + } + return null; + } + private bool FindCycleDFS( + VertextID node, + List<(VertextID To, int DependencyIndex)>[] adjacency, + Dictionary visited, + Stack recursionStack) + { + if (!visited.TryGetValue(node, out bool isVisited)) + { + visited[node] = true; + recursionStack.Push(node); + + foreach (var (neighbor, _) in adjacency[(int)node]) + { + if (!visited.ContainsKey(neighbor) && FindCycleDFS(neighbor, adjacency, visited, recursionStack)) + { + return true; + } + else if (recursionStack.Contains(neighbor)) + { + recursionStack.Push(neighbor); + return true; + } + } + + recursionStack.Pop(); + return false; + } + return isVisited && recursionStack.Contains(node); + } + + private string[] GetCycleDependencies( + List cycle, + List<(VertextID To, int DependencyIndex)>[] adjacency) + { + var cycleEdges = new HashSet<(VertextID, VertextID)>(); + for (int i = 0; i < cycle.Count - 1; i++) + { + cycleEdges.Add((cycle[i], cycle[i + 1])); + } + + var dependencies = new List(); + foreach (var from in cycle) + { + foreach (var (to, depIndex) in adjacency[(int)from]) + { + if (cycleEdges.Contains((from, to)) && _dependencies.Count > depIndex) + { + var dep = _dependencies[depIndex]; + dependencies.Add($"{GetVertexInfo(dep.from).name}->{GetVertexInfo(dep.to).name}"); + } + } + } + return dependencies.Distinct().ToArray(); + } + #endregion + + #region Other + public bool Contains(string layer) { return GetVertexInfo(GetVertexID(layer)).isContained; } + + public Enumerator GetEnumerator() { return new Enumerator(this); } + IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } + IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } + public struct Enumerator : IEnumerator + { + private DependencyGraph _map; + private int _index; + public Enumerator(DependencyGraph map) + { + _map = map; + _index = -1; + } + public string Current + { + get { return _map._vertexInfos._items[_index].name; } + } + object IEnumerator.Current { get { return Current; } } + public bool MoveNext() + { + if (_index++ >= _map._vertexInfos.Count) { return false; } + ref var info = ref _map._vertexInfos._items[_index]; + if(info.isContained == false) + { + return MoveNext(); + } + else + { + return true; + } + } + public void Reset() { _index = -1; } + public void Dispose() { } + } + #endregion + } +} \ No newline at end of file diff --git a/src/Utils/EcsPipelineTemplate.cs b/src/Utils/EcsPipelineTemplate.cs index 59617df..3883ea7 100644 --- a/src/Utils/EcsPipelineTemplate.cs +++ b/src/Utils/EcsPipelineTemplate.cs @@ -21,7 +21,8 @@ namespace DCFApixels.DragonECS [DataMember] public Record[] records; void IEcsModule.Import(EcsPipeline.Builder b) { - b.Layers.MergeWith(layers); + throw new NotImplementedException(); + //b.Layers.MergeWith(layers); foreach (var s in records) { if (s.target == null) { continue; } diff --git a/src/Utils/LayersMap.cs b/src/Utils/LayersMap.cs deleted file mode 100644 index c4aa231..0000000 --- a/src/Utils/LayersMap.cs +++ /dev/null @@ -1,647 +0,0 @@ -using DCFApixels.DragonECS.Internal; -using System; -using System.Collections; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; - -namespace DCFApixels.DragonECS.Core -{ - public partial class LayersMap : IEnumerable - { - private readonly Dictionary _layerIds = new Dictionary(32); - private StructList _layerInfos = new StructList(32); - private LayerID GetLayerID(string layer) - { - if (_layerIds.TryGetValue(layer, out LayerID layerID) == false) - { - layerID = (LayerID)_layerInfos.Count; - _layerInfos.Add(default); - - _layerIds[layer] = layerID; - ref var layerInfo = ref GetLayerInfo(layerID); - layerInfo.name = layer; - } - return layerID; - } - private ref LayerInfo GetLayerInfo(LayerID layerID) - { - return ref _layerInfos._items[(int)layerID]; - } - [DebuggerDisplay("{name}")] - private struct LayerInfo - { - public string name; - public int insertionIndex; - public bool isLocked; - public bool isContained; - public bool isBefore; - //build - public int inDegree; - public bool hasAnyDependency; - public LayerInfo(string name) : this() - { - this.name = name; - } - } - - private readonly EcsPipeline.Builder _source; - private List<(LayerID From, LayerID To)> _dependencies = new List<(LayerID, LayerID)>(16); - private readonly LayerID _rootLayerID; - private readonly LayerID _basicLayerID; - private int _increment = 0; - private int _count; - - public IEnumerable<(string from, string to)> Deps - { - get - { - return _dependencies.Select(o => (GetLayerInfo(o.From).name, GetLayerInfo(o.To).name)); - } - } - - #region Properties - public int Count - { - get { return _count; } - } - #endregion - - #region Constructors - public LayersMap(EcsPipeline.Builder source = null) - { - GetLayerID(""); - _source = source; - _rootLayerID = LayerID.NULL; - _basicLayerID = LayerID.NULL; - } - public LayersMap(EcsPipeline.Builder source, string basicLayerName) - { - GetLayerID(""); - _source = source; - - Add(basicLayerName); - - _rootLayerID = LayerID.NULL; - _basicLayerID = GetLayerID(basicLayerName); - LockLayer(basicLayerName); - } - public LayersMap(EcsPipeline.Builder source, string preBeginlayer, string beginlayer, string basicLayer, string endLayer, string postEndLayer) - { - GetLayerID(""); - _source = source; - - Add(preBeginlayer); - //.Before(beginlayer); - Add(beginlayer) - //.Before(basicLayer) - .After(preBeginlayer); - Add(basicLayer) - //.Before(endLayer) - .After(beginlayer); - Add(endLayer) - //.Before(postEndLayer) - .After(basicLayer); - Add(postEndLayer) - .After(endLayer); - - _rootLayerID = GetLayerID(preBeginlayer); - _basicLayerID = GetLayerID(basicLayer); - LockLayer(preBeginlayer); - LockLayer(beginlayer); - LockLayer(basicLayer); - LockLayer(endLayer); - LockLayer(postEndLayer); - } - #endregion - - #region Methods - private void LockLayer(string layer) - { - GetLayerInfo(GetLayerID(layer)).isLocked = true; - } - private void Add_Internal(LayerID id) - { - ref var info = ref GetLayerInfo(id); - if (info.isLocked) { return; } - if (info.isContained == false) - { - _count++; - info.isContained = true; - } - info.insertionIndex = _increment++; - } - private void Remove_Internal(LayerID id) - { - ref var info = ref GetLayerInfo(id); - if (info.isLocked) { throw new Exception($"The {info.name} layer cannot be removed"); } - if (info.isContained) - { - _count--; - info.isContained = false; - } - info.insertionIndex = 0; - } - private void AddDependency_Internal(LayerID from, LayerID to, bool isBefore = false) - { - GetLayerInfo(from).hasAnyDependency = true; - GetLayerInfo(to).hasAnyDependency = true; - - if (isBefore) - { - //GetLayerInfo(from).insertionIndex = 1000 - (_increment++); - GetLayerInfo(from).isBefore = true; - //_dependencies.Insert(0, (from, to)); - } - else - { - //GetLayerInfo(from).insertionIndex = _increment++; - GetLayerInfo(from).isBefore = false; - //_dependencies.Add((from, to)); - } - //_dependencies.Insert(0, (from, to)); - _dependencies.Add((from, to)); - } - private void AddDependency_Internal(LayerID from, string to, bool isBefore = false) - { - AddDependency_Internal(from, GetLayerID(to), isBefore); - } - private void AddDependency_Internal(string from, LayerID to, bool isBefore = false) - { - AddDependency_Internal(GetLayerID(from), to, isBefore); - } - private void AddDependency_Internal(string from, string to, bool isBefore = false) - { - AddDependency_Internal(GetLayerID(from), GetLayerID(to), isBefore); - } - #endregion - - #region Add - public DependencyHandler Add(string layer) - { - var id = GetLayerID(layer); - Add_Internal(id); - return new DependencyHandler(this, (int)id); - } - public DependencyHandler Add(params string[] layers) - { - return Add(layersRange: layers); - } - public DependencyHandler Add(IEnumerable layersRange) - { - foreach (var layer in layersRange) - { - Add_Internal(GetLayerID(layer)); - } - return new DependencyHandler(this, layersRange); - } - #endregion - - #region Move - public DependencyHandler Move(string layer) - { - return new DependencyHandler(this, (int)GetLayerID(layer)); - } - public DependencyHandler Move(params string[] layers) - { - return new DependencyHandler(this, layers); - } - public DependencyHandler Move(IEnumerable layersRange) - { - return new DependencyHandler(this, layersRange); - } - #endregion - - #region Remove - public void Remove(string layer) - { - Remove_Internal(GetLayerID(layer)); - } - public void Remove(params string[] layers) - { - Remove(layersRange: layers); - } - public void Remove(IEnumerable layersRange) - { - foreach (var layer in layersRange) - { - Remove_Internal(GetLayerID(layer)); - } - } - #endregion - - #region MergeWith - public void MergeWith(LayersMap other) - { - foreach (var otherDependency in other._dependencies) - { - AddDependency_Internal(other.GetLayerInfo(otherDependency.From).name, other.GetLayerInfo(otherDependency.To).name); - } - for (int i = 0; i < other._layerInfos.Count; i++) - { - LayerID otherLayerID = (LayerID)i; - ref var otherLayerInfo = ref other.GetLayerInfo(otherLayerID); - Add(otherLayerInfo.name); - } - } - #endregion - - private enum LayerID : int { NULL = 0 } - public readonly ref struct DependencyHandler - { - private readonly LayersMap _source; - private readonly LayerID _id; - private readonly IEnumerable _layersRange; - - #region Properties - public EcsPipeline.Builder Back - { - get { return _source._source; } - } - #endregion - - #region Constructors - public DependencyHandler(LayersMap source, int id) - { - _source = source; - _id = (LayerID)id; - _layersRange = null; - } - public DependencyHandler(LayersMap source, IEnumerable layersRange) - { - _source = source; - _id = LayerID.NULL; - _layersRange = layersRange; - } - #endregion - - #region Before - public DependencyHandler Before(params string[] targets) - { - return Before(range: targets); - } - public DependencyHandler Before(IEnumerable range) - { - foreach (var target in range) - { - Before(target); - } - return this; - } - public DependencyHandler Before(string targetLayer) - { - if (_id != LayerID.NULL) - { - _source.AddDependency_Internal(_id, targetLayer, true); - } - if (_layersRange != null) - { - foreach (var layer in _layersRange) - { - _source.AddDependency_Internal(layer, targetLayer, true); - } - } - return this; - } - #endregion - - #region After - public DependencyHandler After(params string[] targets) - { - return After(range: targets); - } - public DependencyHandler After(IEnumerable range) - { - foreach (var target in range) - { - After(target); - } - return this; - } - public DependencyHandler After(string target) - { - if (_id != LayerID.NULL) - { - _source.AddDependency_Internal(target, _id); - } - if (_layersRange != null) - { - foreach (var id in _layersRange) - { - _source.AddDependency_Internal(target, id); - } - } - return this; - } - #endregion - } - - #region Build - public string[] Build() - { - LayerID[] nodes = new LayerID[_count]; - var adjacency = new List<(LayerID To, int DependencyIndex)>[_layerInfos.Count]; - - for (int i = 0, j = 0; i < _layerInfos.Count; i++) - { - LayerID layerID = (LayerID)i; - ref var info = ref GetLayerInfo(layerID); - adjacency[(int)layerID] = new List<(LayerID To, int DependencyIndex)>(); - _layerInfos._items[(int)layerID].inDegree = 0; - if (info.isContained) - { - nodes[j++] = layerID; - } - } - - for (int i = 0; i < _dependencies.Count; i++) - { - var (from, to) = _dependencies[i]; - ref var fromInfo = ref GetLayerInfo(from); - ref var toInfo = ref GetLayerInfo(to); - - if (fromInfo.isContained && toInfo.isContained) - { - adjacency[(int)from].Add((to, i)); - toInfo.inDegree += 1; - } - } - - //// добавление зависимостей для нод без зависимостей. - //if (_basicLayerID != LayerID.NULL) - //{ - // var basicLayerAdjacencyList = adjacency[(int)_basicLayerID]; - // int inserIndex = basicLayerAdjacencyList.Count; - // //for (int i = _layerInfos.Count - 1; i >= 0; i--) - // for (int i = 0; i < _layerInfos.Count; i++) - // { - // var id = (LayerID)i; - // ref var toInfo = ref _layerInfos._items[i]; - // if(toInfo.isContained && toInfo.hasAnyDependency == false) - // { - // //toInfo.insertionIndex = -toInfo.insertionIndex; - // basicLayerAdjacencyList.Insert(inserIndex, (id, toInfo.insertionIndex)); - // toInfo.inDegree += 1; - // } - // } - //} - - List zeroInDegree = new List(nodes.Length); - zeroInDegree.AddRange(nodes.Where(id => GetLayerInfo(id).inDegree == 0).OrderBy(id => GetLayerInfo(id).insertionIndex)); - - var result = new List(nodes.Length); - - while (zeroInDegree.Count > 0) - { - var current = zeroInDegree[0]; - zeroInDegree.RemoveAt(0); - - result.Add(GetLayerInfo(current).name); - - - var adjacencyList = adjacency[(int)current]; - //for (int i = adjacencyList.Count - 1; i >= 0; i--) - for (int i = 0; i < adjacencyList.Count; i++) - { - var (neighbor, _) = adjacencyList[i]; - ref var neighborInfo = ref GetLayerInfo(neighbor); - neighborInfo.inDegree--; - if (neighborInfo.inDegree == 0) - { - var neighborInsertionIndex = neighborInfo.insertionIndex; - int insertIndex = zeroInDegree.FindIndex(id => GetLayerInfo(id).insertionIndex < neighborInsertionIndex); - insertIndex = insertIndex < 0 ? 0 : insertIndex; - zeroInDegree.Insert(insertIndex, neighbor); - - //zeroInDegree.Add(neighbor); - //zeroInDegree = zeroInDegree.OrderBy(id => GetLayerInfo(id).insertionIndex).ToList(); - } - } - - //var adjacencyList = adjacency[(int)current]; - ////var adjacencyListSort = adjacencyList.OrderBy(o => GetLayerInfo(o.To).insertionIndex); - //var adjacencyListSort = adjacencyList; - //foreach (var item in adjacencyListSort) - //{ - // var (neighbor, _) = item; - // ref var neighborInfo = ref GetLayerInfo(neighbor); - // neighborInfo.inDegree--; - // if (neighborInfo.inDegree == 0) - // { - // //var neighborInsertionIndex = neighborInfo.insertionIndex; - // //int insertIndex = zeroInDegree.FindIndex(id => GetLayerInfo(id).insertionIndex > neighborInsertionIndex); - // //insertIndex = insertIndex < 0 ? 0 : insertIndex; - // // - // //zeroInDegree.Insert(insertIndex, neighbor); - // - // zeroInDegree.Add(neighbor); - // zeroInDegree = zeroInDegree.OrderBy(id => GetLayerInfo(id).insertionIndex).ToList(); - // } - //} - } - - if (result.Count != nodes.Length) - { - var cycle = FindCycle(adjacency, nodes); - string details = string.Empty; - if (cycle != null) - { - var cycleDependencies = GetCycleDependencies(cycle, adjacency); - details = $" Cycle edges path: {string.Join(", ", cycleDependencies)}"; - } - throw new InvalidOperationException("Cyclic dependency detected." + details); - } - - return result.ToArray(); - } - #endregion - - #region FindCycles - private List FindCycle( - List<(LayerID To, int DependencyIndex)>[] adjacency, - LayerID[] nodes) - { - var visited = new Dictionary(); - var recursionStack = new Stack(); - - foreach (var node in nodes) - { - if (FindCycleDFS(node, adjacency, visited, recursionStack)) - { - return recursionStack.Reverse().ToList(); - } - } - return null; - } - private bool FindCycleDFS( - LayerID node, - List<(LayerID To, int DependencyIndex)>[] adjacency, - Dictionary visited, - Stack recursionStack) - { - if (!visited.TryGetValue(node, out bool isVisited)) - { - visited[node] = true; - recursionStack.Push(node); - - foreach (var (neighbor, _) in adjacency[(int)node]) - { - if (!visited.ContainsKey(neighbor) && FindCycleDFS(neighbor, adjacency, visited, recursionStack)) - { - return true; - } - else if (recursionStack.Contains(neighbor)) - { - recursionStack.Push(neighbor); - return true; - } - } - - recursionStack.Pop(); - return false; - } - return isVisited && recursionStack.Contains(node); - } - - private string[] GetCycleDependencies( - List cycle, - List<(LayerID To, int DependencyIndex)>[] adjacency) - { - var cycleEdges = new HashSet<(LayerID, LayerID)>(); - for (int i = 0; i < cycle.Count - 1; i++) - { - cycleEdges.Add((cycle[i], cycle[i + 1])); - } - - var dependencies = new List(); - foreach (var from in cycle) - { - foreach (var (to, depIndex) in adjacency[(int)from]) - { - if (cycleEdges.Contains((from, to)) && _dependencies.Count > depIndex) - { - var dep = _dependencies[depIndex]; - dependencies.Add($"{GetLayerInfo(dep.From).name}->{GetLayerInfo(dep.To).name}"); - } - } - } - return dependencies.Distinct().ToArray(); - } - #endregion - - #region Other - public bool Contains(string layer) { return GetLayerInfo(GetLayerID(layer)).isContained; } - - public Enumerator GetEnumerator() { return new Enumerator(this); } - IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } - IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } - public struct Enumerator : IEnumerator - { - private LayersMap _map; - private int _index; - public Enumerator(LayersMap map) - { - _map = map; - _index = -1; - } - public string Current - { - get { return _map._layerInfos._items[_index].name; } - } - object IEnumerator.Current { get { return Current; } } - public bool MoveNext() - { - if (_index++ >= _map._layerInfos.Count) { return false; } - ref var info = ref _map._layerInfos._items[_index]; - if(info.isContained == false) - { - return MoveNext(); - } - else - { - return true; - } - } - public void Reset() { _index = -1; } - public void Dispose() { } - } - #endregion - - #region Obsolete - [Obsolete("Use " + nameof(LayersMap) + ".Add(layer).Before(targetLayer).Back;")] - public EcsPipeline.Builder Insert(string targetLayer, string newLayer) - { - Add(newLayer).Before(targetLayer); - return _source; - } - [Obsolete("Use " + nameof(LayersMap) + ".Add(layer).After(targetLayer).Back;")] - public EcsPipeline.Builder InsertAfter(string targetLayer, string newLayer) - { - Add(newLayer).After(targetLayer); - return _source; - } - [Obsolete("Use " + nameof(LayersMap) + ".Move(layer).Before(targetLayer).Back;")] - public EcsPipeline.Builder Move(string targetLayer, string newLayer) - { - Move(newLayer).Before(targetLayer); - return _source; - } - [Obsolete("Use " + nameof(LayersMap) + ".Move(layer).After(targetLayer).Back;")] - public EcsPipeline.Builder MoveAfter(string targetLayer, string newLayer) - { - Move(newLayer).After(targetLayer); - return _source; - } - [Obsolete("Use " + nameof(LayersMap) + ".Add(layers).Before(targetLayer).Back;")] - public EcsPipeline.Builder Insert(string targetLayer, params string[] newLayers) - { - Add(newLayers).Before(targetLayer); - return _source; - } - [Obsolete("Use " + nameof(LayersMap) + ".Add(layers).After(targetLayer).Back;")] - public EcsPipeline.Builder InsertAfter(string targetLayer, params string[] newLayers) - { - Add(newLayers).After(targetLayer); - return _source; - } - [Obsolete("Use " + nameof(LayersMap) + ".Move(layers).Before(targetLayer).Back;")] - public EcsPipeline.Builder Move(string targetLayer, params string[] movingLayers) - { - Move(movingLayers).Before(targetLayer); - return _source; - } - [Obsolete("Use " + nameof(LayersMap) + ".Move(layers).After(targetLayer).Back;")] - public EcsPipeline.Builder MoveAfter(string targetLayer, params string[] movingLayers) - { - Move(movingLayers).After(targetLayer); - return _source; - } - - [Obsolete] - public object this[int index] - { - get - { - int i = 0; - foreach (var item in this) - { - if (i == index) - { - return item; - } - i++; - } - return null; - } - } - [Obsolete("Use MergeWith(LayersMap)")] - public void MergeWith(IReadOnlyList other) - { - foreach (var layer in other) - { - Add(layer); - } - } - #endregion - } -} \ No newline at end of file From 853bc35d22a82d723ac7a03f8bff7c040191733e Mon Sep 17 00:00:00 2001 From: DCFApixels <99481254+DCFApixels@users.noreply.github.com> Date: Sat, 5 Apr 2025 21:30:57 +0800 Subject: [PATCH 6/9] update LayersMap stash --- src/Utils/DependencyGraph.cs | 135 +++++++++++++++-------------------- 1 file changed, 56 insertions(+), 79 deletions(-) diff --git a/src/Utils/DependencyGraph.cs b/src/Utils/DependencyGraph.cs index 05080da..4b108cf 100644 --- a/src/Utils/DependencyGraph.cs +++ b/src/Utils/DependencyGraph.cs @@ -4,23 +4,31 @@ using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; + namespace DCFApixels.DragonECS.Core { using VertextID = DependencyGraphVertextID; public enum DependencyGraphVertextID : short { NULL = 0 } - public interface IDependencyGraph + public interface IDependencyGraph : IReadOnlyCollection { - int Count { get; } VertextID AddVertex(T vertex, bool isLocked); bool ContainsVertex(T vertex); VertextID GetVertexID(T vertex); bool RemoveVertex(T vertex); - void AddBeforeDependency(VertextID vertexID, VertextID otherVertexID); - void AddAfterDependency(VertextID vertexID, VertextID otherVertexID); + void AddDependency(VertextID fromID, VertextID toID, bool moveToRight); T[] Sort(); } - public class LayersMap + public class LayersMap : IDependencyGraph { + #region IDependencyGraph + VertextID IDependencyGraph.AddVertex(string vertex, bool isLocked) { return _graph.AddVertex(vertex, isLocked); } + bool IDependencyGraph.ContainsVertex(string vertex) { return _graph.ContainsVertex(vertex); } + VertextID IDependencyGraph.GetVertexID(string vertex) { return _graph.GetVertexID(vertex); } + bool IDependencyGraph.RemoveVertex(string vertex) { return _graph.RemoveVertex(vertex); } + void IDependencyGraph.AddDependency(VertextID fromID, VertextID toID, bool moveToRight) { _graph.AddDependency(fromID, toID, moveToRight); } + string[] IDependencyGraph.Sort() { return _graph.Sort(); } + #endregion + private readonly IDependencyGraph _graph; private readonly EcsPipeline.Builder _pipelineBuilder; @@ -104,6 +112,7 @@ namespace DCFApixels.DragonECS.Core } #endregion + #region MoveHandler public struct MoveHandler { private readonly IDependencyGraph _graph; @@ -152,13 +161,13 @@ namespace DCFApixels.DragonECS.Core { if (_layerID != VertextID.NULL) { - _graph.AddBeforeDependency(_layerID, _graph.GetVertexID(targetLayer)); + _graph.AddDependency(_layerID, _graph.GetVertexID(targetLayer), true); } if (_layersRange != null) { foreach (var layer in _layersRange) { - _graph.AddBeforeDependency(_graph.GetVertexID(layer), _graph.GetVertexID(targetLayer)); + _graph.AddDependency(_graph.GetVertexID(layer), _graph.GetVertexID(targetLayer), true); } } return this; @@ -182,56 +191,28 @@ namespace DCFApixels.DragonECS.Core { if (_layerID != VertextID.NULL) { - _graph.AddAfterDependency(_graph.GetVertexID(targetLayer), _layerID); + _graph.AddDependency(_graph.GetVertexID(targetLayer), _layerID, false); } if (_layersRange != null) { foreach (var layer in _layersRange) { - _graph.AddBeforeDependency(_graph.GetVertexID(targetLayer), _graph.GetVertexID(layer)); + _graph.AddDependency(_graph.GetVertexID(targetLayer), _graph.GetVertexID(layer), false); } } return this; } #endregion } + #endregion #region Other - public bool Contains(string layer) { return _graph.ContainsVertex(layer); } - - //public Enumerator GetEnumerator() { return new Enumerator(this); } - //IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } - //IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } - //public struct Enumerator : IEnumerator - //{ - // private DependencyGraph _map; - // private int _index; - // public Enumerator(DependencyGraph map) - // { - // _map = map; - // _index = -1; - // } - // public string Current - // { - // get { return _map._vertexInfos._items[_index].name; } - // } - // object IEnumerator.Current { get { return Current; } } - // public bool MoveNext() - // { - // if (_index++ >= _map._vertexInfos.Count) { return false; } - // ref var info = ref _map._vertexInfos._items[_index]; - // if (info.isContained == false) - // { - // return MoveNext(); - // } - // else - // { - // return true; - // } - // } - // public void Reset() { _index = -1; } - // public void Dispose() { } - //} + public bool Contains(string layer) + { + return _graph.ContainsVertex(layer); + } + public IEnumerator GetEnumerator() { return _graph.GetEnumerator(); } + IEnumerator IEnumerable.GetEnumerator() { return _graph.GetEnumerator(); } #endregion #region Build @@ -242,49 +223,49 @@ namespace DCFApixels.DragonECS.Core #endregion #region Obsolete - [Obsolete("Use " + nameof(DependencyGraph) + ".Add(layer).Before(targetLayer).Back;")] + [Obsolete("Use " + nameof(LayersMap) + ".Add(layer).Before(targetLayer).Back;")] public EcsPipeline.Builder Insert(string targetLayer, string newLayer) { Add(newLayer).Before(targetLayer); return _pipelineBuilder; } - [Obsolete("Use " + nameof(DependencyGraph) + ".Add(layer).After(targetLayer).Back;")] + [Obsolete("Use " + nameof(LayersMap) + ".Add(layer).After(targetLayer).Back;")] public EcsPipeline.Builder InsertAfter(string targetLayer, string newLayer) { Add(newLayer).After(targetLayer); return _pipelineBuilder; } - [Obsolete("Use " + nameof(DependencyGraph) + ".Move(layer).Before(targetLayer).Back;")] + [Obsolete("Use " + nameof(LayersMap) + ".Move(layer).Before(targetLayer).Back;")] public EcsPipeline.Builder Move(string targetLayer, string newLayer) { Move(newLayer).Before(targetLayer); return _pipelineBuilder; } - [Obsolete("Use " + nameof(DependencyGraph) + ".Move(layer).After(targetLayer).Back;")] + [Obsolete("Use " + nameof(LayersMap) + ".Move(layer).After(targetLayer).Back;")] public EcsPipeline.Builder MoveAfter(string targetLayer, string newLayer) { Move(newLayer).After(targetLayer); return _pipelineBuilder; } - [Obsolete("Use " + nameof(DependencyGraph) + ".Add(layers).Before(targetLayer).Back;")] + [Obsolete("Use " + nameof(LayersMap) + ".Add(layers).Before(targetLayer).Back;")] public EcsPipeline.Builder Insert(string targetLayer, params string[] newLayers) { Add(newLayers).Before(targetLayer); return _pipelineBuilder; } - [Obsolete("Use " + nameof(DependencyGraph) + ".Add(layers).After(targetLayer).Back;")] + [Obsolete("Use " + nameof(LayersMap) + ".Add(layers).After(targetLayer).Back;")] public EcsPipeline.Builder InsertAfter(string targetLayer, params string[] newLayers) { Add(newLayers).After(targetLayer); return _pipelineBuilder; } - [Obsolete("Use " + nameof(DependencyGraph) + ".Move(layers).Before(targetLayer).Back;")] + [Obsolete("Use " + nameof(LayersMap) + ".Move(layers).Before(targetLayer).Back;")] public EcsPipeline.Builder Move(string targetLayer, params string[] movingLayers) { Move(movingLayers).Before(targetLayer); return _pipelineBuilder; } - [Obsolete("Use " + nameof(DependencyGraph) + ".Move(layers).After(targetLayer).Back;")] + [Obsolete("Use " + nameof(LayersMap) + ".Move(layers).After(targetLayer).Back;")] public EcsPipeline.Builder MoveAfter(string targetLayer, params string[] movingLayers) { Move(movingLayers).After(targetLayer); @@ -319,9 +300,7 @@ namespace DCFApixels.DragonECS.Core #endregion } - - - public partial class DependencyGraph : IEnumerable, IDependencyGraph + public unsafe partial class DependencyGraph : IEnumerable, IDependencyGraph { #region IDependencyGraph VertextID IDependencyGraph.AddVertex(string vertex, bool isLocked) @@ -347,18 +326,6 @@ namespace DCFApixels.DragonECS.Core var result = GetVertexID(vertex); return Remove_Internal(result); } - void IDependencyGraph.AddAfterDependency(VertextID fromoVertexID, VertextID toVertexID) - { - AddDependency_Internal(fromoVertexID, toVertexID, false); - } - void IDependencyGraph.AddBeforeDependency(VertextID fromoVertexID, VertextID toVertexID) - { - AddDependency_Internal(fromoVertexID, toVertexID, true); - } - string[] IDependencyGraph.Sort() - { - return Build(); - } #endregion private readonly Dictionary _vertexIDs = new Dictionary(32); @@ -462,15 +429,15 @@ namespace DCFApixels.DragonECS.Core info.insertionIndex = 0; return result; } - private void AddDependency_Internal(VertextID from, VertextID to, bool isBefore = false) + public void AddDependency(VertextID fromVertexID, VertextID toVertexID, bool moveToRight) { - ref var fromInfo = ref GetVertexInfo(from); - ref var toInfo = ref GetVertexInfo(to); + ref var fromInfo = ref GetVertexInfo(fromVertexID); + ref var toInfo = ref GetVertexInfo(toVertexID); fromInfo.hasAnyDependency = true; toInfo.hasAnyDependency = true; - if (isBefore) + if (moveToRight) { //GetLayerInfo(from).insertionIndex = 1000 - (_increment++); fromInfo.isBefore = true; @@ -483,11 +450,11 @@ namespace DCFApixels.DragonECS.Core //_dependencies.Add((from, to)); } //_dependencies.Insert(0, (from, to)); - _dependencies.Add((from, to)); + _dependencies.Add((fromVertexID, toVertexID)); } private void AddDependency_Internal(string from, string to, bool isBefore = false) { - AddDependency_Internal(GetVertexID(from), GetVertexID(to), isBefore); + AddDependency(GetVertexID(from), GetVertexID(to), isBefore); } #endregion @@ -508,7 +475,7 @@ namespace DCFApixels.DragonECS.Core #endregion #region Build - private unsafe void TopoSorting(UnsafeArray sortingBuffer) + private void TopoSorting(UnsafeArray sortingBuffer) { VertextID[] nodes = new VertextID[_count]; var adjacency = new List<(VertextID To, int DependencyIndex)>[_vertexInfos.Count]; @@ -604,7 +571,7 @@ namespace DCFApixels.DragonECS.Core throw new InvalidOperationException("Cyclic dependency detected." + details); } } - private unsafe void ReoderInsertionIndexes(UnsafeArray sortingBuffer) + private void ReoderInsertionIndexes(UnsafeArray sortingBuffer) { for (int i = 0; i < _vertexInfos.Count; i++) { @@ -643,7 +610,7 @@ namespace DCFApixels.DragonECS.Core } } - private static unsafe void MoveElement(ref UnsafeArray array, int oldIndex, int newIndex) where T : unmanaged + private static void MoveElement(ref UnsafeArray array, int oldIndex, int newIndex) where T : unmanaged { var ptr = array.ptr; if (oldIndex == newIndex) return; @@ -678,7 +645,7 @@ namespace DCFApixels.DragonECS.Core ptr[newIndex] = item; } - public unsafe string[] Build() + public string[] Sort() { const int BUFFER_THRESHOLD = 256; if(_count <= BUFFER_THRESHOLD) @@ -688,7 +655,7 @@ namespace DCFApixels.DragonECS.Core TopoSorting(buffer); ReoderInsertionIndexes(buffer); TopoSorting(buffer); - return buffer.Select(id => GetVertexInfo(id).name).ToArray(); + return ConvertIdsToStringsArray(buffer); } else { @@ -697,9 +664,19 @@ namespace DCFApixels.DragonECS.Core TopoSorting(buffer); ReoderInsertionIndexes(buffer); TopoSorting(buffer); - return buffer.Select(id => GetVertexInfo(id).name).ToArray(); + return ConvertIdsToStringsArray(buffer); } } + + private string[] ConvertIdsToStringsArray(UnsafeArray buffer) + { + string[] result = new string[buffer.Length]; + for (int i = 0; i < result.Length; i++) + { + result[i] = GetVertexInfo(buffer.ptr[i]).name; + } + return result; + } #endregion #region FindCycles From 3ed500ed6b3881ee24fdcd1bd95e6d540094e21a Mon Sep 17 00:00:00 2001 From: DCFApixels <99481254+DCFApixels@users.noreply.github.com> Date: Sat, 5 Apr 2025 23:03:07 +0800 Subject: [PATCH 7/9] update DependencyGraph --- src/EcsPipeline.Builder.cs | 3 +- src/Utils/DependencyGraph.cs | 479 +++++++++++++++++-------------- src/Utils/EcsPipelineTemplate.cs | 3 +- 3 files changed, 265 insertions(+), 220 deletions(-) diff --git a/src/EcsPipeline.Builder.cs b/src/EcsPipeline.Builder.cs index 0beb97d..73aa8d0 100644 --- a/src/EcsPipeline.Builder.cs +++ b/src/EcsPipeline.Builder.cs @@ -63,7 +63,8 @@ namespace DCFApixels.DragonECS Injector.AddNode(); Injector.AddNode(); - //Layers = new DependencyGraph(this, PRE_BEGIN_LAYER, BEGIN_LAYER, BASIC_LAYER, END_LAYER, POST_END_LAYER); + var graph = new DependencyGraph(BASIC_LAYER); + Layers = new LayersMap(graph, this, PRE_BEGIN_LAYER, BEGIN_LAYER, BASIC_LAYER, END_LAYER, POST_END_LAYER); } #endregion diff --git a/src/Utils/DependencyGraph.cs b/src/Utils/DependencyGraph.cs index 4b108cf..e600de5 100644 --- a/src/Utils/DependencyGraph.cs +++ b/src/Utils/DependencyGraph.cs @@ -7,25 +7,16 @@ using System.Linq; namespace DCFApixels.DragonECS.Core { - using VertextID = DependencyGraphVertextID; - public enum DependencyGraphVertextID : short { NULL = 0 } - public interface IDependencyGraph : IReadOnlyCollection - { - VertextID AddVertex(T vertex, bool isLocked); - bool ContainsVertex(T vertex); - VertextID GetVertexID(T vertex); - bool RemoveVertex(T vertex); - void AddDependency(VertextID fromID, VertextID toID, bool moveToRight); - T[] Sort(); - } + using VertexID = DependencyGraphVertextID; public class LayersMap : IDependencyGraph { #region IDependencyGraph - VertextID IDependencyGraph.AddVertex(string vertex, bool isLocked) { return _graph.AddVertex(vertex, isLocked); } + VertexID IDependencyGraph.AddVertex(string vertex, bool isLocked) { return _graph.AddVertex(vertex, isLocked); } bool IDependencyGraph.ContainsVertex(string vertex) { return _graph.ContainsVertex(vertex); } - VertextID IDependencyGraph.GetVertexID(string vertex) { return _graph.GetVertexID(vertex); } + VertexID IDependencyGraph.GetVertexID(string vertex) { return _graph.GetVertexID(vertex); } + string IDependencyGraph.GetVertexFromID(VertexID vertexID) { return _graph.GetVertexFromID(vertexID); } bool IDependencyGraph.RemoveVertex(string vertex) { return _graph.RemoveVertex(vertex); } - void IDependencyGraph.AddDependency(VertextID fromID, VertextID toID, bool moveToRight) { _graph.AddDependency(fromID, toID, moveToRight); } + void IDependencyGraph.AddDependency(VertexID fromID, VertexID toID, bool moveToRight) { _graph.AddDependency(fromID, toID, moveToRight); } string[] IDependencyGraph.Sort() { return _graph.Sort(); } #endregion @@ -41,6 +32,10 @@ namespace DCFApixels.DragonECS.Core { get { return _graph.Count; } } + public ReadonlyDependenciesCollection Dependencies + { + get { return _graph.Dependencies; } + } #endregion #region Constructors @@ -61,7 +56,7 @@ namespace DCFApixels.DragonECS.Core graph.AddVertex(postEndLayer, true); Move(preBeginlayer); - //.Before(beginlayer); + //.Before(beginlayer); Move(beginlayer) //.Before(basicLayer) .After(preBeginlayer); @@ -79,7 +74,7 @@ namespace DCFApixels.DragonECS.Core #region Add public MoveHandler Add(string layer) { - VertextID id = _graph.AddVertex(layer, false); + VertexID id = _graph.AddVertex(layer, false); return new MoveHandler(_graph, _pipelineBuilder, id); } public MoveHandler Add(params string[] layers) @@ -99,7 +94,7 @@ namespace DCFApixels.DragonECS.Core #region Move public MoveHandler Move(string layer) { - VertextID id = _graph.GetVertexID(layer); + VertexID id = _graph.GetVertexID(layer); return new MoveHandler(_graph, _pipelineBuilder, id); } public MoveHandler Move(params string[] layers) @@ -117,7 +112,7 @@ namespace DCFApixels.DragonECS.Core { private readonly IDependencyGraph _graph; private readonly EcsPipeline.Builder _pipelineBuilder; - private readonly VertextID _layerID; + private readonly VertexID _layerID; private readonly IEnumerable _layersRange; #region Properties @@ -128,7 +123,7 @@ namespace DCFApixels.DragonECS.Core #endregion #region Constructors - public MoveHandler(IDependencyGraph graph, EcsPipeline.Builder pipelineBuilder, VertextID id) + public MoveHandler(IDependencyGraph graph, EcsPipeline.Builder pipelineBuilder, VertexID id) { _graph = graph; _pipelineBuilder = pipelineBuilder; @@ -139,7 +134,7 @@ namespace DCFApixels.DragonECS.Core { _graph = graph; _pipelineBuilder = pipelineBuilder; - _layerID = VertextID.NULL; + _layerID = VertexID.NULL; _layersRange = layersRange; } #endregion @@ -159,7 +154,7 @@ namespace DCFApixels.DragonECS.Core } public MoveHandler Before(string targetLayer) { - if (_layerID != VertextID.NULL) + if (_layerID != VertexID.NULL) { _graph.AddDependency(_layerID, _graph.GetVertexID(targetLayer), true); } @@ -189,7 +184,7 @@ namespace DCFApixels.DragonECS.Core } public MoveHandler After(string targetLayer) { - if (_layerID != VertextID.NULL) + if (_layerID != VertexID.NULL) { _graph.AddDependency(_graph.GetVertexID(targetLayer), _layerID, false); } @@ -206,10 +201,17 @@ namespace DCFApixels.DragonECS.Core } #endregion + #region MergeWith + public void MergeWith(IDependencyGraph other) + { + _graph.MergeWith(other); + } + #endregion; + #region Other - public bool Contains(string layer) - { - return _graph.ContainsVertex(layer); + public bool Contains(string layer) + { + return _graph.ContainsVertex(layer); } public IEnumerator GetEnumerator() { return _graph.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return _graph.GetEnumerator(); } @@ -300,97 +302,91 @@ namespace DCFApixels.DragonECS.Core #endregion } - public unsafe partial class DependencyGraph : IEnumerable, IDependencyGraph + public enum DependencyGraphVertextID : short { NULL = 0 } + public interface IDependencyGraph : IReadOnlyCollection { - #region IDependencyGraph - VertextID IDependencyGraph.AddVertex(string vertex, bool isLocked) + ReadonlyDependenciesCollection Dependencies { get; } + VertexID AddVertex(T vertex, bool isLocked); + bool ContainsVertex(T vertex); + VertexID GetVertexID(T vertex); + T GetVertexFromID(VertexID vertexID); + bool RemoveVertex(T vertex); + void AddDependency(VertexID fromID, VertexID toID, bool moveToRight); + void MergeWith(IDependencyGraph other); + T[] Sort(); + } + public static class DependencyGraphExtensions + { + public static void AddDependency(this IDependencyGraph self, T from, T to, bool moveToRight) { - var result = GetVertexID(vertex); - Add_Internal(result); - if (isLocked) + self.AddDependency(self.GetVertexID(from), self.GetVertexID(to), moveToRight); + } + } + public struct ReadonlyDependenciesCollection : IReadOnlyCollection<(T from, T to)> + { + private IDependencyGraph _graph; + private IReadOnlyCollection<(VertexID from, VertexID to)> _source; + public int Count + { + get { return _source.Count; } + } + public ReadonlyDependenciesCollection(IDependencyGraph graph, IReadOnlyCollection<(VertexID from, VertexID to)> source) + { + _graph = graph; + _source = source; + } + public Enumerator GetEnumerator() { return new Enumerator(_graph, _source.GetEnumerator()); } + IEnumerator<(T from, T to)> IEnumerable<(T from, T to)>.GetEnumerator() { return GetEnumerator(); } + IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } + public struct Enumerator : IEnumerator<(T from, T to)> + { + private IDependencyGraph _graph; + private IEnumerator<(VertexID from, VertexID to)> _source; + public Enumerator(IDependencyGraph graph, IEnumerator<(VertexID from, VertexID to)> source) { - LockVertex(vertex); + _graph = graph; + _source = source; } - return result; + public (T from, T to) Current + { + get + { + var (from, to) = _source.Current; + return (_graph.GetVertexFromID(from), _graph.GetVertexFromID(to)); + } + } + object IEnumerator.Current { get { return Current; } } + public bool MoveNext() { return _source.MoveNext(); } + public void Reset() { _source.Reset(); } + public void Dispose() { } } - bool IDependencyGraph.ContainsVertex(string vertex) - { - return GetVertexInfo(GetVertexID(vertex)).isContained; - } - VertextID IDependencyGraph.GetVertexID(string vertex) - { - return GetVertexID(vertex); - } - bool IDependencyGraph.RemoveVertex(string vertex) - { - var result = GetVertexID(vertex); - return Remove_Internal(result); - } - #endregion - - private readonly Dictionary _vertexIDs = new Dictionary(32); + } + public unsafe partial class DependencyGraph : IDependencyGraph + { + private readonly Dictionary _vertexIDs = new Dictionary(32); private StructList _vertexInfos = new StructList(32); - private VertextID GetVertexID(string vertext) - { - if (_vertexIDs.TryGetValue(vertext, out VertextID layerID) == false) - { - layerID = (VertextID)_vertexInfos.Count; - _vertexInfos.Add(default); - _vertexIDs[vertext] = layerID; - ref var layerInfo = ref GetVertexInfo(layerID); - layerInfo.name = vertext; - } - return layerID; - } - private ref VertexInfo GetVertexInfo(VertextID vertexID) - { - return ref _vertexInfos._items[(int)vertexID]; - } - [DebuggerDisplay("{name}")] - private struct VertexInfo - { - public string name; - public int insertionIndex; - public bool isLocked; - public bool isContained; - public bool isBefore; - //build - public bool hasAnyDependency; - public int inDegree; - public int sortingIndex; - public int leftBeforeIndex; - public VertexInfo(string name) : this() - { - this.name = name; - } - } - - private List<(VertextID from, VertextID to)> _dependencies = new List<(VertextID, VertextID)>(16); - private readonly VertextID _basicVertexID; + private List<(VertexID from, VertexID to)> _dependencies = new List<(VertexID, VertexID)>(16); + private readonly VertexID _basicVertexID; private int _increment = 0; private int _count; - public IEnumerable<(string from, string to)> Deps - { - get - { - return _dependencies.Select(o => (GetVertexInfo(o.from).name, GetVertexInfo(o.to).name)); - } - } - #region Properties public int Count { get { return _count; } } + public ReadonlyDependenciesCollection Dependencies + { + get { return new ReadonlyDependenciesCollection(this, _dependencies); } + } #endregion #region Constructors public DependencyGraph() { GetVertexID(""); - _basicVertexID = VertextID.NULL; + _basicVertexID = VertexID.NULL; } public DependencyGraph(string basicVertexName) { @@ -401,25 +397,73 @@ namespace DCFApixels.DragonECS.Core #endregion #region Methods - private void LockVertex(string veretex) + public VertexID GetVertexID(string vertext) { - GetVertexInfo(GetVertexID(veretex)).isLocked = true; + if (_vertexIDs.TryGetValue(vertext, out VertexID layerID) == false) + { + layerID = (VertexID)_vertexInfos.Count; + _vertexInfos.Add(default); + + _vertexIDs[vertext] = layerID; + ref var layerInfo = ref GetVertexInfo(layerID); + layerInfo.value = vertext; + } + return layerID; } - private void Add_Internal(VertextID id) + public string GetVertexFromID(VertexID vertexID) + { + return GetVertexInfo(vertexID).value; + } + private ref VertexInfo GetVertexInfo(VertexID vertexID) + { + return ref _vertexInfos._items[(int)vertexID]; + } + private ref VertexInfo GetVertexInfo(int vertexID) + { + return ref _vertexInfos._items[(int)vertexID]; + } + private int GetVertexInfosCount() + { + return _vertexInfos.Count; + } + public VertexID AddVertex(string vertex, bool isLocked) + { + var result = GetVertexID(vertex); + AddVertexByID(result); + if (isLocked) + { + LockVertex(result); + } + return result; + } + private void LockVertex(string vertex) + { + LockVertex(GetVertexID(vertex)); + } + private void LockVertex(VertexID vertexID) + { + GetVertexInfo(vertexID).isLocked = true; + } + private void AddVertexByID(VertexID id) { ref var info = ref GetVertexInfo(id); if (info.isContained == false || info.isLocked == false) { _count++; info.isContained = true; - info.insertionIndex = _increment++; } + info.insertionIndex = _increment++; } - private bool Remove_Internal(VertextID id) + public bool RemoveVertex(string vertex) + { + var result = GetVertexID(vertex); + return RemoveVertexByID(result); + } + private bool RemoveVertexByID(VertexID id) { ref var info = ref GetVertexInfo(id); bool result = false; - if (info.isLocked) { throw new Exception($"The {info.name} vertex cannot be removed"); } + if (info.isLocked) { throw new Exception($"The {info.value} vertex cannot be removed"); } if (info.isContained) { _count--; @@ -429,63 +473,77 @@ namespace DCFApixels.DragonECS.Core info.insertionIndex = 0; return result; } - public void AddDependency(VertextID fromVertexID, VertextID toVertexID, bool moveToRight) + public void AddDependency(VertexID fromVertexID, VertexID toVertexID, bool moveToRight) { - ref var fromInfo = ref GetVertexInfo(fromVertexID); ref var toInfo = ref GetVertexInfo(toVertexID); fromInfo.hasAnyDependency = true; toInfo.hasAnyDependency = true; - - if (moveToRight) - { - //GetLayerInfo(from).insertionIndex = 1000 - (_increment++); - fromInfo.isBefore = true; - //_dependencies.Insert(0, (from, to)); - } - else - { - //GetLayerInfo(from).insertionIndex = _increment++; - fromInfo.isBefore = false; - //_dependencies.Add((from, to)); - } - //_dependencies.Insert(0, (from, to)); + fromInfo.moveToRight = moveToRight; _dependencies.Add((fromVertexID, toVertexID)); } - private void AddDependency_Internal(string from, string to, bool isBefore = false) - { - AddDependency(GetVertexID(from), GetVertexID(to), isBefore); - } #endregion #region MergeWith - public void MergeWith(DependencyGraph other) + public void MergeWith(IDependencyGraph other) { - foreach (var otherDependency in other._dependencies) + if(other is DependencyGraph graph) { - AddDependency_Internal(other.GetVertexInfo(otherDependency.from).name, other.GetVertexInfo(otherDependency.to).name); + foreach (var otherDependency in graph._dependencies) + { + this.AddDependency(graph.GetVertexFromID(otherDependency.from), graph.GetVertexFromID(otherDependency.to), false); + } + for (int i = 0; i < graph.GetVertexInfosCount(); i++) + { + ref var otherLayerInfo = ref graph.GetVertexInfo(i); + AddVertexByID(GetVertexID(graph.GetVertexFromID((VertexID)i))); + } } - for (int i = 0; i < other._vertexInfos.Count; i++) + foreach (var otherDependency in other.Dependencies) { - VertextID otherLayerID = (VertextID)i; - ref var otherLayerInfo = ref other.GetVertexInfo(otherLayerID); - Add_Internal(GetVertexID(otherLayerInfo.name)); + this.AddDependency(otherDependency.from, otherDependency.to, false); + } + foreach (var vertex in other) + { + AddVertex(vertex, false); } } #endregion - #region Build - private void TopoSorting(UnsafeArray sortingBuffer) + #region Sort + public string[] Sort() { - VertextID[] nodes = new VertextID[_count]; - var adjacency = new List<(VertextID To, int DependencyIndex)>[_vertexInfos.Count]; - - for (int i = 0, j = 0; i < _vertexInfos.Count; i++) + const int BUFFER_THRESHOLD = 256; + if (_count <= BUFFER_THRESHOLD) { - VertextID layerID = (VertextID)i; + var ptr = stackalloc VertexID[_count]; + var buffer = UnsafeArray.Manual(ptr, _count); + TopoSorting(buffer); + ReoderInsertionIndexes(buffer); + TopoSorting(buffer); + return ConvertIdsToStringsArray(buffer); + } + else + { + var ptr = TempBuffer.Get(_count); + var buffer = UnsafeArray.Manual(ptr, _count); + TopoSorting(buffer); + ReoderInsertionIndexes(buffer); + TopoSorting(buffer); + return ConvertIdsToStringsArray(buffer); + } + } + private void TopoSorting(UnsafeArray sortingBuffer) + { + VertexID[] nodes = new VertexID[_count]; + var adjacency = new List<(VertexID To, int DependencyIndex)>[GetVertexInfosCount()]; + + for (int i = 0, j = 0; i < GetVertexInfosCount(); i++) + { + VertexID layerID = (VertexID)i; ref var info = ref GetVertexInfo(layerID); - adjacency[(int)layerID] = new List<(VertextID To, int DependencyIndex)>(); - _vertexInfos._items[(int)layerID].inDegree = 0; + adjacency[(int)layerID] = new List<(VertexID To, int DependencyIndex)>(); + GetVertexInfo(layerID).inDegree = 0; if (info.isContained) { nodes[j++] = layerID; @@ -505,29 +563,26 @@ namespace DCFApixels.DragonECS.Core } } - //// добавление зависимостей для нод без зависимостей. - //if (_basicLayerID != LayerID.NULL) - //{ - // var basicLayerAdjacencyList = adjacency[(int)_basicLayerID]; - // int inserIndex = basicLayerAdjacencyList.Count; - // //for (int i = _layerInfos.Count - 1; i >= 0; i--) - // for (int i = 0; i < _layerInfos.Count; i++) - // { - // var id = (LayerID)i; - // ref var toInfo = ref _layerInfos._items[i]; - // if(toInfo.isContained && toInfo.hasAnyDependency == false) - // { - // //toInfo.insertionIndex = -toInfo.insertionIndex; - // basicLayerAdjacencyList.Insert(inserIndex, (id, toInfo.insertionIndex)); - // toInfo.inDegree += 1; - // } - // } - //} + // добавление зависимостей для нод без зависимостей. + if (_basicVertexID != VertexID.NULL) + { + var basicLayerAdjacencyList = adjacency[(int)_basicVertexID]; + int inserIndex = basicLayerAdjacencyList.Count; + for (int i = 0; i < GetVertexInfosCount(); i++) + { + var toID = (VertexID)i; + ref var toInfo = ref GetVertexInfo(i); + if(toInfo.isContained && toInfo.hasAnyDependency == false) + { + basicLayerAdjacencyList.Insert(inserIndex, (toID, toInfo.insertionIndex)); + toInfo.inDegree += 1; + } + } + } - List zeroInDegree = new List(nodes.Length); + List zeroInDegree = new List(nodes.Length); zeroInDegree.AddRange(nodes.Where(id => GetVertexInfo(id).inDegree == 0).OrderBy(id => GetVertexInfo(id).insertionIndex)); - //List result = new List(nodes.Length); int resultCount = 0; while (zeroInDegree.Count > 0) @@ -535,12 +590,10 @@ namespace DCFApixels.DragonECS.Core var current = zeroInDegree[0]; zeroInDegree.RemoveAt(0); - //result.Add(GetVertexInfo(current).name); GetVertexInfo(current).sortingIndex = resultCount; sortingBuffer.ptr[resultCount++] = current; var adjacencyList = adjacency[(int)current]; - //for (int i = adjacencyList.Count - 1; i >= 0; i--) for (int i = 0; i < adjacencyList.Count; i++) { var (neighbor, _) = adjacencyList[i]; @@ -552,9 +605,6 @@ namespace DCFApixels.DragonECS.Core int insertIndex = zeroInDegree.FindIndex(id => GetVertexInfo(id).insertionIndex < neighborInsertionIndex); insertIndex = insertIndex < 0 ? 0 : insertIndex; zeroInDegree.Insert(insertIndex, neighbor); - - //zeroInDegree.Add(neighbor); - //zeroInDegree = zeroInDegree.OrderBy(id => GetLayerInfo(id).insertionIndex).ToList(); } } } @@ -571,19 +621,19 @@ namespace DCFApixels.DragonECS.Core throw new InvalidOperationException("Cyclic dependency detected." + details); } } - private void ReoderInsertionIndexes(UnsafeArray sortingBuffer) + private void ReoderInsertionIndexes(UnsafeArray sortingBuffer) { - for (int i = 0; i < _vertexInfos.Count; i++) + for (int i = 0; i < GetVertexInfosCount(); i++) { - ref var info = ref _vertexInfos._items[i]; + ref var info = ref GetVertexInfo(i); if (info.isContained == false) { continue; } - info.leftBeforeIndex = info.isBefore ? int.MaxValue : 0; + info.leftBeforeIndex = info.moveToRight ? int.MaxValue : 0; } foreach (var dependency in _dependencies) { ref var fromInfo = ref GetVertexInfo(dependency.from); - if (fromInfo.isBefore) + if (fromInfo.moveToRight) { ref var toInfo = ref GetVertexInfo(dependency.to); fromInfo.leftBeforeIndex = Math.Min(toInfo.sortingIndex, fromInfo.leftBeforeIndex); @@ -594,7 +644,7 @@ namespace DCFApixels.DragonECS.Core { var id = sortingBuffer.ptr[i]; ref var info = ref GetVertexInfo(id); - if (info.isBefore) + if (info.moveToRight) { if (info.leftBeforeIndex < sortingBuffer.Length) { @@ -612,10 +662,9 @@ namespace DCFApixels.DragonECS.Core } private static void MoveElement(ref UnsafeArray array, int oldIndex, int newIndex) where T : unmanaged { - var ptr = array.ptr; if (oldIndex == newIndex) return; - // Сохраняем элемент для перемещения + var ptr = array.ptr; T item = ptr[oldIndex]; int elementSize = sizeof(T); @@ -637,55 +686,28 @@ namespace DCFApixels.DragonECS.Core source = (byte*)(ptr + newIndex); destination = (byte*)(ptr + newIndex + 1); } - - // Копируем память Buffer.MemoryCopy(source: source, destination: destination, destinationSizeInBytes: bytesToCopy, sourceBytesToCopy: bytesToCopy); - // Вставляем сохраненный элемент ptr[newIndex] = item; } - - public string[] Sort() - { - const int BUFFER_THRESHOLD = 256; - if(_count <= BUFFER_THRESHOLD) - { - var ptr = stackalloc VertextID[_count]; - var buffer = UnsafeArray.Manual(ptr, _count); - TopoSorting(buffer); - ReoderInsertionIndexes(buffer); - TopoSorting(buffer); - return ConvertIdsToStringsArray(buffer); - } - else - { - var ptr = TempBuffer.Get(_count); - var buffer = UnsafeArray.Manual(ptr, _count); - TopoSorting(buffer); - ReoderInsertionIndexes(buffer); - TopoSorting(buffer); - return ConvertIdsToStringsArray(buffer); - } - } - - private string[] ConvertIdsToStringsArray(UnsafeArray buffer) + private string[] ConvertIdsToStringsArray(UnsafeArray buffer) { string[] result = new string[buffer.Length]; for (int i = 0; i < result.Length; i++) { - result[i] = GetVertexInfo(buffer.ptr[i]).name; + result[i] = GetVertexInfo(buffer.ptr[i]).value; } return result; } #endregion #region FindCycles - private List FindCycle( - List<(VertextID To, int DependencyIndex)>[] adjacency, - VertextID[] nodes) + private List FindCycle( + List<(VertexID To, int DependencyIndex)>[] adjacency, + VertexID[] nodes) { - var visited = new Dictionary(); - var recursionStack = new Stack(); + var visited = new Dictionary(); + var recursionStack = new Stack(); foreach (var node in nodes) { @@ -697,10 +719,10 @@ namespace DCFApixels.DragonECS.Core return null; } private bool FindCycleDFS( - VertextID node, - List<(VertextID To, int DependencyIndex)>[] adjacency, - Dictionary visited, - Stack recursionStack) + VertexID node, + List<(VertexID To, int DependencyIndex)>[] adjacency, + Dictionary visited, + Stack recursionStack) { if (!visited.TryGetValue(node, out bool isVisited)) { @@ -727,10 +749,10 @@ namespace DCFApixels.DragonECS.Core } private string[] GetCycleDependencies( - List cycle, - List<(VertextID To, int DependencyIndex)>[] adjacency) + List cycle, + List<(VertexID To, int DependencyIndex)>[] adjacency) { - var cycleEdges = new HashSet<(VertextID, VertextID)>(); + var cycleEdges = new HashSet<(VertexID, VertexID)>(); for (int i = 0; i < cycle.Count - 1; i++) { cycleEdges.Add((cycle[i], cycle[i + 1])); @@ -744,7 +766,7 @@ namespace DCFApixels.DragonECS.Core if (cycleEdges.Contains((from, to)) && _dependencies.Count > depIndex) { var dep = _dependencies[depIndex]; - dependencies.Add($"{GetVertexInfo(dep.from).name}->{GetVertexInfo(dep.to).name}"); + dependencies.Add($"{GetVertexInfo(dep.from).value}->{GetVertexInfo(dep.to).value}"); } } } @@ -753,8 +775,10 @@ namespace DCFApixels.DragonECS.Core #endregion #region Other - public bool Contains(string layer) { return GetVertexInfo(GetVertexID(layer)).isContained; } - + public bool ContainsVertex(string vertex) + { + return GetVertexInfo(GetVertexID(vertex)).isContained; + } public Enumerator GetEnumerator() { return new Enumerator(this); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } @@ -769,13 +793,13 @@ namespace DCFApixels.DragonECS.Core } public string Current { - get { return _map._vertexInfos._items[_index].name; } + get { return _map.GetVertexInfo(_index).value; } } object IEnumerator.Current { get { return Current; } } public bool MoveNext() { - if (_index++ >= _map._vertexInfos.Count) { return false; } - ref var info = ref _map._vertexInfos._items[_index]; + if (_index++ >= _map.GetVertexInfosCount()) { return false; } + ref var info = ref _map.GetVertexInfo(_index); if(info.isContained == false) { return MoveNext(); @@ -789,5 +813,26 @@ namespace DCFApixels.DragonECS.Core public void Dispose() { } } #endregion + + #region VertexInfo + [DebuggerDisplay("{value}")] + private struct VertexInfo + { + public string value; + public int insertionIndex; + public bool isLocked; + public bool isContained; + public bool moveToRight; + //build + public bool hasAnyDependency; + public int inDegree; + public int sortingIndex; + public int leftBeforeIndex; + public VertexInfo(string name) : this() + { + this.value = name; + } + } + #endregion } } \ No newline at end of file diff --git a/src/Utils/EcsPipelineTemplate.cs b/src/Utils/EcsPipelineTemplate.cs index 3883ea7..59617df 100644 --- a/src/Utils/EcsPipelineTemplate.cs +++ b/src/Utils/EcsPipelineTemplate.cs @@ -21,8 +21,7 @@ namespace DCFApixels.DragonECS [DataMember] public Record[] records; void IEcsModule.Import(EcsPipeline.Builder b) { - throw new NotImplementedException(); - //b.Layers.MergeWith(layers); + b.Layers.MergeWith(layers); foreach (var s in records) { if (s.target == null) { continue; } From c787efe29fe14d613c45620fb39ae5d3180d1382 Mon Sep 17 00:00:00 2001 From: DCFApixels <99481254+DCFApixels@users.noreply.github.com> Date: Sat, 5 Apr 2025 23:28:53 +0800 Subject: [PATCH 8/9] update DependencyGraph --- src/EcsPipeline.Builder.cs | 2 +- src/Utils/DependencyGraph.cs | 132 +++++++++++++++++++++-------------- 2 files changed, 80 insertions(+), 54 deletions(-) diff --git a/src/EcsPipeline.Builder.cs b/src/EcsPipeline.Builder.cs index 73aa8d0..8a6872e 100644 --- a/src/EcsPipeline.Builder.cs +++ b/src/EcsPipeline.Builder.cs @@ -63,7 +63,7 @@ namespace DCFApixels.DragonECS Injector.AddNode(); Injector.AddNode(); - var graph = new DependencyGraph(BASIC_LAYER); + var graph = new DependencyGraph(BASIC_LAYER); Layers = new LayersMap(graph, this, PRE_BEGIN_LAYER, BEGIN_LAYER, BASIC_LAYER, END_LAYER, POST_END_LAYER); } #endregion diff --git a/src/Utils/DependencyGraph.cs b/src/Utils/DependencyGraph.cs index e600de5..cce2f7d 100644 --- a/src/Utils/DependencyGraph.cs +++ b/src/Utils/DependencyGraph.cs @@ -22,6 +22,7 @@ namespace DCFApixels.DragonECS.Core private readonly IDependencyGraph _graph; private readonly EcsPipeline.Builder _pipelineBuilder; + private readonly string _preBeginLayer; #region Properties public EcsPipeline.Builder Back @@ -206,6 +207,37 @@ namespace DCFApixels.DragonECS.Core { _graph.MergeWith(other); } + //[Obsolete("Use MergeWith(LayersMap)")] + public void MergeWith(IReadOnlyList other) + { + var enumerator = other.GetEnumerator(); + string prev = null; + if (_preBeginLayer != null) + { + while (enumerator.MoveNext()) + { + var layer = enumerator.Current; + if (layer == _preBeginLayer) { break; } + + Add(layer); + if (prev != null) + { + Move(prev).Before(layer); + } + prev = layer; + } + } + while (enumerator.MoveNext()) + { + var layer = enumerator.Current; + Add(layer); + if (prev != null) + { + Move(layer).After(prev); + } + prev = layer; + } + } #endregion; #region Other @@ -279,31 +311,23 @@ namespace DCFApixels.DragonECS.Core { get { - //int i = 0; - //foreach (var item in this) - //{ - // if (i == index) - // { - // return item; - // } - // i++; - //} + int i = 0; + foreach (var item in this) + { + if (i == index) + { + return item; + } + i++; + } return null; } } - [Obsolete("Use MergeWith(LayersMap)")] - public void MergeWith(IReadOnlyList other) - { - foreach (var layer in other) - { - Add(layer); - } - } #endregion } public enum DependencyGraphVertextID : short { NULL = 0 } - public interface IDependencyGraph : IReadOnlyCollection + public interface IDependencyGraph : IReadOnlyCollection { ReadonlyDependenciesCollection Dependencies { get; } VertexID AddVertex(T vertex, bool isLocked); @@ -361,14 +385,14 @@ namespace DCFApixels.DragonECS.Core public void Dispose() { } } } - public unsafe partial class DependencyGraph : IDependencyGraph + public unsafe partial class DependencyGraph : IDependencyGraph { - private readonly Dictionary _vertexIDs = new Dictionary(32); + private readonly Dictionary _vertexIDs = new Dictionary(32); private StructList _vertexInfos = new StructList(32); private List<(VertexID from, VertexID to)> _dependencies = new List<(VertexID, VertexID)>(16); private readonly VertexID _basicVertexID; - private int _increment = 0; + private int _increment = 1; private int _count; #region Properties @@ -376,28 +400,30 @@ namespace DCFApixels.DragonECS.Core { get { return _count; } } - public ReadonlyDependenciesCollection Dependencies + public ReadonlyDependenciesCollection Dependencies { - get { return new ReadonlyDependenciesCollection(this, _dependencies); } + get { return new ReadonlyDependenciesCollection(this, _dependencies); } } #endregion #region Constructors public DependencyGraph() { - GetVertexID(""); + //GetVertexID(""); + _vertexInfos.Add(default); _basicVertexID = VertexID.NULL; } - public DependencyGraph(string basicVertexName) + public DependencyGraph(T basicVertexName) { - GetVertexID(""); + //GetVertexID(""); + _vertexInfos.Add(default); _basicVertexID = GetVertexID(basicVertexName); LockVertex(basicVertexName); } #endregion #region Methods - public VertexID GetVertexID(string vertext) + public VertexID GetVertexID(T vertext) { if (_vertexIDs.TryGetValue(vertext, out VertexID layerID) == false) { @@ -410,7 +436,7 @@ namespace DCFApixels.DragonECS.Core } return layerID; } - public string GetVertexFromID(VertexID vertexID) + public T GetVertexFromID(VertexID vertexID) { return GetVertexInfo(vertexID).value; } @@ -426,7 +452,7 @@ namespace DCFApixels.DragonECS.Core { return _vertexInfos.Count; } - public VertexID AddVertex(string vertex, bool isLocked) + public VertexID AddVertex(T vertex, bool isLocked) { var result = GetVertexID(vertex); AddVertexByID(result); @@ -436,7 +462,7 @@ namespace DCFApixels.DragonECS.Core } return result; } - private void LockVertex(string vertex) + private void LockVertex(T vertex) { LockVertex(GetVertexID(vertex)); } @@ -454,7 +480,7 @@ namespace DCFApixels.DragonECS.Core } info.insertionIndex = _increment++; } - public bool RemoveVertex(string vertex) + public bool RemoveVertex(T vertex) { var result = GetVertexID(vertex); return RemoveVertexByID(result); @@ -485,9 +511,9 @@ namespace DCFApixels.DragonECS.Core #endregion #region MergeWith - public void MergeWith(IDependencyGraph other) + public void MergeWith(IDependencyGraph other) { - if(other is DependencyGraph graph) + if(other is DependencyGraph graph) { foreach (var otherDependency in graph._dependencies) { @@ -511,7 +537,7 @@ namespace DCFApixels.DragonECS.Core #endregion #region Sort - public string[] Sort() + public T[] Sort() { const int BUFFER_THRESHOLD = 256; if (_count <= BUFFER_THRESHOLD) @@ -521,7 +547,7 @@ namespace DCFApixels.DragonECS.Core TopoSorting(buffer); ReoderInsertionIndexes(buffer); TopoSorting(buffer); - return ConvertIdsToStringsArray(buffer); + return ConvertIdsToTsArray(buffer); } else { @@ -530,7 +556,7 @@ namespace DCFApixels.DragonECS.Core TopoSorting(buffer); ReoderInsertionIndexes(buffer); TopoSorting(buffer); - return ConvertIdsToStringsArray(buffer); + return ConvertIdsToTsArray(buffer); } } private void TopoSorting(UnsafeArray sortingBuffer) @@ -660,14 +686,14 @@ namespace DCFApixels.DragonECS.Core } } - private static void MoveElement(ref UnsafeArray array, int oldIndex, int newIndex) where T : unmanaged + private static void MoveElement(ref UnsafeArray array, int oldIndex, int newIndex) where TValue : unmanaged { if (oldIndex == newIndex) return; var ptr = array.ptr; - T item = ptr[oldIndex]; + TValue item = ptr[oldIndex]; - int elementSize = sizeof(T); + int elementSize = sizeof(TValue); int copyLength = Math.Abs(newIndex - oldIndex); byte* source; @@ -690,9 +716,9 @@ namespace DCFApixels.DragonECS.Core ptr[newIndex] = item; } - private string[] ConvertIdsToStringsArray(UnsafeArray buffer) + private T[] ConvertIdsToTsArray(UnsafeArray buffer) { - string[] result = new string[buffer.Length]; + T[] result = new T[buffer.Length]; for (int i = 0; i < result.Length; i++) { result[i] = GetVertexInfo(buffer.ptr[i]).value; @@ -775,31 +801,31 @@ namespace DCFApixels.DragonECS.Core #endregion #region Other - public bool ContainsVertex(string vertex) + public bool ContainsVertex(T vertex) { return GetVertexInfo(GetVertexID(vertex)).isContained; } public Enumerator GetEnumerator() { return new Enumerator(this); } - IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } + IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } - public struct Enumerator : IEnumerator + public struct Enumerator : IEnumerator { - private DependencyGraph _map; + private DependencyGraph _graph; private int _index; - public Enumerator(DependencyGraph map) + public Enumerator(DependencyGraph graph) { - _map = map; + _graph = graph; _index = -1; } - public string Current + public T Current { - get { return _map.GetVertexInfo(_index).value; } + get { return _graph.GetVertexInfo(_index).value; } } object IEnumerator.Current { get { return Current; } } public bool MoveNext() { - if (_index++ >= _map.GetVertexInfosCount()) { return false; } - ref var info = ref _map.GetVertexInfo(_index); + if (_index++ >= _graph.GetVertexInfosCount()) { return false; } + ref var info = ref _graph.GetVertexInfo(_index); if(info.isContained == false) { return MoveNext(); @@ -818,7 +844,7 @@ namespace DCFApixels.DragonECS.Core [DebuggerDisplay("{value}")] private struct VertexInfo { - public string value; + public T value; public int insertionIndex; public bool isLocked; public bool isContained; @@ -828,7 +854,7 @@ namespace DCFApixels.DragonECS.Core public int inDegree; public int sortingIndex; public int leftBeforeIndex; - public VertexInfo(string name) : this() + public VertexInfo(T name) : this() { this.value = name; } From 6c3b62c2e373d561c76bab963cbfe18e9a2e5b97 Mon Sep 17 00:00:00 2001 From: DCFApixels <99481254+DCFApixels@users.noreply.github.com> Date: Sat, 5 Apr 2025 23:33:51 +0800 Subject: [PATCH 9/9] separate LayersMap --- src/Utils/DependencyGraph.cs | 329 +---------------------------------- src/Utils/LayersMap.cs | 325 ++++++++++++++++++++++++++++++++++ 2 files changed, 332 insertions(+), 322 deletions(-) create mode 100644 src/Utils/LayersMap.cs diff --git a/src/Utils/DependencyGraph.cs b/src/Utils/DependencyGraph.cs index cce2f7d..c499959 100644 --- a/src/Utils/DependencyGraph.cs +++ b/src/Utils/DependencyGraph.cs @@ -8,324 +8,6 @@ using System.Linq; namespace DCFApixels.DragonECS.Core { using VertexID = DependencyGraphVertextID; - public class LayersMap : IDependencyGraph - { - #region IDependencyGraph - VertexID IDependencyGraph.AddVertex(string vertex, bool isLocked) { return _graph.AddVertex(vertex, isLocked); } - bool IDependencyGraph.ContainsVertex(string vertex) { return _graph.ContainsVertex(vertex); } - VertexID IDependencyGraph.GetVertexID(string vertex) { return _graph.GetVertexID(vertex); } - string IDependencyGraph.GetVertexFromID(VertexID vertexID) { return _graph.GetVertexFromID(vertexID); } - bool IDependencyGraph.RemoveVertex(string vertex) { return _graph.RemoveVertex(vertex); } - void IDependencyGraph.AddDependency(VertexID fromID, VertexID toID, bool moveToRight) { _graph.AddDependency(fromID, toID, moveToRight); } - string[] IDependencyGraph.Sort() { return _graph.Sort(); } - #endregion - - private readonly IDependencyGraph _graph; - private readonly EcsPipeline.Builder _pipelineBuilder; - private readonly string _preBeginLayer; - - #region Properties - public EcsPipeline.Builder Back - { - get { return _pipelineBuilder; } - } - public int Count - { - get { return _graph.Count; } - } - public ReadonlyDependenciesCollection Dependencies - { - get { return _graph.Dependencies; } - } - #endregion - - #region Constructors - public LayersMap(IDependencyGraph graph, EcsPipeline.Builder pipelineBuilder) - { - _graph = graph; - _pipelineBuilder = pipelineBuilder; - } - public LayersMap(IDependencyGraph graph, EcsPipeline.Builder pipelineBuilder, string preBeginlayer, string beginlayer, string basicLayer, string endLayer, string postEndLayer) - { - _graph = graph; - _pipelineBuilder = pipelineBuilder; - - graph.AddVertex(preBeginlayer, true); - graph.AddVertex(beginlayer, true); - graph.AddVertex(basicLayer, true); - graph.AddVertex(endLayer, true); - graph.AddVertex(postEndLayer, true); - - Move(preBeginlayer); - //.Before(beginlayer); - Move(beginlayer) - //.Before(basicLayer) - .After(preBeginlayer); - Move(basicLayer) - //.Before(endLayer) - .After(beginlayer); - Move(endLayer) - //.Before(postEndLayer) - .After(basicLayer); - Move(postEndLayer) - .After(endLayer); - } - #endregion - - #region Add - public MoveHandler Add(string layer) - { - VertexID id = _graph.AddVertex(layer, false); - return new MoveHandler(_graph, _pipelineBuilder, id); - } - public MoveHandler Add(params string[] layers) - { - return Add(layersRange: layers); - } - public MoveHandler Add(IEnumerable layersRange) - { - foreach (var layer in layersRange) - { - Add(layer); - } - return new MoveHandler(_graph, _pipelineBuilder, layersRange); - } - #endregion - - #region Move - public MoveHandler Move(string layer) - { - VertexID id = _graph.GetVertexID(layer); - return new MoveHandler(_graph, _pipelineBuilder, id); - } - public MoveHandler Move(params string[] layers) - { - return new MoveHandler(_graph, _pipelineBuilder, layers); - } - public MoveHandler Move(IEnumerable layersRange) - { - return new MoveHandler(_graph, _pipelineBuilder, layersRange); - } - #endregion - - #region MoveHandler - public struct MoveHandler - { - private readonly IDependencyGraph _graph; - private readonly EcsPipeline.Builder _pipelineBuilder; - private readonly VertexID _layerID; - private readonly IEnumerable _layersRange; - - #region Properties - public EcsPipeline.Builder Back - { - get { return _pipelineBuilder; } - } - #endregion - - #region Constructors - public MoveHandler(IDependencyGraph graph, EcsPipeline.Builder pipelineBuilder, VertexID id) - { - _graph = graph; - _pipelineBuilder = pipelineBuilder; - _layerID = id; - _layersRange = null; - } - public MoveHandler(IDependencyGraph graph, EcsPipeline.Builder pipelineBuilder, IEnumerable layersRange) - { - _graph = graph; - _pipelineBuilder = pipelineBuilder; - _layerID = VertexID.NULL; - _layersRange = layersRange; - } - #endregion - - #region Before - public MoveHandler Before(params string[] targets) - { - return Before(targetsRange: targets); - } - public MoveHandler Before(IEnumerable targetsRange) - { - foreach (var target in targetsRange) - { - Before(target); - } - return this; - } - public MoveHandler Before(string targetLayer) - { - if (_layerID != VertexID.NULL) - { - _graph.AddDependency(_layerID, _graph.GetVertexID(targetLayer), true); - } - if (_layersRange != null) - { - foreach (var layer in _layersRange) - { - _graph.AddDependency(_graph.GetVertexID(layer), _graph.GetVertexID(targetLayer), true); - } - } - return this; - } - #endregion - - #region After - public MoveHandler After(params string[] targets) - { - return After(targetsRange: targets); - } - public MoveHandler After(IEnumerable targetsRange) - { - foreach (var target in targetsRange) - { - After(target); - } - return this; - } - public MoveHandler After(string targetLayer) - { - if (_layerID != VertexID.NULL) - { - _graph.AddDependency(_graph.GetVertexID(targetLayer), _layerID, false); - } - if (_layersRange != null) - { - foreach (var layer in _layersRange) - { - _graph.AddDependency(_graph.GetVertexID(targetLayer), _graph.GetVertexID(layer), false); - } - } - return this; - } - #endregion - } - #endregion - - #region MergeWith - public void MergeWith(IDependencyGraph other) - { - _graph.MergeWith(other); - } - //[Obsolete("Use MergeWith(LayersMap)")] - public void MergeWith(IReadOnlyList other) - { - var enumerator = other.GetEnumerator(); - string prev = null; - if (_preBeginLayer != null) - { - while (enumerator.MoveNext()) - { - var layer = enumerator.Current; - if (layer == _preBeginLayer) { break; } - - Add(layer); - if (prev != null) - { - Move(prev).Before(layer); - } - prev = layer; - } - } - while (enumerator.MoveNext()) - { - var layer = enumerator.Current; - Add(layer); - if (prev != null) - { - Move(layer).After(prev); - } - prev = layer; - } - } - #endregion; - - #region Other - public bool Contains(string layer) - { - return _graph.ContainsVertex(layer); - } - public IEnumerator GetEnumerator() { return _graph.GetEnumerator(); } - IEnumerator IEnumerable.GetEnumerator() { return _graph.GetEnumerator(); } - #endregion - - #region Build - public string[] Build() - { - return _graph.Sort(); - } - #endregion - - #region Obsolete - [Obsolete("Use " + nameof(LayersMap) + ".Add(layer).Before(targetLayer).Back;")] - public EcsPipeline.Builder Insert(string targetLayer, string newLayer) - { - Add(newLayer).Before(targetLayer); - return _pipelineBuilder; - } - [Obsolete("Use " + nameof(LayersMap) + ".Add(layer).After(targetLayer).Back;")] - public EcsPipeline.Builder InsertAfter(string targetLayer, string newLayer) - { - Add(newLayer).After(targetLayer); - return _pipelineBuilder; - } - [Obsolete("Use " + nameof(LayersMap) + ".Move(layer).Before(targetLayer).Back;")] - public EcsPipeline.Builder Move(string targetLayer, string newLayer) - { - Move(newLayer).Before(targetLayer); - return _pipelineBuilder; - } - [Obsolete("Use " + nameof(LayersMap) + ".Move(layer).After(targetLayer).Back;")] - public EcsPipeline.Builder MoveAfter(string targetLayer, string newLayer) - { - Move(newLayer).After(targetLayer); - return _pipelineBuilder; - } - [Obsolete("Use " + nameof(LayersMap) + ".Add(layers).Before(targetLayer).Back;")] - public EcsPipeline.Builder Insert(string targetLayer, params string[] newLayers) - { - Add(newLayers).Before(targetLayer); - return _pipelineBuilder; - } - [Obsolete("Use " + nameof(LayersMap) + ".Add(layers).After(targetLayer).Back;")] - public EcsPipeline.Builder InsertAfter(string targetLayer, params string[] newLayers) - { - Add(newLayers).After(targetLayer); - return _pipelineBuilder; - } - [Obsolete("Use " + nameof(LayersMap) + ".Move(layers).Before(targetLayer).Back;")] - public EcsPipeline.Builder Move(string targetLayer, params string[] movingLayers) - { - Move(movingLayers).Before(targetLayer); - return _pipelineBuilder; - } - [Obsolete("Use " + nameof(LayersMap) + ".Move(layers).After(targetLayer).Back;")] - public EcsPipeline.Builder MoveAfter(string targetLayer, params string[] movingLayers) - { - Move(movingLayers).After(targetLayer); - return _pipelineBuilder; - } - - [Obsolete] - public object this[int index] - { - get - { - int i = 0; - foreach (var item in this) - { - if (i == index) - { - return item; - } - i++; - } - return null; - } - } - #endregion - } - public enum DependencyGraphVertextID : short { NULL = 0 } public interface IDependencyGraph : IReadOnlyCollection { @@ -385,7 +67,10 @@ namespace DCFApixels.DragonECS.Core public void Dispose() { } } } - public unsafe partial class DependencyGraph : IDependencyGraph + + + + public unsafe class DependencyGraph : IDependencyGraph { private readonly Dictionary _vertexIDs = new Dictionary(32); private StructList _vertexInfos = new StructList(32); @@ -513,7 +198,7 @@ namespace DCFApixels.DragonECS.Core #region MergeWith public void MergeWith(IDependencyGraph other) { - if(other is DependencyGraph graph) + if (other is DependencyGraph graph) { foreach (var otherDependency in graph._dependencies) { @@ -598,7 +283,7 @@ namespace DCFApixels.DragonECS.Core { var toID = (VertexID)i; ref var toInfo = ref GetVertexInfo(i); - if(toInfo.isContained && toInfo.hasAnyDependency == false) + if (toInfo.isContained && toInfo.hasAnyDependency == false) { basicLayerAdjacencyList.Insert(inserIndex, (toID, toInfo.insertionIndex)); toInfo.inDegree += 1; @@ -826,7 +511,7 @@ namespace DCFApixels.DragonECS.Core { if (_index++ >= _graph.GetVertexInfosCount()) { return false; } ref var info = ref _graph.GetVertexInfo(_index); - if(info.isContained == false) + if (info.isContained == false) { return MoveNext(); } diff --git a/src/Utils/LayersMap.cs b/src/Utils/LayersMap.cs new file mode 100644 index 0000000..8ee47a8 --- /dev/null +++ b/src/Utils/LayersMap.cs @@ -0,0 +1,325 @@ +using System; +using System.Collections; +using System.Collections.Generic; + +namespace DCFApixels.DragonECS.Core +{ + using VertexID = DependencyGraphVertextID; + public class LayersMap : IDependencyGraph + { + #region IDependencyGraph + VertexID IDependencyGraph.AddVertex(string vertex, bool isLocked) { return _graph.AddVertex(vertex, isLocked); } + bool IDependencyGraph.ContainsVertex(string vertex) { return _graph.ContainsVertex(vertex); } + VertexID IDependencyGraph.GetVertexID(string vertex) { return _graph.GetVertexID(vertex); } + string IDependencyGraph.GetVertexFromID(VertexID vertexID) { return _graph.GetVertexFromID(vertexID); } + bool IDependencyGraph.RemoveVertex(string vertex) { return _graph.RemoveVertex(vertex); } + void IDependencyGraph.AddDependency(VertexID fromID, VertexID toID, bool moveToRight) { _graph.AddDependency(fromID, toID, moveToRight); } + string[] IDependencyGraph.Sort() { return _graph.Sort(); } + #endregion + + private readonly IDependencyGraph _graph; + private readonly EcsPipeline.Builder _pipelineBuilder; + private readonly string _preBeginLayer; + + #region Properties + public EcsPipeline.Builder Back + { + get { return _pipelineBuilder; } + } + public int Count + { + get { return _graph.Count; } + } + public ReadonlyDependenciesCollection Dependencies + { + get { return _graph.Dependencies; } + } + #endregion + + #region Constructors + public LayersMap(IDependencyGraph graph, EcsPipeline.Builder pipelineBuilder) + { + _graph = graph; + _pipelineBuilder = pipelineBuilder; + } + public LayersMap(IDependencyGraph graph, EcsPipeline.Builder pipelineBuilder, string preBeginlayer, string beginlayer, string basicLayer, string endLayer, string postEndLayer) + { + _graph = graph; + _pipelineBuilder = pipelineBuilder; + + graph.AddVertex(preBeginlayer, true); + graph.AddVertex(beginlayer, true); + graph.AddVertex(basicLayer, true); + graph.AddVertex(endLayer, true); + graph.AddVertex(postEndLayer, true); + + Move(preBeginlayer); + //.Before(beginlayer); + Move(beginlayer) + //.Before(basicLayer) + .After(preBeginlayer); + Move(basicLayer) + //.Before(endLayer) + .After(beginlayer); + Move(endLayer) + //.Before(postEndLayer) + .After(basicLayer); + Move(postEndLayer) + .After(endLayer); + } + #endregion + + #region Add + public MoveHandler Add(string layer) + { + VertexID id = _graph.AddVertex(layer, false); + return new MoveHandler(_graph, _pipelineBuilder, id); + } + public MoveHandler Add(params string[] layers) + { + return Add(layersRange: layers); + } + public MoveHandler Add(IEnumerable layersRange) + { + foreach (var layer in layersRange) + { + Add(layer); + } + return new MoveHandler(_graph, _pipelineBuilder, layersRange); + } + #endregion + + #region Move + public MoveHandler Move(string layer) + { + VertexID id = _graph.GetVertexID(layer); + return new MoveHandler(_graph, _pipelineBuilder, id); + } + public MoveHandler Move(params string[] layers) + { + return new MoveHandler(_graph, _pipelineBuilder, layers); + } + public MoveHandler Move(IEnumerable layersRange) + { + return new MoveHandler(_graph, _pipelineBuilder, layersRange); + } + #endregion + + #region MoveHandler + public struct MoveHandler + { + private readonly IDependencyGraph _graph; + private readonly EcsPipeline.Builder _pipelineBuilder; + private readonly VertexID _layerID; + private readonly IEnumerable _layersRange; + + #region Properties + public EcsPipeline.Builder Back + { + get { return _pipelineBuilder; } + } + #endregion + + #region Constructors + public MoveHandler(IDependencyGraph graph, EcsPipeline.Builder pipelineBuilder, VertexID id) + { + _graph = graph; + _pipelineBuilder = pipelineBuilder; + _layerID = id; + _layersRange = null; + } + public MoveHandler(IDependencyGraph graph, EcsPipeline.Builder pipelineBuilder, IEnumerable layersRange) + { + _graph = graph; + _pipelineBuilder = pipelineBuilder; + _layerID = VertexID.NULL; + _layersRange = layersRange; + } + #endregion + + #region Before + public MoveHandler Before(params string[] targets) + { + return Before(targetsRange: targets); + } + public MoveHandler Before(IEnumerable targetsRange) + { + foreach (var target in targetsRange) + { + Before(target); + } + return this; + } + public MoveHandler Before(string targetLayer) + { + if (_layerID != VertexID.NULL) + { + _graph.AddDependency(_layerID, _graph.GetVertexID(targetLayer), true); + } + if (_layersRange != null) + { + foreach (var layer in _layersRange) + { + _graph.AddDependency(_graph.GetVertexID(layer), _graph.GetVertexID(targetLayer), true); + } + } + return this; + } + #endregion + + #region After + public MoveHandler After(params string[] targets) + { + return After(targetsRange: targets); + } + public MoveHandler After(IEnumerable targetsRange) + { + foreach (var target in targetsRange) + { + After(target); + } + return this; + } + public MoveHandler After(string targetLayer) + { + if (_layerID != VertexID.NULL) + { + _graph.AddDependency(_graph.GetVertexID(targetLayer), _layerID, false); + } + if (_layersRange != null) + { + foreach (var layer in _layersRange) + { + _graph.AddDependency(_graph.GetVertexID(targetLayer), _graph.GetVertexID(layer), false); + } + } + return this; + } + #endregion + } + #endregion + + #region MergeWith + public void MergeWith(IDependencyGraph other) + { + _graph.MergeWith(other); + } + //[Obsolete("Use MergeWith(LayersMap)")] + public void MergeWith(IReadOnlyList other) + { + var enumerator = other.GetEnumerator(); + string prev = null; + if (_preBeginLayer != null) + { + while (enumerator.MoveNext()) + { + var layer = enumerator.Current; + if (layer == _preBeginLayer) { break; } + + Add(layer); + if (prev != null) + { + Move(prev).Before(layer); + } + prev = layer; + } + } + while (enumerator.MoveNext()) + { + var layer = enumerator.Current; + Add(layer); + if (prev != null) + { + Move(layer).After(prev); + } + prev = layer; + } + } + #endregion; + + #region Other + public bool Contains(string layer) + { + return _graph.ContainsVertex(layer); + } + public IEnumerator GetEnumerator() { return _graph.GetEnumerator(); } + IEnumerator IEnumerable.GetEnumerator() { return _graph.GetEnumerator(); } + #endregion + + #region Build + public string[] Build() + { + return _graph.Sort(); + } + #endregion + + #region Obsolete + [Obsolete("Use " + nameof(LayersMap) + ".Add(layer).Before(targetLayer).Back;")] + public EcsPipeline.Builder Insert(string targetLayer, string newLayer) + { + Add(newLayer).Before(targetLayer); + return _pipelineBuilder; + } + [Obsolete("Use " + nameof(LayersMap) + ".Add(layer).After(targetLayer).Back;")] + public EcsPipeline.Builder InsertAfter(string targetLayer, string newLayer) + { + Add(newLayer).After(targetLayer); + return _pipelineBuilder; + } + [Obsolete("Use " + nameof(LayersMap) + ".Move(layer).Before(targetLayer).Back;")] + public EcsPipeline.Builder Move(string targetLayer, string newLayer) + { + Move(newLayer).Before(targetLayer); + return _pipelineBuilder; + } + [Obsolete("Use " + nameof(LayersMap) + ".Move(layer).After(targetLayer).Back;")] + public EcsPipeline.Builder MoveAfter(string targetLayer, string newLayer) + { + Move(newLayer).After(targetLayer); + return _pipelineBuilder; + } + [Obsolete("Use " + nameof(LayersMap) + ".Add(layers).Before(targetLayer).Back;")] + public EcsPipeline.Builder Insert(string targetLayer, params string[] newLayers) + { + Add(newLayers).Before(targetLayer); + return _pipelineBuilder; + } + [Obsolete("Use " + nameof(LayersMap) + ".Add(layers).After(targetLayer).Back;")] + public EcsPipeline.Builder InsertAfter(string targetLayer, params string[] newLayers) + { + Add(newLayers).After(targetLayer); + return _pipelineBuilder; + } + [Obsolete("Use " + nameof(LayersMap) + ".Move(layers).Before(targetLayer).Back;")] + public EcsPipeline.Builder Move(string targetLayer, params string[] movingLayers) + { + Move(movingLayers).Before(targetLayer); + return _pipelineBuilder; + } + [Obsolete("Use " + nameof(LayersMap) + ".Move(layers).After(targetLayer).Back;")] + public EcsPipeline.Builder MoveAfter(string targetLayer, params string[] movingLayers) + { + Move(movingLayers).After(targetLayer); + return _pipelineBuilder; + } + + [Obsolete] + public object this[int index] + { + get + { + int i = 0; + foreach (var item in this) + { + if (i == index) + { + return item; + } + i++; + } + return null; + } + } + #endregion + } +} \ No newline at end of file