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'е

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

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

Архив записей в блогах:
Это обновление несомненно порадует фанатов FireFox. Встречайте русскую, финальную версию SpeedFox 1.9. Теперь этот браузер готов использовать всю мощь вашего компьютера, особенно это почувствуют владельцы мощных машин. В арсенале SpeedFox'a теперь ...
Государственные агентства ТАСС и РИА Новости опубликовали почти одинаковые новости, согласно которым Владимир Путин выразил уверенность, что Россия «выйдет с победой из непростого времени». Новости выглядят как реакция президента на обострение отношений с США из-за ...
Ура! Только что у нас в Стамбуле отгремела и закончилась глобальная партнёрская конференция-2022. Ура-ура! 1. Вот здесь: 2. Ну вы же понимаете, что сейчас (вот прямо сейчас) устраивать подобные события как-то весьма стрёмно... Вот и мы пугались. Но пропугались - и сделали! 3. ...
Грозный — мой город. Едва приземлившись, отправляюсь с замиранием сердца открывать его заново, гуляю по проспектам имени Владимира Путина и Ахмат-Хаджи Кадырова. Отделанные дорогой плиткой тротуары, широченные дороги, асфальтированные так здорово, что не найти изъяна, по ним мчатся иномар ...
Вчера город накрыл почти суточный снегопад. Гневных постов  было много. Сейчас, просто немного фактов. Ещё Наполеон сказал, что его победила не Россия, а российская зима. Я не знаю, откуда в наших гражданах уверенность того, что стихия снега проста и справиться с ней может каждый дур ...