Skip to content

Commit

Permalink
small memory improvements in ConsoleString
Browse files Browse the repository at this point in the history
  • Loading branch information
adamabdelhamed committed Jan 5, 2025
1 parent 1b51b2b commit 0cee68d
Show file tree
Hide file tree
Showing 2 changed files with 166 additions and 33 deletions.
134 changes: 101 additions & 33 deletions PowerArgs/HelperTypesPublic/ConsoleString.cs
Original file line number Diff line number Diff line change
Expand Up @@ -347,13 +347,20 @@ public override string ToString()
{
return Value + "";
}
public ConsoleCharacter Darker
{
get
{
return new ConsoleCharacter(this.Value, this.ForegroundColor.Darker, this.BackgroundColor.Darker);
}
}

/// <summary>
/// ConsoleCharacters can be compared to other ConsoleCharacter instances or char values.
/// </summary>
/// <param name="obj">The ConsoleCharacter or char to compare to.</param>
/// <returns></returns>
public override bool Equals(object obj)
/// <summary>
/// ConsoleCharacters can be compared to other ConsoleCharacter instances or char values.
/// </summary>
/// <param name="obj">The ConsoleCharacter or char to compare to.</param>
/// <returns></returns>
public override bool Equals(object obj)
{
return obj is ConsoleCharacter other && Equals(other);
}
Expand Down Expand Up @@ -564,7 +571,7 @@ public ConsoleString Darker
var buffer = new ConsoleCharacter[this.Length];
for(var i = 0; i < Length; i++)
{
buffer[i] = new ConsoleCharacter(this[i].Value, this[i].ForegroundColor.Darker, this[i].BackgroundColor.Darker);
buffer[i] = this[i].Darker;
}
return new ConsoleString(buffer);
}
Expand All @@ -573,7 +580,20 @@ public ConsoleString Darker
/// <summary>
/// Returns true if all characters have the default foreground and background color
/// </summary>
public bool IsUnstyled => this.Where(c => c.ForegroundColor != DefaultForegroundColor || c.BackgroundColor != DefaultBackgroundColor).Count() == 0;
public bool IsUnstyled
{
get
{
for (var i = 0; i < characters.Length; i++)
{
if (characters[i].ForegroundColor != DefaultForegroundColor || characters[i].BackgroundColor != DefaultBackgroundColor)
{
return false;
}
}
return true;
}
}

/// <summary>
/// Creates a new ConsoleString from a collection of ConsoleCharacter objects
Expand Down Expand Up @@ -777,24 +797,54 @@ public ConsoleString ReplaceRegex(string regex, string toReplace, RGB? foregroun
return ret;
}

/// <summary>
/// Finds the index of a given substring in this ConsoleString.
/// </summary>
/// <param name="toFind">The substring to search for.</param>
/// <param name="comparison">Specifies how characters are compared</param>
/// <returns>The first index of the given substring or -1 if the substring was not found.</returns>
public int IndexOf(string toFind, StringComparison comparison = StringComparison.InvariantCulture)
/// <summary>
/// Finds the index of a given substring in this ConsoleString.
/// </summary>
/// <param name="toFind">The substring to search for.</param>
/// <param name="comparison">Specifies how characters are compared</param>
/// <returns>The first index of the given substring or -1 if the substring was not found.</returns>
public int IndexOf(string toFind, StringComparison comparison = StringComparison.InvariantCulture)
{
if (toFind == null)
return -1;

if (toFind.Length == 0)
return 0;

int toFindLength = toFind.Length;

for (int i = 0; i <= characters.Length - toFindLength; i++)
{
return this.ToString().ToConsoleString().IndexOf(toFind.ToConsoleString(), comparison);
bool match = true;

for (int j = 0; j < toFindLength; j++)
{
char currentChar = characters[i + j].Value;
char targetChar = toFind[j];

if (!CharEquals(currentChar, targetChar, comparison))
{
match = false;
break;
}
}

if (match)
{
return i;
}
}

/// <summary>
/// Finds the index of a given substring in this ConsoleString.
/// </summary>
/// <param name="toFind">The substring to search for. The styles of the strings must match.</param>
/// <param name="comparison">Specifies how characters are compared</param>
/// <returns>The first index of the given substring or -1 if the substring was not found.</returns>
public int IndexOf(ConsoleString toFind, StringComparison comparison = StringComparison.InvariantCulture)
return -1;
}

