Вернуть Ruby's Fiddle::Pointer из функции C

В настоящее время я работаю над высокопроизводительным расширением Vector/Matrix Ruby gem C, так как нахожу встроенную реализацию громоздкой и не идеальной для большинства случаев, с которыми я лично столкнулся, а также в других областях.

Мой первый подход был реализован в Ruby как подкласс Fiddle::CStructEntity, так как цель состоит в том, чтобы сделать их оптимизированными для взаимодействия без необходимости преобразования (например, переход к собственным функциям OpenGL). Внедрение в C дает большую пользу для математики, но я столкнулся с препятствиями, пытаясь реализовать второстепенную функцию.

Я хотел, чтобы метод возвращал Fiddle::Pointer к структуре (в основном указатель на Rdata->data, Я хотел вернуть фактический Fiddle::Pointer объект. Возврат целочисленного адреса, упакованной строки и т. Д. Тривиален, и его использование можно легко расширить в методе Ruby для преобразования в Fiddle::Pointer как это:

def ptr
  # Assume address is an integer address returned from C
  Fiddle::Pointer.new(self.address, self.size)
end

Этот вид открыл мне вопрос, и можно ли вообще сделать такое из C? Fiddle не является частью ядра, библиотеки, она является частью стандартной библиотеки и, как таковая, на самом деле является просто самим расширением.

Эта проблема тривиальна и может быть легко решена с помощью пары строк кода на Ruby, как показано выше, но было более любопытно, если возвращать Fiddle объект был даже возможен с расширением C без хаков? Я не смог найти никаких примеров того, как это делается, и, как всегда, когда дело доходит до документации, касающейся Fiddle, она довольно проста и мало что объясняет.

1 ответ

Решение

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

Возможно, есть более сложные способы сделать это, включая заголовки для Fiddleи строил против этого, но это не было действительно жизнеспособным решением, так как я не хотел ограничивать свое расширение C только для работы с Ruby 2.0+, и было бы вполне приемлемо просто опустить метод в случае, если версия Ruby была менее 2,0

Сначала я включаю version.h, который дает доступ определяет макрос RUBY_API_VERSION_MAJOR, это все, что мне действительно нужно знать в отношении того, Fiddle будет присутствовать или нет.

Это будет сокращенная версия, чтобы просто показать, как получить Fiddle::Pointer класс как VALUEи создать экземпляр.

#if RUBY_API_VERSION_MAJOR >= 2

    rb_require("fiddle");
    VALUE fiddle = rb_const_get(rb_cObject, rb_intern("Fiddle"));
    rb_cFiddlePointer = rb_const_get(fiddle, rb_intern("Pointer"));

#endif

В этом примере класс хранится в rb_cFiddlePointer, который затем может быть использован для создания и возврата Fiddle::Pointer объект из C.

    // Get basic data about the struct
    struct RData *rdata = RDATA(self);
    VALUE *args = xmalloc(sizeof(VALUE) * 2);
    // Set the platform pointer-size address (could just use size_t here...)
    #if SIZEOF_INTPTR_T == 4
        args[0] = LONG2NUM((long) rdata->data);
    #elif SIZEOF_INTPTR_T == 8
        args[0] = LL2NUM((long long) rdata->data);
    #else 
        args[0] = INT2NUM(0);
    #endif
    // Get size of structure
    args[1] = INT2NUM(SIZE_OF_YOUR_STRUCTURE);
    VALUE ptr = rb_class_new_instance(2, args, rb_cFiddlePointer);
    xfree(args);
    return ptr;

После привязки функции к реальному методу Ruby вы можете вызвать его, чтобы получить размерный указатель на внутреннюю структуру в памяти.

Другие вопросы по тегам