From 9490dabbd6304aa56ab9b9067500eb17062a2b6b Mon Sep 17 00:00:00 2001 From: Matt Nadareski Date: Sun, 24 Nov 2024 23:16:11 -0500 Subject: [PATCH] Overhaul matching extensions --- SabreTools.Matching/Extensions.cs | 171 ++++++++++++++++-------------- 1 file changed, 91 insertions(+), 80 deletions(-) diff --git a/SabreTools.Matching/Extensions.cs b/SabreTools.Matching/Extensions.cs index fc4fba9..5beb4e1 100644 --- a/SabreTools.Matching/Extensions.cs +++ b/SabreTools.Matching/Extensions.cs @@ -17,37 +17,52 @@ namespace SabreTools.Matching /// /// Find all positions of one array in another, if possible, if possible /// - public static List FindAllPositions(this byte[] stack, byte[]? needle, int start = 0, int end = -1) + /// Byte array to search within + /// Byte array representing the search value + /// Optional starting position in the stack, defaults to 0 + /// Optional ending position in the stack, defaults to -1 (length of stack) + public static List FindAllPositions(this byte[] stack, byte[] needle, int start = 0, int end = -1) { - // Convert the needle to a nullable byte array - byte?[]? nullableNeedle = null; - if (needle != null) - nullableNeedle = Array.ConvertAll(needle, b => (byte?)b); - + byte?[] nullableNeedle = Array.ConvertAll(needle, b => (byte?)b); return FindAllPositions(stack, nullableNeedle, start, end); } /// /// Find all positions of one array in another, if possible, if possible /// - public static List FindAllPositions(this byte[] stack, byte?[]? needle, int start = 0, int end = -1) + /// Byte array to search within + /// Byte array representing the search value + /// Optional starting position in the stack, defaults to 0 + /// Optional ending position in the stack, defaults to -1 (length of stack) + public static List FindAllPositions(this byte[] stack, byte?[] needle, int start = 0, int end = -1) { // Get the outgoing list List positions = []; - // Initialize the loop variables - int lastPosition = start; - var matcher = new ContentMatch(needle, end: end); + // Validate the start and end values + if (start < 0 || start >= stack.Length) + return positions; + if (end < -1 || (end != -1 && end < start) || end > stack.Length) + return positions; - // Loop over and get all positions - while (true) + // Normalize the end value, if necessary + if (end == -1) + end = stack.Length; + + // Loop while there is data to check + while (start < end) { - matcher.Start = lastPosition; - lastPosition = matcher.Match(stack, false); - if (lastPosition < 0) + // Create a new matcher for this segment + var matcher = new ContentMatch(needle, start, end); + + // Get the next matching position + int position = matcher.Match(stack, reverse: false); + if (position < 0) break; - positions.Add(lastPosition); + // Append the position and reset the start index + positions.Add(position); + start = position; } return positions; @@ -56,115 +71,111 @@ namespace SabreTools.Matching /// /// Find the first position of one array in another, if possible /// - public static bool FirstPosition(this byte[] stack, byte[]? needle, out int position, int start = 0, int end = -1) + /// Byte array to search within + /// Byte array representing the search value + /// Optional starting position in the stack, defaults to 0 + /// Optional ending position in the stack, defaults to -1 (length of stack) + public static int FirstPosition(this byte[] stack, byte[] needle, int start = 0, int end = -1) { - // Convert the needle to a nullable byte array - byte?[]? nullableNeedle = null; - if (needle != null) - nullableNeedle = Array.ConvertAll(needle, b => (byte?)b); - - return FirstPosition(stack, nullableNeedle, out position, start, end); + byte?[] nullableNeedle = Array.ConvertAll(needle, b => (byte?)b); + return FirstPosition(stack, nullableNeedle, start, end); } /// /// Find the first position of one array in another, if possible /// - public static bool FirstPosition(this byte[] stack, byte?[]? needle, out int position, int start = 0, int end = -1) + /// Byte array to search within + /// Byte array representing the search value + /// Optional starting position in the stack, defaults to 0 + /// Optional ending position in the stack, defaults to -1 (length of stack) + public static int FirstPosition(this byte[] stack, byte?[] needle, int start = 0, int end = -1) { var matcher = new ContentMatch(needle, start, end); - position = matcher.Match(stack, false); - return position >= 0; + return matcher.Match(stack, reverse: false); } /// /// Find the last position of one array in another, if possible /// - public static bool LastPosition(this byte[] stack, byte[]? needle, out int position, int start = 0, int end = -1) + /// Byte array to search within + /// Byte array representing the search value + /// Optional starting position in the stack, defaults to 0 + /// Optional ending position in the stack, defaults to -1 (length of stack) + public static int LastPosition(this byte[] stack, byte[] needle, int start = 0, int end = -1) { - // Convert the needle to a nullable byte array - byte?[]? nullableNeedle = null; - if (needle != null) - nullableNeedle = Array.ConvertAll(needle, b => (byte?)b); - - return LastPosition(stack, nullableNeedle, out position, start, end); + byte?[] nullableNeedle = Array.ConvertAll(needle, b => (byte?)b); + return LastPosition(stack, nullableNeedle, start, end); } /// /// Find the last position of one array in another, if possible /// - public static bool LastPosition(this byte[] stack, byte?[]? needle, out int position, int start = 0, int end = -1) + /// Byte array to search within + /// Byte array representing the search value + /// Optional starting position in the stack, defaults to 0 + /// Optional ending position in the stack, defaults to -1 (length of stack) + public static int LastPosition(this byte[] stack, byte?[] needle, int start = 0, int end = -1) { var matcher = new ContentMatch(needle, start, end); - position = matcher.Match(stack, true); - return position >= 0; + return matcher.Match(stack, reverse: true); } /// - /// See if a byte array starts with another + /// Check if a byte array starts with another /// - public static bool StartsWith(this byte[] stack, byte[]? needle, bool exact = false) + /// Byte array to search within + /// Byte array representing the search value + public static bool StartsWith(this byte[] stack, byte[] needle) { - // If we have any invalid inputs, we return false - if (needle == null - || stack.Length == 0 || needle.Length == 0 - || needle.Length > stack.Length - || (exact && stack.Length != needle.Length)) - { - return false; - } - - return FirstPosition(stack, needle, out int _, start: 0, end: 1); + byte?[] nullableNeedle = Array.ConvertAll(needle, b => (byte?)b); + return StartsWith(stack, nullableNeedle); } /// - /// See if a byte array starts with another + /// Check if a byte array starts with another /// - public static bool StartsWith(this byte[] stack, byte?[]? needle, bool exact = false) + /// Byte array to search within + /// Byte array representing the search value + public static bool StartsWith(this byte[] stack, byte?[] needle) { - // If we have any invalid inputs, we return false - if (needle == null - || stack.Length == 0 || needle.Length == 0 - || needle.Length > stack.Length - || (exact && stack.Length != needle.Length)) - { + // If either the stack or needle are 0-length + if (stack.Length == 0 || needle.Length == 0) return false; - } - return FirstPosition(stack, needle, out int _, start: 0, end: 1); + // If the needle is longer than the stack + if (needle.Length > stack.Length) + return false; + + return FirstPosition(stack, needle, start: 0, end: 1) > -1; } /// - /// See if a byte array ends with another + /// Check if a byte array ends with another /// - public static bool EndsWith(this byte[] stack, byte[]? needle, bool exact = false) + /// Byte array to search within + /// Byte array representing the search value + public static bool EndsWith(this byte[] stack, byte[] needle) { - // If we have any invalid inputs, we return false - if (needle == null - || stack.Length == 0 || needle.Length == 0 - || needle.Length > stack.Length - || (exact && stack.Length != needle.Length)) - { - return false; - } - - return FirstPosition(stack, needle, out int _, start: stack.Length - needle.Length); + byte?[] nullableNeedle = Array.ConvertAll(needle, b => (byte?)b); + return EndsWith(stack, nullableNeedle); } /// - /// See if a byte array ends with another + /// Check if a byte array ends with another /// - public static bool EndsWith(this byte[] stack, byte?[]? needle, bool exact = false) + /// Byte array to search within + /// Byte array representing the search value + public static bool EndsWith(this byte[] stack, byte?[] needle) { - // If we have any invalid inputs, we return false - if (needle == null - || stack.Length == 0 || needle.Length == 0 - || needle.Length > stack.Length - || (exact && stack.Length != needle.Length)) - { + // If either the stack or needle are 0-length + if (stack.Length == 0 || needle.Length == 0) return false; - } - return FirstPosition(stack, needle, out int _, start: stack.Length - needle.Length); + // If the needle is longer than the stack + if (needle.Length > stack.Length) + return false; + + return FirstPosition(stack, needle, start: stack.Length - needle.Length) > -1; } } } \ No newline at end of file