Ho problemi ad adattare la proposta C++ 1z in sospeso N3980 da @HowardHinnant per lavorare con tabulation hashing.hashing di tabulazione e N3980
Ab initio computing un hash di tabulazione funziona come per l'algoritmo di hash (Spooky, Murmur, ecc.) Descritto in N3980. Non è così complicato: basta serializzare un oggetto di qualsiasi tipo definito dall'utente tramite hash_append() e lasciare che la funzione hash aggiorni un puntatore in una tabella di numeri casuali mentre procedete.
Il problema inizia quando si tenta di implementare una delle buone proprietà dell'hash di tabulazione: molto economico per calcolare gli aggiornamenti incrementali nell'hash se un oggetto è mutato. Per gli hash di tabulazione "fatti a mano", si ricalcola l'hash dei byte interessati dell'oggetto.
La mia domanda è: come comunicare aggiornamenti incrementali a un oggetto uhash<MyTabulationAlgorithm>
funzione, mantenendo fedele al tema centrale del N3980 (Tipi non sanno #)?
per illustrare le difficoltà di progettazione: dire che ho un tipo definito dall'utente X con N membri dati xi di vari tipi Ti
struct X
{
T1 x1;
...
TN xN;
};
Creare ora un oggetto e calcolare il suo hash
X x { ... }; // initialize
std::size_t h = uhash<MyTabulationAlgorithm>(x);
Aggiornare un singolo membro e ricalcolare l'hash
x.x2 = 42;
h ^= ...; // ?? I want to avoid calling uhash<>() again
Potrei calcolare l'incremento aggiornamento ntale come qualcosa di simile
h ^= hash_update(x.x2, start, stop);
dove [start, stop)
rappresenta la gamma della tabella di numeri casuali che corrispondono all'elemento di dati x2. Tuttavia, al fine di incrementare (cioè a buon mercato!) L'hash per mutazioni arbitrarie, ogni membro di dati deve in qualche modo conoscere il proprio subrange nel flusso di byte serializzato della sua classe contenente. Questo non sembra lo spirito di N3980. Ad esempio, l'aggiunta di nuovi membri di dati alla classe contenente, cambierebbe il layout di classe e quindi gli offset nel flusso di byte serializzato.
Applicazione: l'hashing di tabulazione è molto vecchio, ed è stato recentemente dimostrato che ha proprietà matematiche molto belle (vedere il link di Wikipedia). È anche molto popolare nella comunità di programmazione di giochi da tavolo (scacchi per computer e go e.g.) dove va sotto il nome di Zobrist hashing. In questo caso, la posizione di una scheda assume il ruolo di X e si sposta il ruolo di un piccolo aggiornamento (spostare un pezzo dalla sua origine alla sua destinazione, ad esempio). Sarebbe bello se l'N3980 potesse essere adattato non solo a tale hashing di tabulazione, ma che potesse anche contenere gli economici aggiornamenti incrementali.
Il riempimento nel layout della classe avrebbe rovinato il calcolo dell'indirizzo o mi manca qualcosa? – TemplateRex
@TemplateRex se c'è padding allora '' '' '' hash_append' di X' passerà 'x.x2' all'algoritmo hash come un singolo blocco di memoria, e' key' sarà uguale a 'p'. Si noti che 'ignore' viene chiamato solo per i frammenti di memoria che partecipano alla rappresentazione del valore di' X'. – ecatmur
Ah, buon punto. Un altro punto che non è abbastanza chiaro è che con l'hashing della tabulazione, è necessario XOR fuori il vecchio valore 'x2' e poi XOR nel nuovo. Quindi l'IncrementalHashAdaptor ha bisogno di ricevere il "delta" completo nello stato dell'oggetto di 'x' (ad esempio' x.x2' includendo il suo valore iniziale e il nuovo valore 42). Dì negli scacchi al computer, hai una classe State/Position e una classe Delta/Move che incapsula la modifica. Quindi 'uhash' funziona su' State' e l'IncrementalHashAdaptor funziona su 'Delta' (e forse anche su' State'). – TemplateRex