Idiomatyczne zawijanie interfejsu API typu C ++ w C

9

Pracuję nad opakowaniem interfejsu API języka C ++, który zapewnia dostęp do magazynu danych (Hazelcast) w funkcjach C, aby dostęp do magazynu danych był również możliwy z kodu tylko w języku C.

Interfejs API Hazelcast C ++ dla struktury danych mapy wygląda następująco:

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

Wykorzystuje typy szablonów keyi valueparametry. Ponieważ w C nie ma dostępnych szablonów, pomyślałem o utworzeniu funkcji otoki dla każdej specjalizacji getMap<T, U>metody. Oznacza to, że dla każdego typu C. Chociaż zdaję sobie sprawę, że istnieją signedi unsignedwersje typu C, jestem zadowolony z ograniczeniem API obsługuje tylko int, double, float, char *dla keyi value.

Napisałem więc mały skrypt, który automatycznie generuje wszystkie kombinacje. Wyeksportowane funkcje wyglądają następująco:

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

...

Generowanie funkcję get, set, containsze wszystkich możliwych kombinacji keyi valuetypów zwiększa ilość kodu sporo i choć myślę generowania kodu jest dobrym pomysłem, to dodaje dodatkową złożoność konieczności tworzenia pewnego rodzaju infrastruktury do generowania kodu.

Innym pomysłem, jaki mogę sobie wyobrazić, jest jedna ogólna funkcja w C, taka jak ta:

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

Które można wykorzystać w ten sposób:

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

To sprawia, że ​​jest to trochę łatwiejsze dla wywołującego, ponieważ przenosi ciężar uzyskania poprawnej specjalizacji na mój kod, ale traci bezpieczeństwo typu i wymaga rzutowania. Ponadto, do przekazywania int, jak void *jest teraz typ keyi value, obsada podobna (void *) (intptr_t) intValbyłaby potrzebna po stronie wywołującej, co znowu nie jest super miłe do przeczytania i utrzymania.

  • Czy jest jakaś trzecia opcja, której nie mogę rozpoznać?
  • Która wersja byłaby preferowana przez programistów C?

Najczęściej jestem skłonny do automatycznego generowania wszystkich kombinacji typów i tworzenia funkcji dla każdej, chociaż plik nagłówka stanie się dość duży.

Max
źródło
Wiele głosów pozytywnych, brak opinii. Rozumiem, że to powszechny problem, jak zawijać metody wpisywane w szablonie w C?
Maks
Nie jestem pewien, czy to powszechne. Głosowałem, ponieważ uważam ten problem za interesujący.
MetaFight,
Powiązane, choć nie bardzo przydatne tutaj: stackoverflow.com/questions/1588788/...
Martin Ba

Odpowiedzi:

1

Generowanie dla wszystkich możliwości nie wydawało mi się bardzo dobrym rozwiązaniem. Klucz i wartości mogą być również obiektami. Dlatego możliwości są nieskończone :(

Czy spojrzałeś na klasę IMapImpl? Ta klasa nie używa typów, ale dane binarne (które są dostarczane po serializacji). Stąd innym rozwiązaniem byłoby napisanie interfejsu API naśladującego ten interfejs + udostępnienie narzędzia do szeregowania, które konwertuje dowolny typ na plik binarny wymagany przez ten interfejs.

Na przykład

API:

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

Narzędzie do serializacji:

int hazelcast_binary_to_int(const Binary *data);

Może być konieczne napisanie tych funkcji pomocniczych dla typów obiektów, które chcesz obsługiwać. Może to być realny interfejs. Należy wziąć pod uwagę takie kwestie, jak zarządzanie pamięcią.

Serializacja jest złożonym tematem, ale na pewno możesz zacząć od wspierania typów pierwotnych. Zobacz http://docs.hazelcast.org/docs/3.6/manual/html-single/index.html#serialization i https://github.com/hazelcast/hazelcast/blob/master/hazelcast/src/main/java /com/hazelcast/internal/serialization/impl/ConstantSerializers.java w celu uzyskania szczegółów serializacji.

ihsan demir
źródło
Myślę, że to jest właściwy sposób postępowania w mojej sprawie. Dla osób spoza pętli zadałem to samo pytanie w PR klientowi hazelcast C ++ github.com/hazelcast/hazelcast-cpp-client/pull/127, a ihsan, opiekun tego klienta C ++, był tak miły jak: aby odpowiedzieć również na moje pytanie tutaj na SO.
Maks