Involucro idiomatico dell'API del tipo di modello C ++ in C

9

Sto lavorando su una API C ++ che fornisce accesso a un archivio dati (Hazelcast) nelle funzioni C, in modo che l'archivio dati sia accessibile anche dal codice C-only.

L'API C ++ Hazelcast per la struttura dati della mappa ha il seguente aspetto:

auto map = hazelcastClient->client->getMap<int, string>(mapName);
map.put(key, value);

Utilizza i tipi di modello per i parametri key e value . Poiché non ci sono modelli disponibili in C, ho pensato di creare una funzione wrapper per ogni specializzazione del metodo getMap<T, U> . Cioè, per ogni tipo di C. Sebbene io sappia che ci sono signed e unsigned versioni di tipi C, sto bene limitando l'API per supportare solo int , double , float , char * per key e value .

Quindi ho scritto un piccolo script, che genera automaticamente tutte le combinazioni. Le funzioni esportate hanno questo aspetto:

int Hazelcast_Map_put_int_string(
    Hazelcast_Client_t *hazelcastClient,
    const char *mapName,
    int key,
    char *value,
    char** errptr
);

int Hazelcast_Map_put_int_int(
    Hazelcast_Client_t *hazelcastClient,
    const char *mapName,
    int key,
    int value,
    char** errptr
);

...

Generare una funzione per get , set , contains con tutte le possibili combinazioni di key e value tipi aumenta la quantità di codice molto, e anche se penso che generare il codice sia una buona idea, aggiunge ulteriore complessità dovendo creare una sorta di infrastruttura di generazione del codice.

Un'altra idea che posso immaginare è una funzione generica in C, come questa:

int Hazelcast_Map_put(
    Hazelcast_Client_t *hazelcastClient,
    const char *mapName,

    const void *key,
    API_TYPE key_type,

    const void *value,
    API_TYPE value_type,

    char** errptr
);

Che può essere usato in questo modo:

Hazelcast_Map_put(client, mapName, "key", API_TYPE_STR, "val", API_TYPE_STR, &err);

Questo rende un po 'più facile per il chiamante, perché sposta l'onere di ottenere la specializzazione corretta sul mio codice, ma perde la sicurezza del tipo e richiede cast. Inoltre, per passare un int, come void * è ora il tipo di key e value , sarebbe necessario un cast come (void *) (intptr_t) intVal sul lato chiamanti, che di nuovo non è super bello da leggere e mantenere .

  • C'è qualche terza opzione, che non riesco a riconoscere?
  • Quale versione sarebbe preferibile agli sviluppatori C?

Sono per lo più propenso a generare automaticamente tutte le combinazioni di tipi e creare una funzione per ciascuna, anche se il file di intestazione diventerà piuttosto enorme, suppongo.

    
posta Max 08.05.2016 - 02:57
fonte

1 risposta

1

Generare per tutte le possibilità non sembrava essere una soluzione molto buona per me. La chiave e i valori possono essere anche oggetti. Quindi, le possibilità sono infinite: (

Hai dato un'occhiata alla classe IMapImpl? Questa classe non usa tipi ma i dati binari (che sono forniti dopo la serializzazione). Quindi, un'altra soluzione sarebbe scrivere un'API che simula questa interfaccia + fornendo un'utilità di serializzazione che converte qualsiasi tipo di dato nel binario di cui ha bisogno questa interfaccia.

per es.

API:

struct Binary {
   byte *data;
   size_t length;
   int32_t dataType;
};
Binary *hazelcast_map_put(const Binary *key, const Binary *value);

Utilità di serializzazione:

int hazelcast_binary_to_int(const Binary *data);

Potrebbe essere necessario scrivere queste funzioni di supporto per i tipi di oggetto che si desidera supportare. Questa potrebbe essere un'interfaccia valida. Ci sono cose da considerare come la gestione della memoria.

La serializzazione è un argomento complesso, ma puoi sicuramente iniziare con il supporto dei tipi primitivi. Vedi link e link per dettagli sulla serializzazione.

    
risposta data 09.05.2016 - 17:02
fonte

Leggi altre domande sui tag