Предоставить AoS доступ к SoA

У меня есть данные, размещенные в памяти в форме структуры массивов (SoA) или структуры указателей (SoP), и у меня есть способ получить доступ к этим данным, как если бы они были изложены в форме массива структуры (AoS) — указан код ниже.

Тем не менее, я не слишком доволен использованием struct AoS_4_SoP — хотя это struct кажется, использует шаблоны, это на самом деле не является общим, так как, например, foo а также bar жестко закодированы внутри него.

Два вопроса / просьбы:

1) Предоставляется ли доступ к AoS для производительности чтения и записи так же, как прямой доступ к SoA?

2) Какой будет более общая схема? (Я видел quamrana«s код здесь, но это не помогло.)

struct  SoP{      // Structure of Pointers
int    *foo{ nullptr };
double *bar{ nullptr };
SoP( int *xi, double *xd ):foo(xi), bar(xd){};
};

struct SoR{       // Structure of References
int    &foo;
double &bar;
SoR( int &xi, double &xd ):foo(xi), bar(xd){};
};

template< typename T,  typename S >
struct AoS_4_SoP {
AoS_4_SoP( T *x ) : p( x ){};
T    *p;

S  operator[](std::size_t idx) const { return { p->foo[idx], p->bar[idx] }; }
const S  operator[](std::size_t idx) const { return { p->foo[idx], p->bar[idx] }; }
};

Вот main() показывая использование выше:

int main()
{
std::vector< int    > ibuf{ 11, 22, 33, 44 };
std::vector< double > dbuf{ 0.11, 0.22, 0.33, 0.44 };;

SoP  x_sop( ibuf.data(),  dbuf.data() );

ibuf.at(2)  = 333;
std::cout << "Access via SoP syntax:\n      "<< x_sop.foo[2]
<< "        "<< x_sop.bar[2] << std::endl;

AoS_4_SoP<SoP, SoR> xacc( &x_sop );

std::cout << "Access via AoS syntax:\n      "<< xacc[2].foo
<< "        "<< xacc[2].bar << std::endl;

// show write access via SoA syntax
ibuf.at(2)   = 3333;
dbuf.at( 2 ) = 0.333333;  // will get overwritten below
xacc[2].bar = 0.3333;

std::cout << "Values written via SoP, read via SoP:\n      "<< x_sop.foo[2]
<< "       "<< x_sop.bar[2] << std::endl;

// show write access via AoS syntax
xacc[2].foo = 333333;
dbuf.at( 2 ) = 0.3333333333;  // will get overwritten below
xacc[2].bar = 0.333333;

std::cout << "Values written via AoS, read via AoS:\n      "<< xacc[2].foo
<< "     "<< xacc[2].bar << std::endl;
}

Выше код может быть скомпилирован с помощью:

// x86_64-w64-mingw32-g++.exe -D_WIN64 -Wall -Wextra -Werror -std=c++11 -O3 -static-libgcc -static-libstdc++ aossoa.cc -o aossoa.exe

и приводит к следующему выводу:

Access via SoP syntax:
333        0.33
Access via AoS syntax:
333        0.33
Values written via SoP, read via SoP:
3333       0.3333
Values written via AoS, read via AoS:
333333     0.333333

0

Решение

Я думаю, что этот шаблон будет работать.

template<class T, class U, class D, class S>
struct Accessor {
T* p;
U* (T::*pFirst);
D* (T::*pSecond);
S operator[](size_t index) {
return {(p->*pFirst)[index], (p->*pSecond)[index]};
}
Accessor(T* p_, U * (T::*pF), D * (T::*pS)): p(p_), pFirst(pF), pSecond(pS) {}
};

void main() {
std::vector< int    > ibuf{ 11, 22, 33, 44 };
std::vector< double > dbuf{ 0.11, 0.22, 0.33, 0.44 };;

SoP  x_sop(ibuf.data(),  dbuf.data());

Accessor<SoP, int, double, SoR> aos(&x_sop, &SoP::foo, &SoP::bar);

aos[0].foo;
}

Теперь шаблон Accessor ничего не знает об именах членов T,

По крайней мере, он компилируется под VS2015

1

Другие решения

Вот моя адаптация quamranaрешение для «обратного» варианта использования (SoA-доступ для AoS):

template<class T, class S, class M0, class M1>
struct Accessor2{
T*  p;
M0  m0;
M1  m1;

S operator[](std::size_t idx)       { return { m0[idx], m1[idx] }; }
const S operator[](std::size_t idx) const { return { m0[idx], m1[idx] }; }

Accessor2(T* x, M0 p0, M1 p1): p(x), m0(p0), m1(p1){}
};

template< typename T,  typename S >
struct AoS_4_SoP : public Accessor2<T, S, decltype(T::foo), decltype(T::bar)>
{
#ifndef COMPILER_CAN_INFER_PARENT_CLASS_TEMPLATE_SPECIFICATION
AoS_4_SoP(T *x) : Accessor2<T, S, decltype(T::foo), decltype(T::bar)>
(x, x->foo, x->bar ){}
#else
AoS_4_SoP(T *x):Accessor2(x, x->foo, x->bar ){}
#endif
};

Учитывая #ifndef COMPILER_CAN_INFER_PARENT_CLASS_TEMPLATE_SPECIFICATION, компилятор я использую, а именно, g++ 6.2.0 (x86_64_6.2.0_posix_seh_rt_v5_rev1/mingw64/bin/x86_64-w64-mingw32-g++.exe) не может вывести спецификацию шаблона родительского класса. Но, как Гонки легкости на орбите говорит на этой странице: имя введенного класса базы должно быть достаточной информацией для компилятора.

0

По вопросам рекламы [email protected]