/// <summary>
/// Finds the index of a given substring in this ConsoleString.
/// </summary>
/// <param name="toFind">The substring to search for. The styles of the strings must match.</param>
/// <param name="comparison">Specifies how characters are compared</param>
/// <returns>The first index of the given substring or -1 if the substring was not found.</returns>
public int IndexOf(ConsoleString toFind, StringComparison comparison = StringComparison.InvariantCulture)
{
if (toFind == null) return -1;
if (toFind == ConsoleString.Empty) return 0;
Expand All @@ -817,14 +867,26 @@ public int IndexOf(ConsoleString toFind, StringComparison comparison = StringCom

return -1;
}

/// <summary>
/// Determines if this ConsoleString starts with the given string
/// </summary>
/// <param name="substr">the substring to look for</param>
/// <param name="comparison">Specifies how characters are compared</param>
/// <returns>true if this ConsoleString starts with the given substring, false otherwise</returns>
public bool StartsWith(string substr, StringComparison comparison = StringComparison.InvariantCulture)
private bool CharEquals(char a, char b, StringComparison comparison)
{
switch (comparison)
{
case StringComparison.CurrentCultureIgnoreCase:
case StringComparison.InvariantCultureIgnoreCase:
case StringComparison.OrdinalIgnoreCase:
return char.ToLowerInvariant(a) == char.ToLowerInvariant(b);
case StringComparison.Ordinal:
default:
return a == b;
}
}
/// <summary>
/// Determines if this ConsoleString starts with the given string
/// </summary>
/// <param name="substr">the substring to look for</param>
/// <param name="comparison">Specifies how characters are compared</param>
/// <returns>true if this ConsoleString starts with the given substring, false otherwise</returns>
public bool StartsWith(string substr, StringComparison comparison = StringComparison.InvariantCulture)
{
return IndexOf(substr, comparison) == 0;
}
Expand Down Expand Up @@ -1107,7 +1169,12 @@ public void WriteLine()
/// <returns></returns>
public override string ToString()
{
return new string(this.Select(c => c.Value).ToArray());
var buffer = new char[Length];
for (var i = 0; i < Length; i++)
{
buffer[i] = characters[i].Value;
}
return new string(buffer);
}

/// <summary>
Expand Down Expand Up @@ -1775,8 +1842,9 @@ public ConsoleString ToWhite(RGB? bg = null, bool underlined = false)
private ConsoleString To(RGB color, RGB? bg, bool underlined)
{
List<ConsoleCharacter> chars = new List<ConsoleCharacter>();
foreach (var c in this)
for (int i = 0; i < characters.Length; i++)
{
ConsoleCharacter c = characters[i];
chars.Add(new ConsoleCharacter(c.Value, color, bg ?? c.BackgroundColor, underlined));
}

Expand Down
65 changes: 65 additions & 0 deletions PowerArgsTestCore/Core/ConsoleStringTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,71 @@ public void TestIndexOf()
Assert.AreEqual(1010,s.IndexOf("!"));
}

[TestMethod]
public void TestIndexOfAdditionalCases()
{
// Test with a single character string
ConsoleString s = new ConsoleString("abcdefg");
Assert.AreEqual(0, s.IndexOf("a"));
Assert.AreEqual(6, s.IndexOf("g"));
Assert.AreEqual(-1, s.IndexOf("z"));

// Test with repeating characters
s = new ConsoleString("aaaaaa");
Assert.AreEqual(0, s.IndexOf("a"));

Assert.AreEqual(-1, s.IndexOf("b"));

// Test with overlapping patterns
s = new ConsoleString("abababab");
Assert.AreEqual(0, s.IndexOf("abab"));
Assert.AreEqual(1, s.IndexOf("baba"));
Assert.AreEqual(-1, s.IndexOf("abaabab"));

// Test case sensitivity
s = new ConsoleString("AbCdEfGh");
Assert.AreEqual(0, s.IndexOf("a", StringComparison.OrdinalIgnoreCase));
Assert.AreEqual(-1, s.IndexOf("a", StringComparison.Ordinal));
Assert.AreEqual(4, s.IndexOf("Ef", StringComparison.OrdinalIgnoreCase));
Assert.AreEqual(-1, s.IndexOf("ef", StringComparison.Ordinal));

// Test with spaces
s = new ConsoleString("hello world");
Assert.AreEqual(6, s.IndexOf("world"));
Assert.AreEqual(5, s.IndexOf(" "));
Assert.AreEqual(-1, s.IndexOf("world!"));

// Test with special characters
s = new ConsoleString("!@#$%^&*()");
Assert.AreEqual(0, s.IndexOf("!"));
Assert.AreEqual(5, s.IndexOf("^"));
Assert.AreEqual(-1, s.IndexOf("abc"));

// Test with empty ConsoleString
s = new ConsoleString("");
Assert.AreEqual(-1, s.IndexOf("a"));
Assert.AreEqual(0, s.IndexOf(""));


// Test with partial matches at the end
s = new ConsoleString("abcdefgh");
Assert.AreEqual(-1, s.IndexOf("ghijk"));
Assert.AreEqual(6, s.IndexOf("gh"));

// Test with very large input
s = new ConsoleString(new string('a', 100000) + "b");
Assert.AreEqual(100000, s.IndexOf("b"));
Assert.AreEqual(-1, s.IndexOf("c"));


// Test with mixed case ConsoleString
s = new ConsoleString("AbCdEfGhIj");
Assert.AreEqual(0, s.IndexOf("AbCdEf", StringComparison.Ordinal));
Assert.AreEqual(0, s.IndexOf("abcdef", StringComparison.OrdinalIgnoreCase));
Assert.AreEqual(-1, s.IndexOf("abcdef", StringComparison.Ordinal));
}


[TestMethod]
public void TestIndexOfCustomComparison()
{
Expand Down

0 comments on commit 0cee68d

Please sign in to comment.