BeeBand
BeeBand

Reputation: 11493

Is there such a thing as a union of unions?

I came across the following code - what is the data type of col_8888 and why does it reference the union _colours? I googled unions, but I can't find a reference to this kind of declaration - it looks to me as though col_8888 is a "union of unions"?

union _colours {
    uint8  c[3][4];
    uint32 alignment;
};

static const union _colours col_8888 = 
{        
    {    /*   B     G     R     A  in memory     */
        {    0x00, 0x00, 0xFF, 0xFF, }, /* red   */
        {    0x00, 0xFF, 0x00, 0xFF, }, /* green */
        {    0xFF, 0x00, 0x00, 0xFF, }, /* blue  */
    }   
};

#define COL_8888_RED   *((uint32 *)&col_8888.c[0])
#define COL_8888_GREEN *((uint32 *)&col_8888.c[1])
#define COL_8888_BLUE  *((uint32 *)&col_8888.c[2])

Upvotes: 0

Views: 471

Answers (2)

redorav
redorav

Reputation: 962

I have used this in a math class (https://github.com/redorav/hlslpp) around SIMD types. One way I devised having accessors is to have a class component that is unioned with the main type.

Something like the following:

class component1
{
    __m128 vec;
    component1(float f) { // Only write to one component }
}

class vec4
{
    union
    {    
        __m128 vec;
        component1 x;
        component1 y;
        component1 z;
        component1 w;
    }
}

This example is incomplete because component1 is actually templated and its behavior depends on which component you access but for this example it's good.

If you extend this to matrices, you can have accessors for each row that essentially point to the same data. You can extend this to have matrix3 alias in memory with matrix4.

For example,

class mat3
{
    union
        {
             __m128 row1;
             component1 m00, m01, m02;
        }
        union
        {
             __m128 row2;
             component1 m10, m11, m12;
        }
        union
        {
             __m128 row3;
             component1 m20, m21, m22;
        }
}

class mat4
{
    union
    {
        mat3 _m3;

        union
        {
             __m128 row1;
             component1 m00, m01, m02, m03;
        }
        union
        {
             __m128 row2;
             component1 m10, m11, m12, m13;
        }
        union
        {
             __m128 row3;
             component1 m20, m21, m22, m23;
        }
        union
        {
             __m128 row4;
             component1 m30, m31, m32, m33;
        }
    }
}

With this idea you'd be able to do things like

mat4 m4;
m4.m00 = 3.0f;

mat3& m3 = m4._m3;
m3.m00 = 5.0f; // m4.m00 is now 5.0f

Upvotes: 0

DrAl
DrAl

Reputation: 72616

The type of col_8888 is union _colours, so it isn't a union of unions: it's just a union. In C, it is necessary to prefix the union name with union to use it. Alternatively you can use a typedef. Thus the following two declarations are equivalent:

union _colours {
    uint8  c[3][4];
    uint32 alignment;
};

static const union _colours col_8888 =
...

/* Equivalent to: */

typedef union {
    uint8  c[3][4];
    uint32 alignment;
} _colours_t;

static const _colours_t col_8888 =
...

Upvotes: 9

Related Questions