Was: Re: Vote for std.process
Vladimir Panteleev
vladimir at thecybershadow.net
Fri Apr 12 08:29:19 PDT 2013
On Friday, 12 April 2013 at 14:58:10 UTC, Manu wrote:
> I didn't see any attempt to index the array by key in this
> case. That's
> what an AA is for, and it's not being used here, so it's not a
> job for an
> AA.
Sorry, not following.
Are you suggesting to use a dynamic array for creating processes,
but an associative array for examining the current process's
environment?
> I wouldn't use env ~= "FOO=BAR";
> I would use env ~= EnvVar("FOO", "BAR");
> Or whatever key/value pair structure you like.
OK, but I don't see how it changes your argument. Also, you
mentioned string[] earlier.
> Well it seemed appropriate. I can't understand what's so wildly
> complex
> that it would make code utterly unmaintainable, and error prone.
I did not say it would be _utterly_ unmaintainable or error
prone. Just more so.
> It starts as soon as the majority agree it's important enough
> to enforce.
> Although I think a tool like: char[len] stackString; would be a
> super-useful tool to make this considerably more painless. Some
> C compilers
> support this.
I believe this is the feature:
http://en.wikipedia.org/wiki/Variable-length_array
It is part of C99.
-------------------------------------------------------------
Earlier today, I wrote:
> Please rewrite some part of std.process with performance in
> mind, and post it here for review. This way, we can analyze the
> benefits and drawbacks based on a concrete example, instead of
> vapor and hot air.
I've tried doing this myself, for the bit of code you brought up
(constructing environment variables). Here's what I ended up with:
-------------------------------------------------------------
import std.array;
private struct StaticAppender(size_t SIZE, T)
{
T[SIZE] buffer = void;
Appender!(T[]) appender;
alias appender this;
}
/// Returns a struct containing a fixed-size buffer and an
/// appender. The appender will use the buffer (which has
/// SIZE elements) until it runs out of space, at which
/// point it will reallocate itself on the heap.
auto staticAppender(size_t SIZE, T)()
{
StaticAppender!(SIZE, T) result;
result.appender = appender(result.buffer[]);
return result;
}
/// Allows allocating a T[] given a size.
/// Contains a fized-size buffer of T elements with SIZE
/// length. When asked to allocate an array with
/// length <= than SIZE, the buffer is used instead of
/// the heap.
struct StaticArray(size_t SIZE, T)
{
T[SIZE] buffer = void;
T[] get(size_t size)
{
if (size <= SIZE)
{
buffer[0..size] = T.init;
return buffer[0..size];
}
else
return new T[size];
}
}
// --------------------------------------------------------
void exec(const(char)*[] envz) { /+ ... +/ }
void oldWay(string[string] environment)
{
auto envz = new const(char)*[environment.length + 1];
int pos = 0;
foreach (var, val; environment)
envz[pos++] = (var~'='~val~'\0').ptr;
exec(envz);
}
void newWay(string[string] environment)
{
auto buf = staticAppender!(4096, char)();
StaticArray!(64, size_t) envpBuf;
size_t[] envp = envpBuf.get(environment.length + 1);
size_t pos;
foreach (var, val; environment)
{
envp[pos++] = buf.data.length;
buf.put(var);
buf.put('=');
buf.put(val);
buf.put('\0');
}
// Convert offsets to pointers in-place
auto envz = cast(const(char)*[])envp;
foreach (n; 0..pos)
envz[n] += cast(size_t)buf.data.ptr;
exec(envz);
}
-------------------------------------------------------------
As you can see, the code is quite more verbose, even with the
helper types. It's no longer obvious at a glance what the code is
doing. Perhaps you can come up with better abstractions?
More information about the Digitalmars-d
mailing list