Skip to content

Commit

Permalink
Reduce allocations in Styling API
Browse files Browse the repository at this point in the history
  • Loading branch information
SirNickolas committed Nov 29, 2023
1 parent e72cb56 commit 0680bad
Showing 1 changed file with 99 additions and 25 deletions.
124 changes: 99 additions & 25 deletions source/argparse/ansi.d
Original file line number Diff line number Diff line change
Expand Up @@ -52,38 +52,65 @@ 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;
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 this(ubyte st) scope inout nothrow pure @safe

private ref opOpAssign(string op : "~")(ubyte other)
{
if(st != 0)
style = [st];
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;
}

private auto opBinary(string op : "~")(ubyte other) inout
public auto opCall(string str) const
{
return other != 0 ? inout TextStyle(style ~ other) : this;
if(str.length == 0 || style.length == prefix.length)
return str;
return style ~ suffix ~ str ~ reset;
}

public auto opCall(string str) const
public void opCall(W)(ref W writer, const(char)[] str) const
{
import std.conv: text, to;
import std.algorithm: joiner, map;
import std.utf: byCodeUnit;
import std.range.primitives: put;

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

return text(prefix, style.map!(_ => _.to!string.byCodeUnit).joiner(separator.byCodeUnit), suffix, str, reset);
immutable enabled = style.length != prefix.length;
if(enabled)
{
put(writer, style);
put(writer, suffix);
}
put(writer, str);
if(enabled)
put(writer, 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 @@ -103,14 +130,25 @@ package struct StyledText
}

// this ~ rhs
string opBinary(string op : "~")(string rhs) const
string opBinary(string op : "~")(const(char)[] rhs) const
{
return toString() ~ rhs;
import std.array: appender;

auto a = appender!string;
style(a, text);
a ~= rhs;
return a[];
}

// lhs ~ this
string opBinaryRight(string op : "~")(string lhs) const
string opBinaryRight(string op : "~")(const(char)[] lhs) const
{
return lhs ~ toString();
import std.array: appender;

auto a = appender!string;
a ~= lhs;
style(a, text);
return a[];
}
}

Expand All @@ -122,27 +160,41 @@ 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);
}
public void StyleImpl(W)(ref W writer, const(char)[] text)
{
style(writer, text);
}
public void StyleImpl(W)(TextStyle otherStyle, ref W writer, const(char)[] text)
{
(otherStyle ~= styleCode)(writer, text);
}
}

Expand Down Expand Up @@ -199,6 +251,28 @@ 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;
}

nothrow pure @safe unittest
{
import std.array: appender;

immutable boldItalic = bold.italic;

auto sink = appender!string;
bold(sink, "A");
bold(sink, ""); // No-op.
sink ~= 'B';
boldItalic(sink, "C");
sink ~= 'D';
boldItalic.red(sink, "E");
assert(sink[] == "\033[1mA\033[mB\033[1;3mC\033[mD\033[1;3;31mE\033[m");
}

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

public auto getUnstyledText(string text)
Expand All @@ -217,7 +291,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 0680bad

Please sign in to comment.