Je travaille sur l'encapsulation d'une API C ++ qui donne accès à un magasin de données (Hazelcast) dans les fonctions C, afin que le magasin de données soit également accessible à partir de code C uniquement.
L'API Hazelcast C ++ pour la structure de données de la carte ressemble à ceci:
auto map = hazelcastClient->client->getMap<int, string>(mapName);
map.put(key, value);
Il utilise des types de modèles key
et des value
paramètres. Comme il n'y a pas de modèles disponibles en C, j'ai pensé à créer une fonction wrapper pour chaque spécialisation de la getMap<T, U>
méthode. Autrement dit, pour chaque type C. Même si je suis conscient qu'il existe signed
et unsigned
versions de types C, je suis très bien avec la limitation de l'API pour soutenir que int
, double
, float
, char *
pour key
et value
.
J'ai donc écrit un petit script, qui génère automatiquement toutes les combinaisons. Les fonctions exportées ressemblent à ceci:
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
);
...
Génération d' une fonction pour get
, set
, contains
avec toutes les combinaisons possibles key
et value
types augmente la quantité de code tout à fait beaucoup, et même si je pense que la génération du code est une bonne idée, il ajoute une complexité supplémentaire d'avoir à créer une sorte d'infrastructures génératrices de code.
Une autre idée que je peux imaginer est une fonction générique en C, comme ceci:
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
);
Qui peut être utilisé comme ceci:
Hazelcast_Map_put(client, mapName, "key", API_TYPE_STR, "val", API_TYPE_STR, &err);
Cela rend un peu plus facile pour l'appelant, car cela déplace la charge d'obtenir la spécialisation correcte sur mon code, mais il perd la sécurité du type et nécessite des transtypages. De plus, pour passer un int, comme void *
c'est maintenant le type de key
et value
, un cast comme (void *) (intptr_t) intVal
serait nécessaire du côté des appelants, ce qui n'est pas très agréable à lire et à maintenir.
- Y a-t-il une troisième option que je ne peux pas reconnaître?
- Quelle version serait préférée par les développeurs C?
Je suis surtout enclin à générer automatiquement toutes les combinaisons de types et à créer une fonction pour chacune, bien que le fichier d'en-tête devienne assez énorme, je suppose.
la source
Réponses:
Générer pour toutes les possibilités ne me semblait pas être une très bonne solution. La clé et les valeurs peuvent également être des objets. Par conséquent, les possibilités sont infinies :(
Avez-vous regardé la classe IMapImpl? Cette classe n'utilise pas de types mais les données binaires (qui sont fournies après la sérialisation). Par conséquent, une autre solution serait d'écrire une API qui imite cette interface + fournissant un utilitaire de sérialisation qui convertit tout type donné en binaire dont cette interface a besoin.
Par exemple
API:
Utilitaire de sérialisation:
Vous devrez peut-être écrire ces fonctions d'assistance pour les types d'objets que vous souhaitez prendre en charge. Cela peut être une interface viable. Il y a des choses à considérer comme la gestion de la mémoire.
La sérialisation est un sujet complexe, mais vous pouvez sûrement commencer par prendre en charge les types primitifs en premier. Voir http://docs.hazelcast.org/docs/3.6/manual/html-single/index.html#serialization et https://github.com/hazelcast/hazelcast/blob/master/hazelcast/src/main/java /com/hazelcast/internal/serialization/impl/ConstantSerializers.java pour les détails de sérialisation.
la source