diff --git a/TLM/TLM/Lifecycle/AssetDataExtension.cs b/TLM/TLM/Lifecycle/AssetDataExtension.cs index 22e14021b..4be144187 100644 --- a/TLM/TLM/Lifecycle/AssetDataExtension.cs +++ b/TLM/TLM/Lifecycle/AssetDataExtension.cs @@ -43,7 +43,7 @@ public static void OnAssetSavedImpl(string name, object asset, out Dictionary + diff --git a/TLM/TLM/Util/Extensions/EnumerableExtensions.cs b/TLM/TLM/Util/Extensions/EnumerableExtensions.cs new file mode 100644 index 000000000..ac7f2733f --- /dev/null +++ b/TLM/TLM/Util/Extensions/EnumerableExtensions.cs @@ -0,0 +1,11 @@ +namespace TrafficManager.Util.Extensions { + using System; + using System.Collections; + using System.Collections.Generic; + using System.Linq; + using System.Text; + + internal static class EnumerableExtensions { + internal static IEnumerable EmptyIfNull(this IEnumerable e) => e ?? Enumerable.Empty(); + } +} diff --git a/TLM/TLM/Util/Record/IRecordable.cs b/TLM/TLM/Util/Record/IRecordable.cs index b08ef1551..86a31d642 100644 --- a/TLM/TLM/Util/Record/IRecordable.cs +++ b/TLM/TLM/Util/Record/IRecordable.cs @@ -1,4 +1,4 @@ -using System; +using System.Linq; using System.Collections.Generic; namespace TrafficManager.Util.Record { @@ -19,6 +19,18 @@ public interface IRecordable { /// maps old Instance IDs to new Instance IDs void Transfer(Dictionary map); + /// + /// Detects if record is empty to help releasing empty records from memory. + /// + /// true if record stores only default values. false if record stores any useful information. + bool IsDefault(); + byte[] Serialize(); } + + public static class RecordExtensions { + public static bool AreDefault(this IEnumerable records) + where T : IRecordable => + records == null || records.All(record => record == null || record.IsDefault()); + } } diff --git a/TLM/TLM/Util/Record/LaneArrowsRecord.cs b/TLM/TLM/Util/Record/LaneArrowsRecord.cs index c43369d7e..1df6e92bc 100644 --- a/TLM/TLM/Util/Record/LaneArrowsRecord.cs +++ b/TLM/TLM/Util/Record/LaneArrowsRecord.cs @@ -17,6 +17,8 @@ public void Record() { arrows_ = Flags.GetLaneArrowFlags(LaneId); } + public bool IsDefault() => arrows_ == null; + public void Restore() => Transfer(LaneId); public void Transfer(Dictionary map) => diff --git a/TLM/TLM/Util/Record/LaneConnectionRecord.cs b/TLM/TLM/Util/Record/LaneConnectionRecord.cs index c993b1dfb..01c2c6afb 100644 --- a/TLM/TLM/Util/Record/LaneConnectionRecord.cs +++ b/TLM/TLM/Util/Record/LaneConnectionRecord.cs @@ -48,6 +48,11 @@ private void RestoreImpl(LaneConnectionSubManager man, uint[] connections) { } } + public bool IsDefault() => + connections_.IsNullOrEmpty() && + roadConnections_.IsNullOrEmpty() && + trackConnections_.IsNullOrEmpty(); + public void Restore() { if (connections_ != null) { // legacy diff --git a/TLM/TLM/Util/Record/NodeRecord.cs b/TLM/TLM/Util/Record/NodeRecord.cs index 89ee3ebaa..344a5ad26 100644 --- a/TLM/TLM/Util/Record/NodeRecord.cs +++ b/TLM/TLM/Util/Record/NodeRecord.cs @@ -1,8 +1,8 @@ namespace TrafficManager.Util.Record { using System; using System.Collections.Generic; + using System.Linq; using TrafficManager.Manager.Impl; - using static TrafficManager.Util.Shortcuts; using TrafficManager.State; using TrafficManager.Util.Extensions; @@ -13,45 +13,32 @@ public class NodeRecord : IRecordable { public ushort NodeId { get; private set; } InstanceID InstanceID => new InstanceID { NetNode = NodeId}; - private bool trafficLight_; + private bool? trafficLight_; private List lanes_; private static TrafficLightManager tlMan => TrafficLightManager.Instance; public void Record() { - trafficLight_ = tlMan.HasTrafficLight(NodeId, ref NodeId.ToNode()); + trafficLight_ = tlMan.GetHasTrafficLight(NodeId); lanes_ = LaneConnectionRecord.GetLanes(NodeId); - foreach (LaneConnectionRecord sourceLane in lanes_) { - sourceLane.Record(); + foreach (LaneConnectionRecord sourceLane in lanes_.EmptyIfNull()) { + sourceLane?.Record(); } } + public bool IsDefault() => + trafficLight_ == null && lanes_.AreDefault(); + public void Restore() { - SetTrafficLight(NodeId, trafficLight_); - foreach (LaneConnectionRecord sourceLane in lanes_) { - sourceLane.Restore(); + tlMan.SetHasTrafficLight(NodeId, trafficLight_); + foreach (LaneConnectionRecord sourceLane in lanes_.EmptyIfNull()) { + sourceLane?.Restore(); } } public void Transfer(Dictionary map) { - SetTrafficLight(map[InstanceID].NetNode, trafficLight_); - foreach (LaneConnectionRecord sourceLane in lanes_) - sourceLane.Transfer(map); - } - - private static bool SetTrafficLight(ushort nodeId, bool flag) { - // TODO move code to manager. - bool currentValue = tlMan.HasTrafficLight(nodeId, ref nodeId.ToNode()); - if (currentValue == flag) - return true; - bool canChangeValue = tlMan.CanToggleTrafficLight( - nodeId, - flag, - ref nodeId.ToNode(), - out _); - if (!canChangeValue) { - return false; - } - return tlMan.SetTrafficLight(nodeId, flag, ref nodeId.ToNode()); + tlMan.SetHasTrafficLight(map[InstanceID].NetNode, trafficLight_); + foreach (LaneConnectionRecord sourceLane in lanes_.EmptyIfNull()) + sourceLane?.Transfer(map); } public byte[] Serialize() => SerializationUtil.Serialize(this); diff --git a/TLM/TLM/Util/Record/SegmentEndRecord.cs b/TLM/TLM/Util/Record/SegmentEndRecord.cs index 596d6b234..1e62e0df9 100644 --- a/TLM/TLM/Util/Record/SegmentEndRecord.cs +++ b/TLM/TLM/Util/Record/SegmentEndRecord.cs @@ -6,9 +6,10 @@ namespace TrafficManager.Util.Record { using TrafficManager.API.Traffic.Enums; using TrafficManager.Manager.Impl; using TrafficManager.State; + using TrafficManager.Util.Extensions; [Serializable] - class SegmentEndRecord : IRecordable { + public class SegmentEndRecord : IRecordable { public SegmentEndRecord(int segmentEndIndex) { SegmentEndManager.Instance. GetSegmentAndNodeFromIndex(segmentEndIndex, out ushort segmentId, out bool startNode); @@ -23,7 +24,7 @@ public SegmentEndRecord(ushort segmentId, bool startNode) { public ushort SegmentId { get; private set; } public bool StartNode { get; private set; } - InstanceID InstanceID => new InstanceID { NetSegment = SegmentId }; + private InstanceID InstanceID => new InstanceID { NetSegment = SegmentId }; private TernaryBool uturnAllowed_; private TernaryBool nearTurnOnRedAllowed_; @@ -38,6 +39,18 @@ public SegmentEndRecord(ushort segmentId, bool startNode) { private static TrafficPriorityManager priorityMan => TrafficPriorityManager.Instance; private static JunctionRestrictionsManager JRMan => JunctionRestrictionsManager.Instance; + public bool IsDefault() { + return + uturnAllowed_ == TernaryBool.Undefined && + nearTurnOnRedAllowed_ == TernaryBool.Undefined && + farTurnOnRedAllowed_ == TernaryBool.Undefined && + laneChangingAllowedWhenGoingStraight_ == TernaryBool.Undefined && + enteringBlockedJunctionAllowed_ == TernaryBool.Undefined && + pedestrianCrossingAllowed_ == TernaryBool.Undefined && + prioirtySign_ == PriorityType.None && + arrowLanes_.AreDefault(); + } + public void Record() { uturnAllowed_ = JRMan.GetUturnAllowed(SegmentId, StartNode); nearTurnOnRedAllowed_ = JRMan.GetNearTurnOnRedAllowed(SegmentId, StartNode); @@ -49,13 +62,13 @@ public void Record() { prioirtySign_ = priorityMan.GetPrioritySign(SegmentId, StartNode); arrowLanes_ = LaneArrowsRecord.GetLanes(SegmentId, StartNode); - foreach(IRecordable lane in arrowLanes_) - lane.Record(); + foreach(IRecordable lane in arrowLanes_.EmptyIfNull()) + lane?.Record(); } public void Restore() { - foreach (IRecordable lane in arrowLanes_) - lane.Restore(); + foreach (IRecordable lane in arrowLanes_.EmptyIfNull()) + lane?.Restore(); if (priorityMan.MaySegmentHavePrioritySign(SegmentId, StartNode) && prioirtySign_ != priorityMan.GetPrioritySign(SegmentId, StartNode)) { @@ -74,8 +87,8 @@ public void Restore() { public void Transfer(Dictionary map) { ushort segmentId = map[InstanceID].NetSegment; - foreach (IRecordable lane in arrowLanes_) - lane.Transfer(map); + foreach (IRecordable lane in arrowLanes_.EmptyIfNull()) + lane?.Transfer(map); if (priorityMan.MaySegmentHavePrioritySign(segmentId, StartNode) && prioirtySign_ != priorityMan.GetPrioritySign(segmentId, StartNode)) { @@ -95,8 +108,9 @@ public void Transfer(uint mappedId) { ushort segmentId = (ushort)mappedId; var mappedLanes = SpeedLimitLaneRecord.GetLanes(segmentId); - for (int i = 0; i == arrowLanes_.Count; ++i) { - arrowLanes_[i].Transfer(mappedLanes[i].LaneId); + int n = arrowLanes_?.Count ?? 0; + for (int i = 0; i == n; ++i) { + arrowLanes_[i]?.Transfer(mappedLanes[i].LaneId); } } diff --git a/TLM/TLM/Util/Record/SegmentRecord.cs b/TLM/TLM/Util/Record/SegmentRecord.cs index e31ac211d..9ef0b98a5 100644 --- a/TLM/TLM/Util/Record/SegmentRecord.cs +++ b/TLM/TLM/Util/Record/SegmentRecord.cs @@ -26,32 +26,40 @@ public void Record() { parkingForward_ = pMan.IsParkingAllowed(SegmentId, NetInfo.Direction.Forward); parkingBackward_ = pMan.IsParkingAllowed(SegmentId, NetInfo.Direction.Backward); speedLanes_ = SpeedLimitLaneRecord.GetLanes(SegmentId); - foreach (var lane in speedLanes_) - lane.Record(); + foreach (var lane in speedLanes_.EmptyIfNull()) + lane?.Record(); vehicleRestrictionsLanes_ = VehicleRestrictionsLaneRecord.GetLanes(SegmentId); - foreach (var lane in vehicleRestrictionsLanes_) - lane.Record(); + foreach (var lane in vehicleRestrictionsLanes_.EmptyIfNull()) + lane?.Record(); allLaneIds_ = GetAllLanes(SegmentId); } + public bool IsDefault() { + return + parkingForward_ == true && + parkingBackward_ == true && + speedLanes_.AreDefault() && + vehicleRestrictionsLanes_.AreDefault(); + } + public void Restore() { // TODO fix SetParkingAllowed pMan.SetParkingAllowed(SegmentId, NetInfo.Direction.Forward, parkingForward_); pMan.SetParkingAllowed(SegmentId, NetInfo.Direction.Backward, parkingBackward_); - foreach (var lane in speedLanes_) - lane.Restore(); - foreach (var lane in vehicleRestrictionsLanes_) - lane.Restore(); + foreach (var lane in speedLanes_.EmptyIfNull()) + lane?.Restore(); + foreach (var lane in vehicleRestrictionsLanes_.EmptyIfNull()) + lane?.Restore(); } public void Transfer(Dictionary map){ ushort segmentId = map[InstanceID].NetSegment; pMan.SetParkingAllowed(segmentId, NetInfo.Direction.Forward, parkingForward_); pMan.SetParkingAllowed(segmentId, NetInfo.Direction.Backward, parkingBackward_); - foreach (var lane in speedLanes_) - lane.Transfer(map); - foreach (var lane in vehicleRestrictionsLanes_) - lane.Transfer(map); + foreach (var lane in speedLanes_.EmptyIfNull()) + lane?.Transfer(map); + foreach (var lane in vehicleRestrictionsLanes_.EmptyIfNull()) + lane?.Transfer(map); } public byte[] Serialize() => SerializationUtil.Serialize(this); diff --git a/TLM/TLM/Util/Record/SpeedLimitLaneRecord.cs b/TLM/TLM/Util/Record/SpeedLimitLaneRecord.cs index 1cb34ed0b..5b743d756 100644 --- a/TLM/TLM/Util/Record/SpeedLimitLaneRecord.cs +++ b/TLM/TLM/Util/Record/SpeedLimitLaneRecord.cs @@ -26,6 +26,8 @@ public void Record() { : (float?)null; } + public bool IsDefault() => speedLimit_ == null; + public void Restore() => Transfer(LaneId); public void Transfer(Dictionary map) => diff --git a/TLM/TLM/Util/Record/TrafficRulesRecord.cs b/TLM/TLM/Util/Record/TrafficRulesRecord.cs index cf7e530ad..1549f07d0 100644 --- a/TLM/TLM/Util/Record/TrafficRulesRecord.cs +++ b/TLM/TLM/Util/Record/TrafficRulesRecord.cs @@ -64,6 +64,8 @@ public void AddNodeAndSegmentEnds(ushort nodeId) { } } + public bool IsDefault() => Records.AreDefault(); + public void Record() { foreach (ushort nodeId in NodeIDs) Records.Add(new NodeRecord(nodeId)); @@ -72,18 +74,18 @@ public void Record() { foreach (int segmentEndIndex in SegmentEndIndeces) Records.Add(new SegmentEndRecord(segmentEndIndex)); foreach (IRecordable record in Records) - record.Record(); + record?.Record(); } public void Restore() { - foreach (IRecordable record in Records) - record.Restore(); + foreach (IRecordable record in Records.EmptyIfNull()) + record?.Restore(); } public void Transfer(Dictionary map) { - foreach (IRecordable record in Records) { + foreach (IRecordable record in Records.EmptyIfNull()) { try { - record.Transfer(map); + record?.Transfer(map); } catch(KeyNotFoundException ex) { // hide message in release build to avoid scaring the user. diff --git a/TLM/TLM/Util/Record/VehicleRestrictionsLaneRecord.cs b/TLM/TLM/Util/Record/VehicleRestrictionsLaneRecord.cs index 0605a7105..58fb5bb94 100644 --- a/TLM/TLM/Util/Record/VehicleRestrictionsLaneRecord.cs +++ b/TLM/TLM/Util/Record/VehicleRestrictionsLaneRecord.cs @@ -21,6 +21,8 @@ public class VehicleRestrictionsLaneRecord : IRecordable { InstanceID InstanceID => new InstanceID { NetLane = LaneId }; + public bool IsDefault() => allowedVehicleTypes_ == null; + public void Record() { allowedVehicleTypes_ = VehicleRestrictionsManager.Instance.GetAllowedVehicleTypesRaw(SegmentId, LaneIndex); }