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.
Here's a really simple example:
import std.stdio : writeln;
struct Range
{
void put(char c)
{
writeln(c);
}
}
void sanitize(OutputRange)(string value, OutputRange range)
{
import std.format : formattedWrite;
range.formattedWrite!"'%s'"(value);
}
void main()
{
Range range;
sanitize("foo", range);
}
The problem now is that the data is passed one char at the time
to the range. Meaning that if the user implements a custom
output range, the user is in full control of the data. It will
now be very easy for the user to make a mistake or manipulate
the data on purpose. Making the whole idea of the sanitized
type pointless.
Any suggestions how to fix this or a better idea?
Q is it an option to let the caller provide all the storage in an
oversized fixed-length buffer? You could add a second helper
function to compute and return a suitable safely pessimistic ott
max value for the length reqd which could be called once
beforehand to establish the reqd buffer size (or check it). This
is the technique I am using right now. My sizing function is
ridiculously fast as I am lucky in the particular use-case.