string to character code hex string

Moritz Maxeiner via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Sat Sep 2 10:45:30 PDT 2017


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];
}
---


More information about the Digitalmars-d-learn mailing list