Idiomatisches Umbrechen der C ++ - Vorlagentyp-API in C.

9

Ich arbeite daran, eine C ++ - API zu verpacken, die den Zugriff auf einen Datenspeicher (Hazelcast) in C-Funktionen ermöglicht, damit auf den Datenspeicher auch über C-only-Code zugegriffen werden kann.

Die Hazelcast C ++ - API für die Map-Datenstruktur sieht folgendermaßen aus:

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

Es werden Vorlagentypen keyund valueParameter verwendet. Da in C keine Vorlagen verfügbar sind, habe ich mir überlegt, für jede Spezialisierung der getMap<T, U>Methode eine Wrapper-Funktion zu erstellen . Das heißt, für jeden C-Typ. Obwohl ich bin mir bewusst , dass es signedund unsignedVersionen von C - Typen, ich bin gut mit der API - Begrenzung nur zu unterstützen int, double, float, char *für keyund value.

Also habe ich ein kleines Skript geschrieben, das alle Kombinationen automatisch generiert. Die exportierten Funktionen sehen folgendermaßen aus:

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
);

...

Erzeugen eine Funktion für get, set, containsmit allen möglichen Kombinationen von keyund valueArten erhöht die Menge an Code ziemlich viel, und obwohl ich den Code denke Erzeugung eine gute Idee ist, fügt es zusätzliche Komplexität , indem er eine Art von Code-generierenden Infrastruktur zu schaffen.

Eine andere Idee, die ich mir vorstellen kann, ist eine generische Funktion in C wie diese:

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
);

Welches kann so verwendet werden:

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

Dies macht es für den Anrufer etwas einfacher, da es die Last der korrekten Spezialisierung auf meinen Code verlagert, aber die Typensicherheit verliert und Casts erfordert. Außerdem würde für die Übergabe eines Int, wie void *es jetzt der Typ von keyund ist value, eine Besetzung wie (void *) (intptr_t) intValauf der Anruferseite benötigt, was wiederum nicht besonders schön zu lesen und zu pflegen ist.

  • Gibt es eine dritte Option, die ich nicht erkennen kann?
  • Welche Version würden C-Entwickler bevorzugen?

Ich bin meistens geneigt, alle Typkombinationen automatisch zu generieren und für jede eine Funktion zu erstellen, obwohl die Header-Datei vermutlich ziemlich groß wird.

Max
quelle
Viele positive Stimmen, noch keine Meinung. Ich nehme an, es ist ein häufiges Problem, wie vorlagentypisierte Methoden in C eingeschlossen werden.
Max
Ich bin mir nicht sicher, ob es üblich ist. Ich habe gestimmt, weil ich das Problem interessant finde.
MetaFight
Verwandte, wenn auch nicht wirklich hilfreich hier: stackoverflow.com/questions/1588788/…
Martin Ba

Antworten:

1

Das Generieren für alle Möglichkeiten schien mir keine sehr gute Lösung zu sein. Der Schlüssel und die Werte können auch Objekte sein. Daher sind die Möglichkeiten unendlich :(

Haben Sie sich die IMapImpl-Klasse angesehen? Diese Klasse verwendet keine Typen, sondern die Binärdaten (die nach der Serialisierung bereitgestellt werden). Daher würde eine andere Lösung darin bestehen, eine API zu schreiben, die diese Schnittstelle nachahmt und ein Serialisierungsdienstprogramm bereitstellt, das einen bestimmten Typ in die von dieser Schnittstelle benötigte Binärdatei konvertiert.

Z.B

API:

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

Dienstprogramm zur Serialisierung:

int hazelcast_binary_to_int(const Binary *data);

Möglicherweise müssen Sie diese Hilfsfunktionen für Objekttypen schreiben, die Sie unterstützen möchten. Dies kann eine brauchbare Schnittstelle sein. Es gibt Dinge zu beachten, wie z. B. Speicherverwaltung.

Serialisierung ist ein komplexes Thema, aber Sie können sicherlich zuerst mit der Unterstützung der primitiven Typen beginnen. Siehe http://docs.hazelcast.org/docs/3.6/manual/html-single/index.html#serialization und https://github.com/hazelcast/hazelcast/blob/master/hazelcast/src/main/java /com/hazelcast/internal/serialization/impl/ConstantSerializers.java für Details zur Serialisierung.

Ihsan Demir
quelle
Ich denke, das ist der richtige Weg für meinen Fall. Für Leute außerhalb des Regelkreises stellte ich dem Hazelcast-C ++ - Client github.com/hazelcast/hazelcast-cpp-client/pull/127 dieselbe Frage in einer PR, und ihsan, der Betreuer dieses C ++ - Clients, war so nett wie um auch hier auf SO auf meine Frage zu antworten.
Max