Skip to content

Commit

Permalink
Merge pull request #358 from nostek/optimizations/memandgc
Browse files Browse the repository at this point in the history
Optimizations/memandgc
  • Loading branch information
Siccity authored Nov 28, 2022
2 parents dd62011 + da0f291 commit 5967cef
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 37 deletions.
5 changes: 5 additions & 0 deletions Scripts/Node.cs
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,8 @@ public NodeWidthAttribute(int width) {
public void OnBeforeSerialize() {
keys.Clear();
values.Clear();
keys.Capacity = this.Count;
values.Capacity = this.Count;
foreach (KeyValuePair<string, NodePort> pair in this) {
keys.Add(pair.Key);
values.Add(pair.Value);
Expand All @@ -404,6 +406,9 @@ public void OnBeforeSerialize() {

public void OnAfterDeserialize() {
this.Clear();
#if UNITY_2021_3_OR_NEWER
this.EnsureCapacity(keys.Count);
#endif

if (keys.Count != values.Count)
throw new System.Exception("there are " + keys.Count + " keys and " + values.Count + " values after deserialization. Make sure that both key and value types are serializable.");
Expand Down
59 changes: 23 additions & 36 deletions Scripts/NodeDataCache.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,24 @@ namespace XNode {
public static class NodeDataCache {
private static PortDataCache portDataCache;
private static Dictionary<System.Type, Dictionary<string, string>> formerlySerializedAsCache;
private static Dictionary<System.Type, string> typeQualifiedNameCache;
private static bool Initialized { get { return portDataCache != null; } }

public static string GetTypeQualifiedName(System.Type type) {
if(typeQualifiedNameCache == null) typeQualifiedNameCache = new Dictionary<System.Type, string>();

string name;
if (!typeQualifiedNameCache.TryGetValue(type, out name)) {
name = type.AssemblyQualifiedName;
typeQualifiedNameCache.Add(type, name);
}
return name;
}

/// <summary> Update static ports and dynamic ports managed by DynamicPortLists to reflect class fields. </summary>
public static void UpdatePorts(Node node, Dictionary<string, NodePort> ports) {
if (!Initialized) BuildCache();

Dictionary<string, NodePort> staticPorts = new Dictionary<string, NodePort>();
Dictionary<string, List<NodePort>> removedPorts = new Dictionary<string, List<NodePort>>();
System.Type nodeType = node.GetType();

Expand All @@ -23,17 +34,15 @@ public static void UpdatePorts(Node node, Dictionary<string, NodePort> ports) {

List<NodePort> dynamicListPorts = new List<NodePort>();

List<NodePort> typePortCache;
if (portDataCache.TryGetValue(nodeType, out typePortCache)) {
for (int i = 0; i < typePortCache.Count; i++) {
staticPorts.Add(typePortCache[i].fieldName, portDataCache[nodeType][i]);
}
}
Dictionary<string, NodePort> staticPorts;
if (!portDataCache.TryGetValue(nodeType, out staticPorts)) {
staticPorts = new Dictionary<string, NodePort>();
}

// Cleanup port dict - Remove nonexisting static ports - update static port types
// AND update dynamic ports (albeit only those in lists) too, in order to enforce proper serialisation.
// Loop through current node ports
foreach (NodePort port in ports.Values.ToList()) {
foreach (NodePort port in ports.Values.ToArray()) {
// If port still exists, check it it has been changed
NodePort staticPort;
if (staticPorts.TryGetValue(port.fieldName, out staticPort)) {
Expand Down Expand Up @@ -84,7 +93,7 @@ public static void UpdatePorts(Node node, Dictionary<string, NodePort> ports) {
foreach (NodePort listPort in dynamicListPorts) {
// At this point we know that ports here are dynamic list ports
// which have passed name/"backing port" checks, ergo we can proceed more safely.
string backingPortName = listPort.fieldName.Split(' ')[0];
string backingPortName = listPort.fieldName.Substring(0, listPort.fieldName.IndexOf(' '));
NodePort backingPort = staticPorts[backingPortName];

// Update port constraints. Creating a new port instead will break the editor, mandating the need for setters.
Expand Down Expand Up @@ -147,6 +156,7 @@ private static void BuildCache() {
// The following assemblies, and sub-assemblies (eg. UnityEngine.UI) are skipped
case "UnityEditor":
case "UnityEngine":
case "Unity":
case "System":
case "mscorlib":
case "Microsoft":
Expand Down Expand Up @@ -195,8 +205,9 @@ private static void CachePorts(System.Type nodeType) {

if (inputAttrib != null && outputAttrib != null) Debug.LogError("Field " + fieldInfo[i].Name + " of type " + nodeType.FullName + " cannot be both input and output.");
else {
if (!portDataCache.ContainsKey(nodeType)) portDataCache.Add(nodeType, new List<NodePort>());
portDataCache[nodeType].Add(new NodePort(fieldInfo[i]));
if (!portDataCache.ContainsKey(nodeType)) portDataCache.Add(nodeType, new Dictionary<string, NodePort>());
NodePort port = new NodePort(fieldInfo[i]);
portDataCache[nodeType].Add(port.fieldName, port);
}

if (formerlySerializedAsAttribute != null) {
Expand All @@ -210,30 +221,6 @@ private static void CachePorts(System.Type nodeType) {
}

[System.Serializable]
private class PortDataCache : Dictionary<System.Type, List<NodePort>>, ISerializationCallbackReceiver {
[SerializeField] private List<System.Type> keys = new List<System.Type>();
[SerializeField] private List<List<NodePort>> values = new List<List<NodePort>>();

// save the dictionary to lists
public void OnBeforeSerialize() {
keys.Clear();
values.Clear();
foreach (var pair in this) {
keys.Add(pair.Key);
values.Add(pair.Value);
}
}

// load dictionary from lists
public void OnAfterDeserialize() {
this.Clear();

if (keys.Count != values.Count)
throw new System.Exception(string.Format("there are {0} keys and {1} values after deserialization. Make sure that both key and value types are serializable."));

for (int i = 0; i < keys.Count; i++)
this.Add(keys[i], values[i]);
}
}
private class PortDataCache : Dictionary<System.Type, Dictionary<string, NodePort>> { }
}
}
3 changes: 2 additions & 1 deletion Scripts/NodePort.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,9 @@ public Type ValueType {
return valueType;
}
set {
if (valueType == value) return;
valueType = value;
if (value != null) _typeQualifiedName = value.AssemblyQualifiedName;
if (value != null) _typeQualifiedName = NodeDataCache.GetTypeQualifiedName(value);
}
}
private Type valueType;
Expand Down

0 comments on commit 5967cef

Please sign in to comment.