2015-04-30 6 views
5

ho una struttura che assomiglia a questo:più veloce possibile struct-di-array per array-di-Structs conversione

struct SoA 
{ 
    int arr1[COUNT]; 
    int arr2[COUNT]; 
}; 

E voglio farlo sembrare come questo:

struct AoS 
{ 
    int arr1_data; 
    int arr2_data; 
}; 

std::vector<AoS> points; 

come rapidamente possibile. L'ordine deve essere conservato.

Costruisce ciascun oggetto AoS singolarmente e lo spinge indietro nel modo più veloce per farlo, oppure esiste un'opzione più veloce?

SoA before; 
std::vector<AoS> after; 

for (int i = 0; i < COUNT; i++) 
    points.push_back(AoS(after.arr1[i], after.arr2[i])); 

ci sono SOA/AoS relative domande su StackOverflow, ma non ho trovato uno correlate a più rapida possibile conversione. A causa delle differenze di impaginazione strutturale non riesco a vedere alcun modo per evitare di copiare i dati da un formato all'altro, ma spero che qualcuno possa dirmi che esiste un modo per fare semplicemente riferimento ai dati in modo diverso ed evitare una copia.

Off the wall soluzioni particolarmente incoraggiate.

+0

Dubito che sia possibile "fare semplicemente riferimento ai dati in modo diverso", poiché ha una diversa disposizione in memoria. – immibis

+0

E dovrai inserire/spingerli comunque, altrimenti il ​​tuo 'vector' non sarebbe in stato valido. –

+1

Si noti che la referenziazione dei dati in modo diverso potrebbe non essere più veloce di una copia ... Le cache RAM sono più efficaci quando si legge o si scrive la memoria in modo lineare, e fare un sacco di dereferenziazioni potrebbe spezzare quel modello, causando molti errori di cache e quindi esecuzione più lenta. (o forse no, ma la cosa fondamentale è misurarla in entrambi i modi ed essere pronta a rimanere sorpresa quando le tue intuizioni non corrispondono alla realtà) –

risposta

5

Il layout binario di SoA e AoS[]/std::vector<AoS> è diverso, quindi non c'è davvero alcun modo di trasformare l'uno con l'altro senza operazioni di copia.

Il codice che hai è abbastanza vicino a quello ottimale - un miglioramento forse per il pre-allocazione del vettore con il numero previsto di elementi. In alternativa, prova l'array raw con sia la costruzione dell'intero elemento sia l'inizializzazione per proprietà. Le modifiche devono essere misurate con attenzione (misurate sicuramente usando la build completamente ottimizzata con le dimensioni dell'array che vi aspettate) e ponderate con la leggibilità/correttezza del codice.

Se non è necessario il layout binario esatto (sembra che sia il caso in cui si utilizza il vettore) si potrebbe essere in grado di ottenere una sintassi similare creando coppie di classi personalizzate che potrebbero esporre i dati esistenti in modo diverso. Questo eviterà di copiare del tutto.

Si avrebbe bisogno tipo "vettore" (fornire indicizzazione/iterazione su istanza di SoA) e di tipo "elemento" (inizializzato con referece per esempio di SOA e indice, esponendo di accesso per i campi separati in tale indice)

Schizzo approssimativo del codice (aggiungere iteratori, ...):

class AoS_Element 
{ 
    SoA& soa; 
    int index; 
public: 
    AoS_Element(SoA& soa, int index) ... 
    int arr1_data() { return soa.arr1[index];} 
    int arr2_data() { return soa.arr2[index];} 
} 

class AoS 
{ 
    SoA& soa; 
public: 
    AoS(SoA& _soa):soa(_soa){} 
    AoS_Element operator[](int index) { return AoS_Element(soa, index);} 
} 
+0

Puoi espandere il tipo di "matrice" che menzioni? Sei corretto, la rappresentazione binaria esatta non è l'obiettivo qui, solo un accesso efficiente agli elementi. Non avevo pensato di usare un iteratore personalizzato –

+0

@ConnorLawson Ho aggiunto un campione molto approssimativo (probabilmente non verrà nemmeno compilato ... si spera che mostri cosa intendo meglio delle parole). –

+0

Il contenuto 'std :: vector' ha lo stesso layout binario in un semplice vecchio array. –