From abac7381231396e6c441a98a9327806b3e0a7c35 Mon Sep 17 00:00:00 2001 From: Ellpeck Date: Sun, 18 Jul 2021 22:18:46 +0200 Subject: [PATCH] Removed LINQ Any and All usage in various methods to improve memory usage --- CHANGELOG.md | 6 ++++- MLEM.Data/DynamicEnum.cs | 6 +++-- MLEM.Extended/Tiled/TiledMapCollisions.cs | 10 ++++++- MLEM.Ui/Elements/TextField.cs | 32 ++++++++++++++++++++--- MLEM.Ui/Elements/Tooltip.cs | 8 ++++-- MLEM.Ui/UiSystem.cs | 8 +++++- MLEM/Formatting/TokenizedString.cs | 8 +++++- MLEM/Input/InputHandler.cs | 30 ++++++++++++++++----- MLEM/Input/Keybind.cs | 26 +++++++++++++++--- 9 files changed, 111 insertions(+), 23 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5fb651f..b27cc4e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,8 +13,9 @@ Additions Improvements - Improved NinePatch memory performance - Moved sound-related classes into Sound namespace -- Added customizable overloads for Keybind, Combination and GenericInput ToString methods +- Added customizable overloads for Keybind, Combination and GenericInput ToString methods - Added ColorExtensions.Invert and made ColorHelper.Invert obsolete +- Removed LINQ Any and All usage in various methods to improve memory usage Fixes - Set default values for InputHandler held and pressed keys to avoid an exception if buttons are held in the very first frame @@ -23,6 +24,9 @@ Fixes Additions - Added a masking character to TextField to allow for password-style text fields +Improvements +- Removed LINQ Any and All usage in various methods to improve memory usage + Fixes - Fixed a crash if a paragraph has a link formatting code, but no font diff --git a/MLEM.Data/DynamicEnum.cs b/MLEM.Data/DynamicEnum.cs index 6fbd7bb..2ad9811 100644 --- a/MLEM.Data/DynamicEnum.cs +++ b/MLEM.Data/DynamicEnum.cs @@ -118,8 +118,10 @@ namespace MLEM.Data { if (dict.ContainsKey(value)) throw new ArgumentException($"Duplicate value {value}", nameof(value)); - if (dict.Values.Any(v => v.name == name)) - throw new ArgumentException($"Duplicate name {name}", nameof(name)); + foreach (var v in dict.Values) { + if (v.name == name) + throw new ArgumentException($"Duplicate name {name}", nameof(name)); + } var ret = Construct(typeof(T), name, value); dict.Add(value, ret); diff --git a/MLEM.Extended/Tiled/TiledMapCollisions.cs b/MLEM.Extended/Tiled/TiledMapCollisions.cs index 67b3ff4..59a349b 100644 --- a/MLEM.Extended/Tiled/TiledMapCollisions.cs +++ b/MLEM.Extended/Tiled/TiledMapCollisions.cs @@ -72,7 +72,15 @@ namespace MLEM.Extended.Tiled { /// A function that determines if a certain info should be included or not /// An enumerable of collision infos for that area public IEnumerable GetCollidingTiles(RectangleF area, Func included = null) { - var inclusionFunc = included ?? (tile => tile.Collisions.Any(c => c.Intersects(area))); + bool DefaultInclusion(TileCollisionInfo tile) { + foreach (var c in tile.Collisions) { + if (c.Intersects(area)) + return true; + } + return false; + } + + var inclusionFunc = included ?? DefaultInclusion; var minX = Math.Max(0, area.Left.Floor()); var maxX = Math.Min(this.map.Width - 1, area.Right.Floor()); var minY = Math.Max(0, area.Top.Floor()); diff --git a/MLEM.Ui/Elements/TextField.cs b/MLEM.Ui/Elements/TextField.cs index d9785f1..34af66a 100644 --- a/MLEM.Ui/Elements/TextField.cs +++ b/MLEM.Ui/Elements/TextField.cs @@ -24,19 +24,43 @@ namespace MLEM.Ui.Elements { /// /// A that allows any visible character and spaces /// - public static readonly Rule DefaultRule = (field, add) => !add.Any(char.IsControl); + public static readonly Rule DefaultRule = (field, add) => { + foreach (var c in add) { + if (char.IsControl(c)) + return false; + } + return true; + }; /// /// A that only allows letters /// - public static readonly Rule OnlyLetters = (field, add) => add.All(char.IsLetter); + public static readonly Rule OnlyLetters = (field, add) => { + foreach (var c in add) { + if (!char.IsLetter(c)) + return false; + } + return true; + }; /// /// A that only allows numerals /// - public static readonly Rule OnlyNumbers = (field, add) => add.All(char.IsNumber); + public static readonly Rule OnlyNumbers = (field, add) => { + foreach (var c in add) { + if (!char.IsNumber(c)) + return false; + } + return true; + }; /// /// A that only allows letters and numerals /// - public static readonly Rule LettersNumbers = (field, add) => add.All(c => char.IsLetter(c) || char.IsNumber(c)); + public static readonly Rule LettersNumbers = (field, add) => { + foreach (var c in add) { + if (!char.IsLetter(c) || !char.IsNumber(c)) + return false; + } + return true; + }; /// /// A that only allows characters not contained in /// diff --git a/MLEM.Ui/Elements/Tooltip.cs b/MLEM.Ui/Elements/Tooltip.cs index 0282368..1c5335e 100644 --- a/MLEM.Ui/Elements/Tooltip.cs +++ b/MLEM.Ui/Elements/Tooltip.cs @@ -129,8 +129,12 @@ namespace MLEM.Ui.Elements { public void AddToElement(Element elementToHover) { elementToHover.OnMouseEnter += element => { // only display the tooltip if there is anything in it - if (this.Children.Any(c => !c.IsHidden)) - this.Display(element.System, element.GetType().Name + "Tooltip"); + foreach (var c in this.Children) { + if (!c.IsHidden) { + this.Display(element.System, element.GetType().Name + "Tooltip"); + break; + } + } }; elementToHover.OnMouseExit += element => this.Remove(); } diff --git a/MLEM.Ui/UiSystem.cs b/MLEM.Ui/UiSystem.cs index ff07df1..71a378f 100644 --- a/MLEM.Ui/UiSystem.cs +++ b/MLEM.Ui/UiSystem.cs @@ -465,8 +465,14 @@ namespace MLEM.Ui { this.CanSelectContent = true; }; this.OnElementRemoved += e => { - if (e.CanBeSelected && !this.Element.GetChildren(regardGrandchildren: true).Any(c => c.CanBeSelected)) + if (e.CanBeSelected) { + // check if removing this element removed all other selectable elements + foreach (var c in this.Element.GetChildren(regardGrandchildren: true)) { + if (c.CanBeSelected) + return; + } this.CanSelectContent = false; + } }; } diff --git a/MLEM/Formatting/TokenizedString.cs b/MLEM/Formatting/TokenizedString.cs index d02f1d9..9d60731 100644 --- a/MLEM/Formatting/TokenizedString.cs +++ b/MLEM/Formatting/TokenizedString.cs @@ -100,7 +100,13 @@ namespace MLEM.Formatting { /// The scale that the string is drawn at /// The token under the target position public Token GetTokenUnderPos(Vector2 stringPos, Vector2 target, float scale) { - return this.Tokens.FirstOrDefault(t => t.GetArea(stringPos, scale).Any(r => r.Contains(target))); + foreach (var token in this.Tokens) { + foreach (var rect in token.GetArea(stringPos, scale)) { + if (rect.Contains(target)) + return token; + } + } + return null; } /// diff --git a/MLEM/Input/InputHandler.cs b/MLEM/Input/InputHandler.cs index 3122fee..1f239ce 100644 --- a/MLEM/Input/InputHandler.cs +++ b/MLEM/Input/InputHandler.cs @@ -363,7 +363,11 @@ namespace MLEM.Input { /// The modifier key /// If the modifier key is down public bool IsModifierKeyDown(ModifierKey modifier) { - return modifier.GetKeys().Any(this.IsKeyDown); + foreach (var key in modifier.GetKeys()) { + if (this.IsKeyDown(key)) + return true; + } + return false; } /// @@ -570,18 +574,30 @@ namespace MLEM.Input { } /// - public bool IsAnyDown(params GenericInput[] control) { - return control.Any(c => this.IsDown(c)); + public bool IsAnyDown(params GenericInput[] controls) { + foreach (var control in controls) { + if (this.IsDown(control)) + return true; + } + return false; } /// - public bool IsAnyUp(params GenericInput[] control) { - return control.Any(c => this.IsUp(c)); + public bool IsAnyUp(params GenericInput[] controls) { + foreach (var control in controls) { + if (this.IsUp(control)) + return true; + } + return false; } /// - public bool IsAnyPressed(params GenericInput[] control) { - return control.Any(c => this.IsPressed(c)); + public bool IsAnyPressed(params GenericInput[] controls) { + foreach (var control in controls) { + if (this.IsPressed(control)) + return true; + } + return false; } /// diff --git a/MLEM/Input/Keybind.cs b/MLEM/Input/Keybind.cs index 7d6d8a2..d1a61e9 100644 --- a/MLEM/Input/Keybind.cs +++ b/MLEM/Input/Keybind.cs @@ -89,7 +89,11 @@ namespace MLEM.Input { /// The index of the gamepad to query, or -1 to query all gamepads /// Whether this keybind is considered to be down public bool IsDown(InputHandler handler, int gamepadIndex = -1) { - return this.combinations.Any(c => c.IsDown(handler, gamepadIndex)); + foreach (var combination in this.combinations) { + if (combination.IsDown(handler, gamepadIndex)) + return true; + } + return false; } /// @@ -100,7 +104,11 @@ namespace MLEM.Input { /// The index of the gamepad to query, or -1 to query all gamepads /// Whether this keybind is considered to be pressed public bool IsPressed(InputHandler handler, int gamepadIndex = -1) { - return this.combinations.Any(c => c.IsPressed(handler, gamepadIndex)); + foreach (var combination in this.combinations) { + if (combination.IsPressed(handler, gamepadIndex)) + return true; + } + return false; } /// @@ -111,7 +119,11 @@ namespace MLEM.Input { /// The index of the gamepad to query, or -1 to query all gamepads /// Whether any of this keyboard's modifier keys are down public bool IsModifierDown(InputHandler handler, int gamepadIndex = -1) { - return this.combinations.Any(c => c.IsModifierDown(handler, gamepadIndex)); + foreach (var combination in this.combinations) { + if (combination.IsModifierDown(handler, gamepadIndex)) + return true; + } + return false; } /// @@ -198,7 +210,13 @@ namespace MLEM.Input { /// The index of the gamepad to query, or -1 to query all gamepads /// Whether this combination's modifiers are down public bool IsModifierDown(InputHandler handler, int gamepadIndex = -1) { - return this.Modifiers.Length <= 0 || this.Modifiers.Any(m => handler.IsDown(m, gamepadIndex)); + if (this.Modifiers.Length <= 0) + return true; + foreach (var modifier in this.Modifiers) { + if (handler.IsDown(modifier, gamepadIndex)) + return true; + } + return false; } ///