class DiabolicalData
{
public :
//
// Enums
//
enum TestFlag
{
e1 = 0x1, // Bit flags representing the members and their types.
e2 = 0x2, // Here's the checklist to add a new member to this class:
e3 = 0x4, // 1) Add a value to this enum to represent the member
e4 = 0x8, // 2) Add the member's type to the TestTypes below
e5 = 0x10, // 3) Add the member to this class normally
// 4) Add access code for this member in the GetArrayPtr method.
// No constants after here...
eLast = e5, // Note : I've used bit flags here but normal incrementing enum values
// are possible too; just change the Unroll<TestFlag(i << 1)::???
// call in the Unroll static methods to Unroll<TestFlag(i + 1)::???
};
//
// Structs
//
// Member types accessible by TestFlag value
template <TestFlag i struct TestType { };
struct TestType<e1 { typedef char VType; };
struct TestType<e2 { typedef int VType; };
struct TestType<e3 { typedef float VType; };
struct TestType<e4 { typedef char * VType; };
struct TestType<e5 { typedef struct { int x,y,z; } VType; };
private :
struct DiabolicalUnroller // Keep all the Unroll structs in here so they are publically accessible to
// each other (but we keep the mechanism as a whole private).
{
template <TestFlag i struct Unroll
{
//
// Typedefs
//
typedef TestType<i::VType UnrollType; // Type associated with the array matched to this flag
//
// Static Functions
//
static __forceinline void _Clear(DiabolicalData * pData)
{
// Sets the flagged array to point to null
UnrollType * * pArray = (UnrollType * *)pData-GetArrayPtr(i);
if (pArray)
{
*pArray = 0;
}
else
{
printf("Unroll::_Clear - Array flag %d is unsupported by GetArrayPtr\n",i);
}
Unroll<TestFlag(i << 1)::_Clear(pData);
}
static __forceinline void _Allocate(DiabolicalData * pData,const int Num)
{
// Allocates Num entries to the flagged array
UnrollType * * pArray = (UnrollType * *)pData-GetArrayPtr(i);
if (pArray)
{
if (*pArray)
{
delete [](*pArray);
}
*pArray = new UnrollType[Num];
}
else
{
printf("Unroll::_Allocate - Array flag %d is unsupported by GetArrayPtr\n",i);
}
Unroll<TestFlag(i << 1)::_Allocate(pData,Num);
}
static __forceinline void _AllocateMarked(DiabolicalData * pData,const int Num,const int Mark)
{
// Allocates Num entries to the flagged array if i is flagged in Mark
UnrollType * * pArray = (UnrollType * *)pData-GetArrayPtr(i);
if (pArray && ((Mark & i) != 0))
{
if (*pArray)
{
delete [](*pArray);
}
*pArray = new UnrollType[Num];
}
else
{
printf("Unroll::_AllocateMarked - Array flag %d is unsupported by GetArrayPtr\n",i);
}
Unroll<TestFlag(i << 1)::_AllocateMarked(pData,Num,Mark);
}
static __forceinline void _Deallocate(DiabolicalData * pData)
{
// Deallocates the flagged array
UnrollType * * pArray = (UnrollType * *)pData-GetArrayPtr(i);
if (pArray)
{
delete [](*pArray);
*pArray = 0;
}
else
{
printf("Unroll::_Deallocate - Array flag %d is unsupported by GetArrayPtr\n",i);
}
Unroll<TestFlag(i << 1)::_Deallocate(pData);
}
};
struct Unroll<TestFlag(eLast << 1)
{
// Empty unroll struct - terminates the loop unroll
static __forceinline void _Clear(DiabolicalData*) { }
static __forceinline void _Allocate(DiabolicalData*,const int) { }
static __forceinline void _AllocateMarked(DiabolicalData*,const int,const int) { }
static __forceinline void _Deallocate(DiabolicalData*) { }
};
};
//
// Members
//
TestType<e1::VType * m_pData1; // Bogus data
TestType<e2::VType * m_pData2; // arrays to
TestType<e3::VType * m_pData3; // test this
TestType<e4::VType * m_pData4; // disgusting
TestType<e5::VType * m_pData5; // code
public :
//
// Methods
//
DiabolicalData()
{
DiabolicalUnroller::Unroll<e1::_Clear(this);
}
void * * GetArrayPtr(TestFlag F)
{
// Array get method - update here when adding new array members
switch (F)
{
case e1 : return (void * *)(&m_pData1);
case e2 : return (void * *)(&m_pData2);
case e3 : return (void * *)(&m_pData3);
case e4 : return (void * *)(&m_pData4);
case e5 : return (void * *)(&m_pData5);
};
return 0;
}
//
// Test Functions
//
void AllocateAll(const int NumToAllocate)
{
// Allocates NumToAllocate entries to each of the arrays
DiabolicalUnroller::Unroll<e1::_Allocate(this,NumToAllocate);
}
void AllocateMarked(const int NumToAllocate,const int Mark)
{
// Allocates NumToAllocate entries to each of the marked arrays
DiabolicalUnroller::Unroll<e1::_AllocateMarked(this,NumToAllocate,Mark);
}
void DeallocateAll()
{
// Deallocates all the arrays
DiabolicalUnroller::Unroll<e1::_Deallocate(this);
}
}; |