Re: Handling arbitrary char ranges

2016-04-20 Thread Matt Kline via Digitalmars-d-learn

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

2016-04-20 Thread Matt Kline via Digitalmars-d-learn

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

2016-04-20 Thread Matt Kline via Digitalmars-d-learn
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

2015-09-04 Thread Matt Kline via Digitalmars-d-learn

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

2015-09-03 Thread Matt Kline via Digitalmars-d-learn
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

2015-07-06 Thread Matt Kline via Digitalmars-d-learn
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

2015-07-06 Thread Matt Kline via Digitalmars-d-learn
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

2015-07-06 Thread Matt Kline via Digitalmars-d-learn

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

2015-05-22 Thread Matt Kline via Digitalmars-d-learn

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

2015-02-17 Thread Matt Kline via Digitalmars-d-learn
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

2015-02-17 Thread Matt Kline via Digitalmars-d-learn

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.