loopsd

How to repeat a statement N times (simple loop)


I need to perform an action N times. What is the best way in D to do it?

for(uint i=0; i<N; i++)
   action();

foreach(uint i; 0.. N)
   action();

maybe something better? Ideally I'd want something like Groovy's / Ruby's times e.g

N.times {
   action();
}

is it possible?


Solution

  • Yes, it is possible

    import std.stdio;
    import std.traits;
    
    void foo()
    {
        writeln("Do It!");
    }
    
    void times(T,N)(N n, T action) if (isCallable!T && isIntegral!N)
    {
        static if (ParameterTypeTuple!action.length == 1 
               && isIntegral!(ParameterTypeTuple!action[0]))
            foreach (i; 0 .. n)
                action(i);
        else
            foreach (i; 0 .. n)
                action();
    }
    
    void main(string[] args)
    {
        10.times(&foo);
        10.times({writeln("Do It!");});
        10.times((uint n){writeln(n + 1, " Round");});
    }
    

    version with arguments support:

    import std.stdio;
    import std.traits;
    
    void foo()
    {
        writeln("Do It!");
    }
    
    struct Step {
        alias n this;
        size_t n;
        this(size_t i)
        {
            n = i + 1;
        }
    }
    
    struct Index {
        alias n this;
        size_t n;
    }
    
    void times(T,N,A...)(N n, T action, A args) if (isCallable!T && isIntegral!N)
    {
        alias PTTAction = ParameterTypeTuple!action;
        static if (PTTAction.length >= 1)
        {
            alias FP = PTTAction[0];
            static if (is(Index == FP) || is(Step == FP))
                foreach (i; 0 .. n)
                    action(FP(i), args);
            else
                action(args);
        }
        else
            foreach (i; 0 .. n)
                action();
    }
    
    void main(string[] args)
    {
        10.times(&foo);
        10.times({writeln("Do It!");});
        10.times((Step n){writeln(n, " Step");});
        10.times((Index n, string msg){writeln(n, msg);}, " Index");
        stdin.readln;
    }
    

    UPDATE:

    for better performance you could use alias template parameter for action:

    void times(alias action,N)(N n) if (isCallable!action && isIntegral!N)
    {
        static if (ParameterTypeTuple!action.length == 1 
               && isIntegral!(ParameterTypeTuple!action[0]))
            foreach (i; 0 .. n)
                action(i);
        else
            foreach (i; 0 .. n)
                action();
    }
    
    void main(string[] args)
    {
        10.times!(foo);
        10.times!({writeln("Do It!");});
        10.times!((uint n){writeln(n + 1, " Round");});
    }