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