Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Switching back and forth between Array of Structures (AoS) and Structure of Arrays (SoA)

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?

like image 962
alarge Avatar asked Mar 19 '15 00:03

alarge


People also ask

What are the differences between array of structure and structure of array?

One major difference between both of them is that- in an Array, the elements are of the same data type while a structure has elements of different data types. You can also define an Array's size during the declaration and write it in numbers within a square bracket preceded by the name of the array.

What is AoS in computer science?

In computing, array of structures (AoS), structure of arrays (SoA) and array of structures of arrays (AoSoA) refer to contrasting ways to arrange a sequence of records in memory, with regard to interleaving, and are of interest in SIMD and SIMT programming.


1 Answers

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.

like image 142
quamrana Avatar answered Oct 19 '22 16:10

quamrana