Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fast vector struct that allows [i] and .xyz-operations in D?

I'd like to create a vector struct in D that works like this:

vec u, v;
vec w = [2,6,8];
v.x = 9; // Sets x
v[1] = w.y; // Sets y
u = v; // Should copy data

Later I'd also like to add stuff like u = v * u etc. But the above will do for now.
This is how far I've come:

struct vec3f
{
    float[3] data;
    alias data this;
    @property
    {
        float x(float f) { return data[0] = f; }
        float y(float f) { return data[1] = f; }
        float z(float f) { return data[2] = f; }
        float x() { return data[0]; }
        float y() { return data[1]; }
        float z() { return data[2]; }
    }
    void opAssign(float[3] v)
    {
        data[0] = v[0];
        data[1] = v[1];
        data[2] = v[2];
    }
}

Now this pretty much makes it work like I wanted, but I feel very unsure about if this is "right". Should the opAssign() perhaps return some value?

I'm also wondering if this is really as fast as it can be? Is I've tried adding alias data[0] x; etc. but that doesn't work. Any ideas? Or is this "how it's done"? Perhaps the compiler is smart enough to figure out the propery functions are more or less aliases?

like image 325
0scar Avatar asked Jun 23 '10 00:06

0scar


4 Answers

Overall, this looks pretty reasonable. For the purpose of assignment chaining, opAssign should arguably return v. However, in practice this is often overlooked and might cause a performance hit (I don't know). Unlike in D1, you can return static arrays from functions in D2.

As far as performance, the best way to think of this is at the assembly level. Assuming inlining is enabled, x() will almost certainly be inlined. Static arrays are stored directly in the struct without an extra layer of indirection. The instruction return data[0]; will cause the compiler to generate code to read from an offset from the beginning of the struct. This offset will be known at compile time. Therefore, most likely calling x() will generate exactly the same assembly instructions as if x were actually a public member variable.

One other possibility, though, would be to use an anonymous union and struct:

struct vec3f
{
    union {
        float[3] vec;

        struct {
            float x;
            float y;
            float z;
        }
    }

    alias vec this;  // For assignment of a float[3].

}

Note, though that alias this is fairly buggy right now, and you probably shouldn't use it yet unless you're willing to file some bug reports.

like image 87
dsimcha Avatar answered Oct 19 '22 02:10

dsimcha


You can use opDispatch for swizzling of arbitrary depth. I'd also recommend templating your vector struct on size and type. Here's my version for comparison: tools.vector (D1, so swizzling is a bit more cumbersome).

like image 25
FeepingCreature Avatar answered Oct 19 '22 03:10

FeepingCreature


You can use an array operation to copy the whole array in one shot in opAssign:

data[] = v[];
like image 28
Michel Fortin Avatar answered Oct 19 '22 01:10

Michel Fortin


@property
    {
        float x(float f) { return data[0] = f; }
        float y(float f) { return data[1] = f; }
        float z(float f) { return data[2] = f; }
        float x() { return data[0]; }
        float y() { return data[1]; }
        float z() { return data[2]; }
    }

Why properties ?

I would suggest to drop these lines and make x, y and z public fields. This will also improve performance in non-inline mode. You can use union to have a data[3] array anyway.

like image 27
ponce Avatar answered Oct 19 '22 03:10

ponce