Skip to content

Commit

Permalink
Reduce allocations in Styling API (#134)
Browse files Browse the repository at this point in the history
* Reduce allocations in Styling API

* Remove the overload of `TextStyle.opCall` that takes a sink

We should make `StyledText` a range instead.
  • Loading branch information
SirNickolas authored Dec 1, 2023
1 parent e72cb56 commit a8623c1
Showing 1 changed file with 45 additions and 23 deletions.
68 changes: 45 additions & 23 deletions source/argparse/ansi.d
Original file line number Diff line number Diff line change
Expand Up @@ -52,38 +52,47 @@ private enum Color

package struct TextStyle
{
private ubyte[] style;
private string style = prefix;

private this(return scope inout(ubyte)[] st) scope inout nothrow pure @safe @nogc
private this(const(ubyte)[] st...) scope inout nothrow pure @safe
{
style = st;
}
private this(ubyte st) scope inout nothrow pure @safe
{
if(st != 0)
style = [st];
import std.algorithm.iteration: joiner, map;
import std.array: appender;
import std.conv: toChars;
import std.utf: byCodeUnit;

auto a = appender(prefix);
a ~= st.map!(_ => uint(_).toChars).joiner(separator.byCodeUnit);
style = a[];
}

private auto opBinary(string op : "~")(ubyte other) inout
private ref opOpAssign(string op : "~")(ubyte other)
{
return other != 0 ? inout TextStyle(style ~ other) : this;
import std.array: appender;
import std.conv: toChars;

if(other != 0)
{
auto a = appender(style);
if(style.length != prefix.length)
a ~= separator;
a ~= uint(other).toChars;
style = a[];
}
return this;
}

public auto opCall(string str) const
{
import std.conv: text, to;
import std.algorithm: joiner, map;
import std.utf: byCodeUnit;

if(style.length == 0 || str.length == 0)
if(str.length == 0 || style.length == prefix.length)
return str;

return text(prefix, style.map!(_ => _.to!string.byCodeUnit).joiner(separator.byCodeUnit), suffix, str, reset);
return style ~ suffix ~ str ~ reset;
}
}

nothrow pure @safe unittest
{
assert(TextStyle.init("foo") == "foo");
assert(TextStyle([])("foo") == "foo");
assert(TextStyle([Font.bold])("foo") == "\033[1mfoo\033[m");
assert(TextStyle([Font.bold, Font.italic])("foo") == "\033[1;3mfoo\033[m");
Expand All @@ -107,6 +116,7 @@ package struct StyledText
{
return toString() ~ rhs;
}

// lhs ~ this
string opBinaryRight(string op : "~")(string lhs) const
{
Expand All @@ -122,27 +132,33 @@ nothrow pure @safe unittest
const ubyte[1] data = [Font.bold];
scope c = const TextStyle(data);
assert((const StyledText(c, "foo")).toString() == c("foo"));

immutable foo = StyledText(s, "foo");
assert(foo ~ "bar" == s("foo") ~ "bar");
assert("bar" ~ foo == "bar" ~ s("foo"));
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

package template StyleImpl(ubyte styleCode)
{
public auto StyleImpl()
immutable style = TextStyle(styleCode);

public TextStyle StyleImpl()
{
return TextStyle(styleCode);
return style;
}
public auto StyleImpl(TextStyle otherStyle)
{
return otherStyle ~ styleCode;
return otherStyle ~= styleCode;
}
public auto StyleImpl(string text)
{
return StyledText(TextStyle(styleCode), text);
return StyledText(style, text);
}
public auto StyleImpl(TextStyle otherStyle, string text)
{
return StyledText(otherStyle ~ styleCode, text);
return StyledText(otherStyle ~= styleCode, text);
}
}

Expand Down Expand Up @@ -199,6 +215,12 @@ nothrow pure @safe unittest
assert(bold.italic.red.onWhite("foo").toString() == "\033[1;3;31;107mfoo\033[m");
}

nothrow pure @safe @nogc unittest
{
auto style = bold;
style = italic; // Should be able to reassign.
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

public auto getUnstyledText(string text)
Expand All @@ -217,7 +239,7 @@ package size_t getUnstyledTextLength(string text)

package size_t getUnstyledTextLength(StyledText text)
{
return getUnstyledTextLength(text.toString());
return getUnstyledTextLength(text.text);
}

unittest
Expand Down

0 comments on commit a8623c1

Please sign in to comment.