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 key
i value
parametry. 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ą signed
i unsigned
wersje typu C, jestem zadowolony z ograniczeniem API obsługuje tylko int
, double
, float
, char *
dla key
i 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
, contains
ze wszystkich możliwych kombinacji key
i value
typó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 key
i value
, obsada podobna (void *) (intptr_t) intVal
był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.
źródło
Odpowiedzi:
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:
Narzędzie do serializacji:
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.
źródło