Thread overview
How to automatically generate function overloads
May 04, 2021
Blatnik
May 04, 2021
Blatnik
May 04, 2021
Zone
May 04, 2021
Blatnik
May 04, 2021

I'm porting over my linear algebra library from C++, and I have a bunch of functions that work on both scalars and vectors. The vector versions just apply the scalar function to every element of the vector, for example:

float clamp01(float x) { return x < 0 ? 0 : (x > 1 ? 1 : x); }

float[N] clamp01(size_t N)(float[N] vec)
{
  float[N] result;
  static foreach (i; 0 .. N)
    result[i] = clamp01(vec[i]);

  return result;
}

And this is great, I don't have to write the same function for different array lengths.

But I still have like 30-ish of these functions and I would like to generate the array overload automatically from the scalar overload.

So I would like something like a mixin, that I can use like this:

mixin Vectorize_Unary_Function!clamp01; // Generates the code above.
mixin Vectorize_Unary_Function!floor;
mixin Vectorize_Unary_Function!ceil;
...

It doesn't have to be a mixin like this. I don't really care what it is as long as it works :)

How could I do this?

May 04, 2021

On Tuesday, 4 May 2021 at 11:00:42 UTC, Blatnik wrote:

>

How could I do this?

I've already tried this:

mixin template Vectorize_Unary_Function(alias Function)
{
  float[N] Function(size_t N)(float[N] vec)
  {
    float[N] result;
    static foreach (i; 0 .. N)
      result[i] = Function(vec[i]);
    return result;
  }
}

But it didn't work.

mixin Vectorize_Unary_Function!clamp01;

float[2] vec = [1, 2];
float[2] clamped = clamp01(vec); // Error

I think it actually declared a function called "Function" instead of calling it "clamp01" like the alias I passed in.

May 04, 2021

On Tuesday, 4 May 2021 at 11:00:42 UTC, Blatnik wrote:

>

I'm porting over my linear algebra library from C++, and I have a bunch of functions that work on both scalars and vectors. The vector versions just apply the scalar function to every element of the vector, for example:

float clamp01(float x) { return x < 0 ? 0 : (x > 1 ? 1 : x); }

float[N] clamp01(size_t N)(float[N] vec)
{
  float[N] result;
  static foreach (i; 0 .. N)
    result[i] = clamp01(vec[i]);

  return result;
}

And this is great, I don't have to write the same function for different array lengths.

But I still have like 30-ish of these functions and I would like to generate the array overload automatically from the scalar overload.

So I would like something like a mixin, that I can use like this:

mixin Vectorize_Unary_Function!clamp01; // Generates the code above.
mixin Vectorize_Unary_Function!floor;
mixin Vectorize_Unary_Function!ceil;
...

It doesn't have to be a mixin like this. I don't really care what it is as long as it works :)

How could I do this?

float clamp01(float x) { return x < 0 ? 0 : (x > 1 ? 1 : x); }

template Vectorize_Unary_Function(alias fun) {
    float[N] Vectorize_Unary_Function(size_t N)(float[N] vec)
    {
        float[N] result;
        static foreach (i; 0 .. N)
            result[i] = fun(vec[i]);
        return result;
    }
}

alias clamp01 = Vectorize_Unary_Function!clamp01;


void main() {
    float[5] vec = [1,2,3,4,5];
    float[5] other = clamp01(vec);
    writeln(vec);
    writeln(other);
}

Not exactly what you were asking for but I hope it works, tricky part is I'm not sure how to generate the function name without string mixins so that's why I used alias instead.

May 04, 2021

On Tuesday, 4 May 2021 at 11:21:20 UTC, Zone wrote:

>
template Vectorize_Unary_Function(alias fun) {
    float[N] Vectorize_Unary_Function(size_t N)(float[N] vec)
    {
        float[N] result;
        static foreach (i; 0 .. N)
            result[i] = fun(vec[i]);
        return result;
    }
}

alias clamp01 = Vectorize_Unary_Function!clamp01;

Not exactly what you were asking for but I hope it works, tricky part is I'm not sure how to generate the function name without string mixins so that's why I used alias instead.

Awesome, this does exactly what I wanted. Thanks for the help! :)