dolphin-emu/dolphin — pull request #273 by neobrain (2014-04-14 19:17:54+00:00)
Title: Add functionality for grouping BitFields into arrays.

## Introduction ##

In many places of the Dolphin code, the same code needs to be executed for bitfields with the same purpose, but different location relative to the register LSB. For example, is doing things like this:

m_VtxAttr.texCoord[0].Frac = g_VtxAttr[vtx_attr_group].g0.Tex0Frac;
m_VtxAttr.texCoord[1].Frac = g_VtxAttr[vtx_attr_group].g1.Tex1Frac;
m_VtxAttr.texCoord[2].Frac = g_VtxAttr[vtx_attr_group].g1.Tex2Frac;
m_VtxAttr.texCoord[3].Frac = g_VtxAttr[vtx_attr_group].g1.Tex3Frac;
m_VtxAttr.texCoord[4].Frac = g_VtxAttr[vtx_attr_group].g2.Tex4Frac;
m_VtxAttr.texCoord[5].Frac = g_VtxAttr[vtx_attr_group].g2.Tex5Frac;
m_VtxAttr.texCoord[6].Frac = g_VtxAttr[vtx_attr_group].g2.Tex6Frac;
m_VtxAttr.texCoord[7].Frac = g_VtxAttr[vtx_attr_group].g2.Tex7Frac;

Of the various `TexXFrac` bitfields, some are stored within the same register. Virtually none of them have the same bit-offset from the LSB, so there's no reasonable way to deal with such situations with conventional C++.

Based on the previous BitField work, this branch adds a BitFieldArray type which can be used to group various BitFields and expose the group as an array.

## Usage ##
Given some sample structure

union TestUnion
{
BitField<0, 4, u32> field1;
BitField<4, 4, u32> field2;
BitField<8, 4, u32> field3;
};

the three fields can be grouped by adding a MACRO call at the bottom of the union, i.e.

union TestUnion
{
BitField<0, 4, u32> field1;
BitField<4, 4, u32> field2;
BitField<8, 4, u32> field3;

DECLARE_BITFIELD_ARRAY(fields, field1, field2, field3);
};

Given some `TestUnion test_object;`, the various fields can be accessed like this:

for (int i = 0; i < 3; ++i)
{
test_object.fields()[i] = rand();
}

or alternatively

auto fields = test_object.fields();
for (int i = 0; i < 3; ++i)
{
fields[i] = rand();
}

Real world usage can be found in neobrain/dolphin@88d3bb5ba22 (and previous commits in the same branch).

## Caveats and open questions ##
There are a number of things I'd like to hear other developers' opinions of.
* Access syntax: I cannot include a "true" array in a union for obvious reasons. Hence, each union gets a BitFieldArray getter function per BitFieldArray, which (theoretically) allocates a BitFieldArray object on stack and returns it to the caller. It is very likely that the compiler optimizes all of this out however, hence resulting in optimal assembly as if people just used plain (duplicated) code as above. I understand people might be irritated by the `GetField()[index]` syntax. However, in some cases it's nice to "store" the returned array temporarily (e.g. `auto fields = test_object.fields()` like above). This would not be possible if we were to use something like `GetField(int index)` instead.
* Implementation: `BitFieldArray` technically is kind of an `std::tuple` of BitFields, with additional support for runtime indexing. This required a few somewhat advanced template programming techniques to be employed (variadic templates, compile time integer sequences, template subclasses, ...), some of which might be better suited in a separate file in Common. In particular I'm thinking about integer sequences here, but a) that's just a few additional lines which currently aren't useful anywhere else for Dolphin b) the upcoming C++14 standard will be supporting compile-time integer-sequences anyway, obsoleting these few lines.
* BitFieldArray declaration syntax: I need to use the `DECLARE_BITFIELD_ARRAY` helper macro for two reasons: a) There's no good way to declare the function without duplicating things over and over again. This is due to the requirement of explicit return type specification. This problem will go away with C++14, which provides support for implicit return type deduction. b) As far as my testing goes, there need to be two getters: One non-const, one const. Hence without this macro one would need to write the same BitFieldArray getter twice. If you have a suggestion on how to resolve this issue, don't hesitate to tell me ;)