Function to print a diamond shape

monarch_dodra monarchdodra at gmail.com
Tue Mar 25 01:42:28 PDT 2014


On Tuesday, 25 March 2014 at 02:25:57 UTC, Jay Norwood wrote:
> not through yet with the diamond.  This one is a little faster.
>  Appending the newline to the stars and calculating the slice 
> backward from the end would save a w.put for the newlines ... 
> probably faster.  I keep looking for a way to create a dynamic 
> array of a specific size, filled with the init value I provide. 
> Does it exist?
>
> D:\diamond\diamond\diamond\Release>diamond 1>nul
> brad: time: 19370[ms]
> printDiamond1: time: 1140[ms]
> printDiamond2: time: 1631[ms]
> printDiamond3: time: 633[ms]
> jay1: time: 459[ms]
> sergei: time: 11886[ms]
> jay2: time: 415[ms]
> diamondShape: time: 4553[ms]
> printDiamond: time: 187[ms]
> printDiamonde2a: time: 139[ms]
>
>
> void printDiamonde2a(in uint N)
> {
>     size_t N2 = N/2;
>     char pSpace[] = uninitializedArray!(char[])(N2);
>     pSpace[] = ' ';
>
>     char pStars[] = uninitializedArray!(char[])(N);
>     pStars[] = '*';
>
>     char pNewLine[]=uninitializedArray!(char[])(2);
>     pNewLine[] = '\n';
>
>     auto w = appender!(char[])();
>     w.reserve(N*4);
>
>     foreach (n ; 0 .. N2 + 1){
>         w.put(pSpace[0 .. N2 - n]);
>         w.put(pStars[0 .. 2*n+1]);
>         w.put(pNewLine[1]);
>     }
>
>     foreach_reverse (n ; 0 .. N2){
>         w.put(pSpace[0 .. N2 - n]);
>         w.put(pStars[0 .. 2*n+1]);
>         w.put(pNewLine[1]);
>     }
>     write(w.data);
> }

Interesting. I'd have thought the "extra copy" would be an 
overall slowdown, but I guess that's not the case.

I also tried your strategy of adding '\n' to the buffer, but I 
was getting some bad output on windows. I'm not sure why "\n\n" 
works though. On *nix, I'd have also expected a double line feed. 
Did you check the actual output?

Appender is better than "~=", but it's not actually that good 
either. Try this:

//----
void printDiamond3(size_t N)
{
     import core.memory;
     char* p = cast(char*)GC.malloc(N*N+16);
     p[0..N*N+16]='*';

     auto pp = p;
     N/=2;
     enum code = q{
         pp[0 .. N - n] = ' ';
         pp+=(1+N+n);
         version(Windows)
         {
             pp[0 .. 2] = "\r\n";
             pp+=2;
         }
         else
         {
             pp[0] = '\n';
             ++pp;
         }
     };
     foreach        (n; 0 .. N + 1) {mixin(code);}
     foreach_reverse(n; 0 .. N    ) {mixin(code);}
     write(p[0 .. pp-p]);
}
//----

This makes just 1 allocation of roughly the right size. It also 
eagerly fills the entire array with '*', since I *figure* that's 
faster than a lot of different writes.

I could be mistaken about that though, but I imagine the 
pre-allocation and not using Appender is definitely a boost.


More information about the Digitalmars-d-learn mailing list