Handling arbitrary char ranges
Matt Kline via Digitalmars-d-learn
digitalmars-d-learn at puremagic.com
Wed Apr 20 10:09:29 PDT 2016
I'm doing some work with a REST API, and I wrote a simple utility
function that sets an HTTP's onSend callback to send a string:
@property outgoingString(ref HTTP request, const(void)[] sendData)
{
import std.algorithm : min;
request.contentLength = sendData.length;
auto remainingData = sendData;
request.onSend = delegate size_t(void[] buf)
{
size_t minLen = min(buf.length, remainingData.length);
if (minLen == 0) return 0;
buf[0..minLen] = remainingData[0..minLen];
remainingData = remainingData[minLen..$];
return minLen;
};
}
I then wrote a function that lazily strips some whitespace from
strings I send. To accommodate this change, I need to modify the
function above so it takes arbitrary ranges of char elements. I
assumed this would be a modest task, but it's been an exercise in
frustration. The closest I got was:
@property void outgoingString(T)(ref HTTP request, T sendData)
if (isInputRange!T) // #1
{
static if (isArray!T) {
import std.algorithm : min;
request.contentLength = sendData.length;
request.onSend = delegate size_t(void[] buf)
{
size_t minLen = min(buf.length, sendData.length);
if (minLen == 0) return 0;
buf[0..minLen] = sendData[0..minLen]; // #2
sendData = sendData[minLen..$];
return minLen;
};
}
else {
auto bcu = byCodeUnit(sendData); // #3
static assert(is(ElementType!bcu : char), // #4
__FUNCTION__ ~ " only takes char ranges, not "
~ typeof(bcu.front).stringof);
// Length unknown; chunked transfer
request.contentLength = ulong.max;
request.onSend = delegate size_t(void[] buf)
{
for (size_t i = 0; i < buf.length; ++i) {
if (bcu.empty) return i;
buf[i] = bcu.front; // #5
bcu.popFront();
}
return buf.length;
};
}
}
To each of the commented lines above,
1. What is the idiomatic way to constrain the function to only
take char ranges? One might naïvely add `is(ElementType!T :
char)`, but that falls on its face due to strings "auto-decoding"
their elements to dchar. (More on that later.)
2. The function fails to compile, issuing, "cannot implicitly
convert expression (sendData[0..minLen]) of type string to
void[]" on this line. I assume this has to do with the
immutability of string elements. Specifying a non-const array of
const elements is as simple as `const(void)[]`, but how does one
do this here, with a template argument?
3. Is this needed, or is auto-decoding behavior specific to char
arrays and not other char ranges?
4. Is this a sane approach to make sure I'm dealing with ranges
of chars? Do I need to use `Unqual` to deal with const or
immutable elements?
5. This fails, claiming the right hand side can't be converted to
type void. Casting to ubyte doesn't help - so how *does* one
write to an element of a void array?
Am I making things harder than they have to be? Or is dealing
with an arbitrary ranges of chars this complex? I've lost count
of times templated code wouldn't compile because dchar was
sneaking in somewhere... at least I'm in good company.
(http://forum.dlang.org/post/m01r3d$1frl$1@digitalmars.com)
More information about the Digitalmars-d-learn
mailing list