Static Foreach + Marking "compile time" variables

Simen Kjærås simen.kjaras at gmail.com
Wed Mar 28 23:42:26 UTC 2018


On Wednesday, 28 March 2018 at 23:02:53 UTC, Chris Katko wrote:

There's many things that can be done to make the code easier to 
follow. These lines:
>     static if (!hasPosition)
> 		{
> 		assert(0, "Need to pass a position!");
> 		}

Can be replaced with this:

     static assert(hasPosition, "Need to pass a position");

That will show the error message at compile-time, greatly 
improving the experience of using the code. You could also us it 
as a template constraint:

     void funct2(A...)(ALLEGRO_BITMAP *bit, A a)
     if (anySatisfy!(isa!Position, A))
     {

There are benefits and drawbacks to using template constraints 
vs. static asserts, so try both and see which fits your code.


Since hasPosition needs to be true for anything else to work, we 
can just assert it once, then assume it's true, turning these:

>     static if (hasPosition && hasCenteredPosition)
>     static if (hasPosition && hasRotate && !hasScale)

into these:

     static if (hasCenteredPosition)
     static if (hasRotate && !hasScale)


Another possible simplification in your code would be to use 
staticIndexOf instead of anySatisfy:

     enum position = staticIndexOf!(pos, A);
     static assert(position > -1, "Must pass a position");
     enum hasCenteredPosition = anySatisfy!(isa!center, A);

     static if (hasCenteredPosition) {
         float temp_x = a[position].x - bit.w/2;
         float temp_y = a[position].y - bit.h/2;
     } else {
         float temp_x = a[position].x;
         float temp_y = a[position].y;
     }

In fact, given the style in which you write your code, I would 
suggest these helper templates:

// Returns the first element of Args that is of type T,
// or an empty AliasSeq if no such element exists.
template find(T, Args...) {
     enum idx = staticIndexOf!(T, typeof(Args));
     static if (idx > -1) alias find = Args[idx];
     else                 alias find = AliasSeq!();
}

// Checks if find!() found anything.
enum found(T...) = T.length == 1;


Using those, you would write this code:

void funct2(A...)(ALLEGRO_BITMAP* bit, A a)
if (anySatisfy!(isa!pos, A)
{
     enum centered  = anySatisfy!(isa!center, A)

     alias position = find!(pos, a);
     alias rotation = find!(rotate, a);
     alias scaling  = find!(scale, a);

     static if (centered) {
         // No need to use array lookup - find!() did that for us.
         // That also means we can more easily modify position 
directly,
         // instead of using temporaries.
         position.x -= bit.w/2;
         position.y -= bit.h/2;
     }

     static if (!found!rotation && !found!scaling) {
         // Since rotation and scaling are empty AliasSeqs here,
         // attempting to use them will cause immediate compile 
errors.
         al_draw_bitmap(bit, position.x, position.y, 0);
     } else static if (found!rotation && !found!scaling) {
         al_draw_rotated_bitmap(bit,
             bit.w/2,    bit.h/2,
             position.x, position.y,
             rotation.a,
             0);
     } else static if (found!rotation && found!scaling) {
         // Handle this case.
     } else static if (!found!rotation && found!scaling) {
         // Handle this case.
     }
}

--
   Simen


More information about the Digitalmars-d-learn mailing list