Как я могу использовать переменную python в качестве ввода / вывода для функции C с использованием Cython? - PullRequest
1 голос
/ 02 апреля 2020

Итак, у меня есть C реализация хэш-карты, где я могу хранить разнородные данные. Интерфейс для него выглядит примерно так:

error_e put(const char* key, const type_e type, const void* data);

error_e get(const char* key, const type_e type, void* data);

Где error_e - это перечисление, определяющее все различные ошибки, которые я могу получить, а type_e - это перечисление, определяющее все различные типы данных, которые я могу хранить. .
Теперь я хочу создать оболочку python для этого, используя cython. Это то, что у меня есть в моем hashmap.pyx:

cdef extern from "hashmap.h":
    cdef enum error_e:
      # some enum values...

    cdef enum type_e:
        type_empty  = 0,
        type_int32  = 1,
        type_float  = 2,
        type_string = 3

    error_e put(const char* key, const type_e type, const void* value)
    error_e get(const char* key, const type_e type, void* value)

class Hashmap:
    def __init__(self):
        self.type_dict = {
            int: type_int32,
            float: type_float,
            str: type_string
        }

    def put(self, key, value):
        if not type(value) in self.type_dict:
            return unknown_type

        # Not sure what to do here?

        return put(key.encode('utf-8'), self.type_dict[type(value)], &value) # Obviously doesn't work

    def get(self, key, val_type):
        if not val_type in self.type_dict:
            return unknown_type

        # Also not really sure what to do here

        res = get(key.encode('utf-8'), self.type_dict[val_type], # How can I get data out of here?)
        return (res, data)

У меня проблемы с получением пустого указателя из значения, которое должно быть записано / прочитано из хеш-карты из объекта python , Я пытался использовать операторы if else для разных типов и преобразовывать в них входные данные, но, похоже, я не могу тогда получить указатель на правильную вещь.

Так что это приводит меня к мои вопросы:
1) Как я могу использовать значение переменной python в качестве входа для функции C, которая принимает void*?
2) Как я могу получить данные из C и в переменную python, если функция принимает void*?

edit 1:

Некоторая дополнительная информация о том, как предполагается использовать функции C:
Предоставленный им void* является указателем на C объект со значением, которое вы хотите сохранить / получить. Тип значения указывается с помощью параметра type. В настоящее время поддерживаются только целые числа, числа с плавающей запятой и строки.
Я не хочу хранить python объекты в хэш-карте, и при этом я не хочу, чтобы код C имел какую-либо ссылку на python, так как я хочу сохранить значения с помощью python, сохранить хэш-карту, а затем извлечь и использовать их с помощью C.

edit 2:

Вот небольшой пример того, как можно добавить значения в хэш-карту в C:

int32_t some_int = 5;
put("int_key", type_int32, &some_int);

float some_float = 3.1416;
put("pi", type_float, &some_float);

char* some_string = "some text you want to store";
put("text", type_string, some_string);

А вот как вы можете получить значения из одного и того же:

int32_t returned_int;
get("int_key", type_int32, &returned_int);

float returned_float;
get("pi", type_float, &returned_float);

char returned_string[30];
get("text", type_string, returned_string);

При сохранении или получении чего-либо из хеш-карты, оно всегда будет либо копировать ваши данные во внутреннее хранилище или скопируйте данные из хранилища в указанное место «буфера».

1 Ответ

0 голосов
/ 07 апреля 2020

Одна вещь, которую мы все еще не знаем, как эта библиотека будет использоваться с C. Реализация Cython почти наверняка будет очень похожа на реализацию C, и без этого это в значительной степени всего лишь предположение.

Однако, если бы я делал это в C, я думаю, что структура, которую я буду использовать мы "Союз" - вы можете определить его в Cython как:

cdef union DataType:
    int32_t as_int
    float as_float
    char* as_string

put будет выглядеть примерно так:

cdef DataType data
if isinstance(value, int):
    data.as_int = value
# etc.
return put(key.encode('utf-8'), self.type_dict[type(value)], <void*>(&data)) # Obviously doesn't work

get является своего рода обратным:

cdef DataType data
res = get(key.encode('utf-8'), self.type_dict[val_type], <void*>(&data))

if something_to_do_with_val_type is int:
    out = data.as_int
# etc.

Очевидно, что строка C нуждается в некоторой дополнительной мысли, потому что (как всегда) что-то должно владеть памятью. Вы действительно рискуете получить указатель на внутренности объекта Python, который больше не существует. У меня нет достаточно информации, чтобы даже сделать разумное предположение о том, как вы должны справиться с этим.

...