2016-04-18 38 views
6

Ho un set di funzioni C++. Voglio mappare queste funzioni in una tabella hash, ad esempio: unordered_map<function<ReturnType (Args...)> , SomethingElse>, dove SomethingElse non è rilevante per questa domanda.Generatore di funzioni di hash perfetto per funzioni

Questo set di funzioni è noto in precedenza, piccolo (diciamo meno di 50) e statico (non cambierà).

Poiché le prestazioni di ricerca sono fondamentali (devono essere eseguite in O(1)), desidero definire una funzione di hashing perfetta.

Esiste un generatore di funzioni di hash perfetto per questo scenario?

So che esistono generatori di funzioni di hashing perfette (come GPERF o CMPH) ma poiché non li ho mai usati, non so se sono adatti al mio caso.

MOTIVO:

Sto cercando di progettare un quadro in cui, dato un programma scritto in C++, l'utente può selezionare un sottoinsieme F delle funzioni definite in questo programma.

Per ogni f appartenente al F, il quadro implementa una strategia memoization: quando chiamiamo f con ingresso i, abbiamo memorizzare (i,o) all'interno di qualche struttura dati. Quindi, se chiameremo nuovamente f con i, restituiremo o senza eseguire nuovamente il calcolo (costoso nel tempo).

Il "risultati già calcolati" saranno condivise tra diversi utenti (forse sul cloud), quindi se l'utente u1 ha già calcolato o, utente u2 farà risparmiare tempo di calcolo chiamando f con i (utilizzando la stessa annotazione di prima) .

Ovviamente, abbiamo bisogno di memorizzare l'insieme delle coppie (f,inputs_sets) (dove inputs_sets è il risultati già calcolati set che ho parlato prima), che è la domanda iniziale: come faccio a farlo?

Quindi, utilizzando il "enumerazione trucco" proposto nei commenti a questo scenario potrebbe essere una soluzione, partendo dal presupposto che gli tutti gli utenti utilizzano il esattamente lo stesso enumerazione, che potrebbe essere un problema: supponiamo che il nostro programma ha f1 , f2, f3 cosa succede se u1 vuole Memoize solo f1 e f2 (così F={f1,f2}), mentre u2 vuole Memoize solo f3 (così F={f3})? Una soluzione di overkill potrebbe essere quella di enumerare tutte le funzioni definite nel programma, ma questo potrebbe generare un enorme spreco di memoria.

+0

Le chiavi 'std :: function' non esporranno tutto ciò che è possibile utilizzare per implementare le funzioni di hashing e di uguaglianza necessarie per' unordered_map' - in pratica sei limitato a 'target_type' e' target'. Normalmente non vorrai o ti aspetteresti di limitare le funzioni ad avere diversi 'target_type's, che lascia [' target'] (http://en.cppreference.com/w/cpp/utility/functional/function/target) - un puntatore al bersaglio memorizzato. Mi sembra che possa variare da compilare a compilare, anche per le funzioni extern - difficile da estrarlo, eseguire gperf o simili, modificarlo nel codice e sapere che non sarà cambiato. –

+3

Considerare l'inganno solo dichiarare un'enumerazione (con un valore enum per funzione) e un array const di funzioni e eseguire le 'ricerche' come ricerche di array, utilizzando i valori enum come chiavi? Penso che eviterei completamente il problema di hashing e ti fornisca prestazioni ottimali. –

+0

Come intendi usare la tua mappa? Voglio dire - le tue ricerche sono eseguite solo con un nome esplicito, ad es. 'map.lookup (pippo)', dove 'pippo' è un nome di funzione reale o ci può essere un puntatore di funzione runtime passato come argomento? Se il primo è il caso, probabilmente vorrai che l'hashing sia eseguito anche in fase di compilazione, nel qual caso non è più time-critical. – CygnusX1

risposta

5

Ok, forse non è quello che vuoi sentire, ma considera questo: poiché parli di poche funzioni, meno di 50, la ricerca dell'hash dovrebbe essere trascurabile, anche con le collisioni. Hai effettivamente profilato e visto che la ricerca è fondamentale?

Quindi il mio consiglio è di concentrare le tue energie su qualcos'altro, molto probabilmente una perfetta funzione di hash non porterebbe alcun tipo di miglioramento delle prestazioni nel tuo caso.

Ho intenzione di fare un ulteriore passo avanti e dire che penso che per meno di 50 elementi una mappa piatta (buon vecchio 'vector) avrebbe prestazioni simili (o forse anche migliori a causa della localizzazione della cache). Ma ancora, sono necessarie misurazioni.

+0

questo non vuol dire che la domanda non sia interessante. Ci dovrebbe essere una soluzione reale per i casi in cui conta davvero e per il divertimento di trovare una soluzione. Penso solo che nel tuo caso specifico non sia giustificato. – bolov

+0

Non ho ancora profilato. Quindi stai suggerendo di provare con un vettore semplice e fare una ricerca lineare su di esso? – justHelloWorld

+0

@justHelloWorld yes .. Puoi anche provare a potenziare 'flat_mat' che li mantiene ordinati e ha una complessità di ricerca' log n'. E profilo! Senza profiling non ha quasi più senso parlare di ottimizzazioni. Trova gli hotspot e i colli di bottiglia e poi ottimizza ** quello ** !. Non ha assolutamente senso ottimizzare una porzione di codice in cui il programma spende solo lo 0,1% del tempo di esecuzione. – bolov