Virgil

топ 100 блогов love5an09.10.2010 Привет всем, кто это читает, в т.ч. в различных лентах.

Анонсирую библиотеку Virgil - продвинутый высокоуровневый FFI для CL
http://github.com/Lovesan/virgil

Virgil это ссылка на Данте, да.

Библиотека базируется на cffi, но ориентирована на маршалинг, в противовес манипуляциям сырой памятью.

В зависимостях - cffi, babel(для поддержки строк в разных кодировках) и alexandria

Среди особенностей - поддержка ссылок(references) в стиле C++

Вообще, изначально это был бэкенд в другой моей библиотеке, ldx, но потом я его полностью переписал(и ldx теперь будет основываться на нем)

Банальный пример использования:

(define-external-function
    ("write" put-string)
    ()
  (int rv (if (>= rv 0)
            rv
            nil))
  "Puts a string to the specified file descriptor(stdout by default)"
  (fd int :optional 1)
  (string (& string))
  (count int :aux (length string)))


(put-string "Hello, world!") вернет 13 и напечатает 'Hello, world!' на stdout'е
(put-string "error" 2) - 5 и 'error' на stderr соответственно, а
(put-string "123" 0) вернет NIL

По пунктам:
Имя внешней функции и имя определяемой лисповской функции:

("write" put-string)


Тут пустой список, но вообще тут два необязательных параметра - конвенции вызова и библиотека, из которой внешнее имя вытаскивается [ по дефолту = (:cdecl :default) ]:

()


Тут список из трех элементов - тип возвращаемого значения, в данном случае - int, имя возвращаемого значения(rv) и "форма возвращаемого значения", которая позволяет определять, что именно возвращается после вызова функции. В данном случае мы определем, чтобы при ошибке write(2) функция нам возвращала NIL:

(int rv (if (>= rv 0)
          rv
          nil))


Строка документации:

"Puts a string to the specified file descriptor(stdout by default)"


Дальше идут спецификации аргументов функции в форме (имя тип &optional тип-параметра начальное-значение)
Тип параметра - одно из :primary(дефолтно) :aux :key и :optional,
которые определяют соответствующий тип аргумента в лисповской функции

(fd int :optional 1)


Дальше начинается интересное.

string это встроенный тип для строк, который в полной форме выглядит как
(string :encoding имя-кодировки[по умолчанию - :ascii] :byte-length длина-в-байтах)
(если :byte-length не указана, считается, что строка нуль-терминирована),

А вот (& string) это ссылка на строку.
Фактически, это указатель, но функция принимает в аргументы строку, и внутри, перед вызовом write, выделяет память под нее, маршалит в соответствии с кодировкой, а после вызова - освобождает память. Под определенные типы(с фиксированным размером) память может выделяться на стеке, а под некоторые - совсем не выделяться(конкретно - под массивы определенных типов в некоторых реализациях CL - указатель на данные просто берется из самого массива)

Тип "&", кроме типа на который ссылается, в полной форме имеет еще два аргумента - характер передачи данных(:in :out или :inout)[про это далее] и возможность обнуления
[если последнее не nil, указатель может быть нулевой, а лисповское значение - специальной константой void]

(string (& string))


:aux параметр не появляется в аргументах лисповской функции

(count int :aux (length string))


Среди встроенных типов есть структуры, которые определяются очень похоже на defstruct:
(define-struct (float4
                (:constructor float4 (x y z w))
                (:type (vector single-float)))
  (x float)
  (y float)
  (z float)
  (w float))


Теперь самое интересное. Как я сказал, ссылки могут определять характер передачи данных(по дефолту :in)

То есть, с их помощью мы можем передавать лисповские данные в нативные функции,
а нативные функции могут эти данные изменять. И, в коллбэках - наоборот.

Вот пример.
Определяем коллбэк, который у нас будет играть роль сторонней функции:

(define-callback (float4-add :stdcall)
    void ((out (& float4 :inout)) (v (& float4)))
  (map-into out #'+ out v))


И вызываем его из лиспа:

(let ((v (float4 1.0 2.0 3.0 4.0)))
   (external-pointer-call (get-callback 'float4-add)
     ((:stdcall)
      (void rv outval)
      ((& float4 :inout) outval)
      ((& float4) inval))
     v
     v))


==> #(2.0 4.0 6.0 8.0)

Кстати, поддерживаются функции с переменным числом аргументов:

(define-external-function "printf"
    ()
  (int)
  (format (& string))
  &rest)


define-external-function с аргументом &rest в конце списка типов создает макрос, а не функцию.

Создаваемый макрос имеет сигнатуру вида
(имя ((&optional новая-форма-возвращаемого-значения)
       &rest типы-дополнительных-аргументов)
      &rest аргументы)

Пример использования:

(printf (() (uint)) "%08X" 3405691582)

==> 8
и 'CAFEBABE' на stdout'е

Библиотека только вышла, и пока очень не хватает тестов, и, особенно, документации, но это временно.

Оставить комментарий

Архив записей в блогах:
Укладка мозаики и плитки чтобы бассейна Укладка мозаики сиречь плитки ради бассейна — не менее достопамятный остановка строительства бассейна, беспричинно подобно это финишный остановка отделки. И ежели присутствие облицовочных работах ...
ЛИПА: - Владимир Владимирович! Господин Президент ! Мы оба с Вами знаем цену слову, цену памяти, особенно если это касается политики. Я готов открыто признать свои ошибки, более того, я их признаю сейчас, в этом письме. Многое из того, что я делал, говорил, не ...
Я думаю все прекрасно помнят памятник "Вежливому насильнику кота" который был установлен в очередную годовщину оккупации Крыма в Бахчисарае? Ну да, тот самый где вежливый оккупант имеет деформированное тело и олигофренические черты лица. Вспомнили? Отлично. Так вот, автор сего шедевра, В ...
Глава поселения с депутатом и сыном пьяные похитили местную активистку в защиту животных, вывезли в лес, где пытали привязав к дереву и убили в конце концов. При том женщина успела позвонить в полицию до похищения. У неё на участке нашли следы от шин на снегу и по ним проследили до места ...
Пришла печальная новость о том, что Дмитрий Зимин все-таки решил прекратить финансирование научно-популярных издательских программ фонда "Династия". Наверное, это лучший подарок россиянам ко Дню славянской письменности и культуры. Даже как-то не по себе становится от фантазий на тему "А ...