On Saturday, 2 September 2017 at 16:23:57 UTC, bitwise wrote:
On Saturday, 2 September 2017 at 15:53:25 UTC, bitwise wrote:
[...]

This seems to work well enough.

string toAsciiHex(string str)
{
    import std.array : appender;

    auto ret = appender!string(null);
    ret.reserve(str.length * 2);
    foreach(c; str) ret.put(format!"%x"(c));
    return ret.data;
}

Note: Each of those format calls is going to allocate a new string, followed by put copying that new string's content over into the appender, leaving you with \theta(str.length) tiny memory chunks that aren't used anymore for the GC to eventually collect.

If this (unnecessary waste) is of concern to you (and from the fact that you used ret.reserve I assume it is), then the easy fix is to use `sformat` instead of `format`:

---
string toHex(string str)
{
        import std.format : sformat;
        import std.exception: assumeUnique;

        auto   ret = new char[str.length * 2];
        size_t len;

        foreach (c; str)
        {
                auto slice = sformat!"%x"(ret[len..$], c);
                //auto slice = toHex(ret[len..$], c);
                assert (slice.length <= 2);
                len += slice.length;
        }
        
        return ret[0..len].assumeUnique;
}
---

If you want to cut out the format import entirely, notice the `auto slice = toHex...` line, which can be implemented like this (always returns two chars):

---
char[] toHex(char[] buf, char c)
{
        import std.ascii : lowerHexDigits;

        assert (buf.length >= 2);
        buf[0] = lowerHexDigits[(c & 0xF0) >> 4];
        buf[1] = lowerHexDigits[c & 0x0F];

        return buf[0..2];
}
---

Reply via email to