Output range with custom string type

Moritz Maxeiner via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Mon Aug 28 14:45:36 PDT 2017


On Monday, 28 August 2017 at 14:27:19 UTC, Jacob Carlborg wrote:
> I'm working on some code that sanitizes and converts values of 
> different types to strings. I thought it would be a good idea 
> to wrap the sanitized string in a struct to have some type 
> safety. Ideally it should not be possible to create this type 
> without going through the sanitizing functions.
>
> The problem I have is that I would like these functions to push 
> up the allocation decision to the caller. Internally these 
> functions use formattedWrite. I thought the natural design 
> would be that the sanitize functions take an output range and 
> pass that to formattedWrite.
>
> [...]
>
> Any suggestions how to fix this or a better idea?

If you want the caller to be just in charge of allocation, that's 
what std.experimental.allocator provides. In this case, I would 
polish up the old "format once to get the length, allocate, 
format second time into allocated buffer" method used with 
snprintf for D:

--- test.d ---
import std.stdio;
import std.experimental.allocator;

struct CountingOutputRange
{
private:
	size_t _count;
public:
	size_t count() { return _count; }
	void put(char c) { _count++; }
}

char[] sanitize(string value, IAllocator alloc)
{
	import std.format : formattedWrite, sformat;

	CountingOutputRange r;
	(&r).formattedWrite!"'%s'"(value); // do not copy the range

	auto s = alloc.makeArray!char(r.count);
	scope (failure) alloc.dispose(s);

         // This should only throw if the user provided allocator 
returned less
         // memory than was requested
	return s.sformat!"'%s'"(value);
}

void main()
{
	auto s = sanitize("foo", theAllocator);
	scope (exit) theAllocator.dispose(s);
	writeln(s);
}
--------------


More information about the Digitalmars-d-learn mailing list