Re: Handling arbitrary char ranges
On Wednesday, 20 April 2016 at 20:00:58 UTC, ag0aep6g wrote: Maybe I've missed it, but you didn't say where the HTTP type comes from, did you? std.net.curl: https://dlang.org/phobos/std_net_curl.html#.HTTP (Sorry, I assumed that was a given since it's a standard library type. Poor assumption, perhaps.) I'd rather not write my own cURL wrapper. Do you think it would be worthwhile starting a PR for Phobos to get it changed to ubyte[]? A reading of https://dlang.org/spec/arrays.html indicates the main difference is that that GC crawls void[], but I would think that wouldn't matter for a short-lived buffer being shoveled into libcurl, which is, by nature, a copy of the same data somewhere else in your program...
Re: Handling arbitrary char ranges
On Wednesday, 20 April 2016 at 19:29:22 UTC, ag0aep6g wrote: Maybe use ubyte[] for the buffer type instead. I don't have an option here, do I? I assume HTTP.onSend doesn't take a `delegate size_t(ubyte[])` insetad of a `delegate size_t(void[])`, and that the former isn't implicitly convertible to the latter. I think your problems come more from wanting to accept string, which simply isn't a char range Is this due solely to the "auto-decode" behavior? Generally, (except apparently in this case) don't arrays of type T qualify as InputRanges of type T?
Handling arbitrary char ranges
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)
Re: Detecting premature end of spawned threads with std.concurrency
On Friday, 4 September 2015 at 08:33:08 UTC, Marc Schütz wrote: They're called `OwnerTerminated` and `OwnerFailed` with an "r". No, that's received by the child if the owning thread exits. I'm talking about the "parent" thread attempting to send to a child thread that has exited. Relevant passage in TDPL: https://books.google.com/books?id=bn7GNq6fiIUC=PT602
Detecting premature end of spawned threads with std.concurrency
TDPL suggests that calls to std.concurrency.send will fail with an "OwnedTerminated" or "OwnedFailed" exception if the destination thread has exited, but neither the docs nor the current Phobos implementation make any mention of such exceptions. Thinking the information was just outdated, I searched the Git history of Phobos for such types, but found nothing. What are current best practices for determining if a child thread has died? And should these types be added to TDPL errata?
Coercing ranges to the same type
Say I'm trying to expand an array of file and directory paths (such as ones given as command line args) into a range of file paths I can iterate over. A simplified example might be: auto getEntries(string[] paths, bool recursive) { auto files = paths.filter!(p = p.isFile); if (recursive) { auto expandedDirs = paths .filter!(p = p.isDir) .map!(p = dirEntries(p, SpanMode.depth, false)) .joiner .map!(de = de.name); // back to strings return chain(files, expandedDirs); } else { return files; } } Even though both return statements return a range of strings, this doesn't compile because the result of `chain` is a different type than the result of `filter`. Is there some generic range I could coerce both ranges to in order to have the same return type and make this work? .array is a non-starter since it throws out the ranges' laziness.
Re: Coercing ranges to the same type
As it turns out, inputRangeObject does an excellent job at this task. The solution then becomes something like: InputRange!string getEntries(string[] paths, bool recursive) { auto files = paths.filter!(p = p.isFile); if (recursive) { auto expandedDirs = paths .filter!(p = p.isDir) .map!(p = dirEntries(p, SpanMode.depth, false)) .joiner .map!(de = de.name); return inputRangeObject(chain(files, expandedDirs)); } else { foreach (dir; paths.filter!(p = p.isDir)) stderr.writeln(omitting directory , dir); return inputRangeObject(files); } }
Re: Coercing ranges to the same type
On Monday, 6 July 2015 at 21:35:53 UTC, Alex Parrill wrote: They aren't actually the same types I understand the problem - I was just wondering if there was a standard library solution to this or if I would have to roll my own. use a class wrapper in std.range.interface [1]. [1]: http://dlang.org/phobos/std_range_interfaces.html I think I'll go with this one, since the use case would be similar to the '-r' flag in standard Unix utils (copy, mv, etc.) where the user specifies if they want to recurse through provided directories.
Re: Distinguish recursive Templates
On Friday, 22 May 2015 at 21:13:50 UTC, Manfred Nowak wrote: How can one determine the recursion depth for templated types? Example code: import std.stdio; class Set(T){ override string toString(){ return Set; } } void main(){ auto s0= new Set!uint; writeln( s0); // writes Set auto s1= new Set!(Set!uint); writeln( s1); // should write SetSet } Why should the last line write SetSet? (It doesn't.) toString isn't making any use of the template argument T, so no recursion occurs.
Mimicking C++'s indexing behavior in D associative arrays
In C++, the index operator for maps will either return a reference to the existing value if the key can be found, or a reference to a new, default-initialized value if one with the given key cannot be found. In D, an exception is thrown instead when a value with the given key cannot be found, similar to unordered_map::at in C++. So if I want to mimic the same behavior (get or initialize to default), I have to do something like // Assume bar is some associative array of type Foo[string] Foo* value = key in bar; if (value) { bar[key] = Foo.init; value = bar[key]; } This seems sub-optimal, given that in involves three hashes (two lookups and one insertion). Is there a more efficient or cleaner way to do so?
Re: Mimicking C++'s indexing behavior in D associative arrays
On Wednesday, 18 February 2015 at 00:21:11 UTC, Matt Kline wrote: if (value) { should of course be if (!value) { Sorry for the typo.