One feature that plays a prominent role in many of the writings on data oriented design is that there are many cases where rather than AoS (array of structs):
struct C_AoS {
int foo;
double bar;
};
std::vector<C_AoS> cs;
...
std::cout << cs[42].foo << std::endl;
it is more efficient to arrange one's data in SoA (struct of arrays):
struct C_SoA {
std::vector<int> foo;
std::vector<double> bar;
};
C_SoA cs;
...
std::cout << cs.foo[42] << std::endl;
Now what I am looking for is a solution which would allow me to switch between AoS and SoA without changing the calling interface, i.e. that I could, with minimal effort and with no extra runtime cost (at least to the point of excessive indirection), call e.g. cs[42].foo;
regardless of which arrangement of data I'm using.
I should note that the example syntax above is the ideal case, which might very well be impossible, but I'd be very interested in close approximations, too. Any takers?
I'm going to choose this syntax: cs.foo[42]
to be the single syntax and use typedefs to switch between arrangements:
So, obviously given C_SoA
from your post, the above syntax works and we can have:
typedef C_SoA Arrangement;
Arrangement cs;
In order to use std::vector<C_AoS>
instead we are going to have to introduce something else:
typedef std::vector<C_AoS> AOS;
template<class A, class C, class T>
struct Accessor {
T operator[](size_t index){
return arr[index].*pMember;
}
T (C::*pMember);
A& arr;
Accessor(A& a, T (C::*p)): arr(a), pMember(p){}
};
struct Alt_C_AoS{
Accessor<AOS, C_AoS, int> foo;
Accessor<AOS, C_AoS, double> bar;
AOS aos;
Alt_C_AoS():foo(aos, &C_AoS::foo), bar(aos, &C_AoS::bar){}
};
Now we can have:
//Choose just one arrangement
typedef Alt_C_AoS Arrangement;
//typedef C_SoA Arrangement;
Arrangement cs;
...
std::cout << cs.foo[42] << std::endl;
Essentially this converts container dot member index
into container index dot member
.
来源:https://stackoverflow.com/questions/29135201/switching-back-and-forth-between-array-of-structures-aos-and-structure-of-arra