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