В общем, как я могу проверить тип объекта в портативном виде - PullRequest
8 голосов
/ 21 мая 2011

Я хочу определить метод, который будет специализироваться на объекте типа массива с 8-ю элементами без знака.В sbcl, когда вы (make-array x :element-type '(unsigned-byte 8)), класс объектов реализуется с помощью SB-KERNEL :: SIMPLE-ARRAY-UNSIGNED-BYTE-8.Существует ли независимый от реализации способ специализации на типах массивов без знака?

Ответы [ 3 ]

11 голосов
/ 21 мая 2011

Используйте точку sharpsign для вставки класса объекта, зависящего от реализации, во время чтения:

(defmethod foo ((v #.(class-of (make-array 0 :element-type '(unsigned-byte 8)))))
  :unsigned-byte-8-array)

Макрос читателя sharpsign-dot оценивает форму во время чтения, определяя класс массива. Метод будет специализирован для класса, который конкретная реализация Common Lisp использует для массива.

4 голосов
/ 23 мая 2011

Обратите внимание, что аргумент :ELEMENT-TYPE для MAKE-ARRAY делает что-то особенное, и его точное поведение может быть немного удивительным.

Используя его, вы говорите Common Lisp, что ARRAY должен иметь возможность хранить элементы этого типа элемента или некоторых его подтипов.

Затем система Common Lisp вернет массив, который может хранить эти элементы. Это может быть специализированный массив или массив, который также может хранить более общие элементы.

Примечание: это не объявление типа, и оно не обязательно будет проверено во время компиляции или во время выполнения.

Функция UPGRADED-ARRAY-ELEMENT-TYPE сообщает вам, до какого элемента массив может быть обновлен.

LispWorks 64bit:

CL-USER 10 > (upgraded-array-element-type '(unsigned-byte 8))
(UNSIGNED-BYTE 8)

CL-USER 11 > (upgraded-array-element-type '(unsigned-byte 4))
(UNSIGNED-BYTE 4)

CL-USER 12 > (upgraded-array-element-type '(unsigned-byte 12))
(UNSIGNED-BYTE 16)

Итак, Lispworks 64bit имеет специальные массивы для 4- и 8-битных элементов. Для 12-битных элементов выделяется массив, который может хранить до 16-битных элементов.

Мы генерируем массив, который может хранить десять чисел длиной до 12 бит:

CL-USER 13 > (make-array 10
                         :element-type '(unsigned-byte 12)
                         :initial-element 0)
#(0 0 0 0 0 0 0 0 0 0)

Давайте проверим его тип:

CL-USER 14 > (type-of *)
(SIMPLE-ARRAY (UNSIGNED-BYTE 16) (10))

Это простой массив (не настраиваемый, без указателя заполнения). Он может хранить элементы типа (UNSIGNED-BYTE 16) и его подтипы. Длина 10 и одно измерение.

0 голосов
/ 03 июля 2011

В обычной функции вы можете использовать etypecase для выполнения отправки:

Следующий код не является автономным, но должен дать представление о том, как реализовать функцию, которая выполняет точечные операции, когда дажедля 3D-массивов:

(.* (make-array 3 :element-type 'single-float
                :initial-contents '(1s0 2s0 3s0))
    (make-array 3 :element-type 'single-float
                :initial-contents '(2s0 2s0 3s0)))

Вот код:

(def-generator (point-wise (op rank type) :override-name t)
  (let ((name (format-symbol ".~a-~a-~a" op rank type)))
    (store-new-function name)
    `(defun ,name (a b &optional (b-start (make-vec-i)))
       (declare ((simple-array ,long-type ,rank) a b)
                (vec-i b-start)
                (values (simple-array ,long-type ,rank) &optional))
       (let ((result (make-array (array-dimensions b)
                                 :element-type ',long-type)))
         ,(ecase rank
            (1 `(destructuring-bind (x)
                   (array-dimensions b)
                 (let ((sx (vec-i-x b-start)))
                   (do-region ((i) (x))
                     (setf (aref result i)
                           (,op (aref a (+ i sx))
                              (aref b i)))))))
            (2 `(destructuring-bind (y x)
                   (array-dimensions b)
                 (let ((sx (vec-i-x b-start))
                       (sy (vec-i-y b-start)))
                   (do-region ((j i) (y x))
                     (setf (aref result j i)
                           (,op (aref a (+ j sy) (+ i sx))
                              (aref b j i)))))))
            (3 `(destructuring-bind (z y x)
                   (array-dimensions b)
                 (let ((sx (vec-i-x b-start))
                       (sy (vec-i-y b-start))
                       (sz (vec-i-z b-start)))
                   (do-region ((k j i) (z y x))
                     (setf (aref result k j i)
                         (,op (aref a (+ k sz) (+ j sy) (+ i sx))
                            (aref b k j i))))))))
         result))))
#+nil
(def-point-wise-op-rank-type * 1 sf)

(defmacro def-point-wise-functions (ops ranks types)
  (let ((specific-funcs nil)
        (generic-funcs nil))
    (loop for rank in ranks do
         (loop for type in types do
              (loop for op in ops do
                   (push `(def-point-wise-op-rank-type ,op ,rank ,type)
                         specific-funcs))))
    (loop for op in ops do
         (let ((cases nil))
           (loop for rank in ranks do
                (loop for type in types do
                     (push `((simple-array ,(get-long-type type) ,rank)
                             (,(format-symbol  ".~a-~a-~a" op rank type) 
                               a b b-start))
                           cases)))
           (let ((name (format-symbol ".~a" op)))
             (store-new-function name)
            (push `(defun ,name (a b &optional (b-start (make-vec-i)))
                       (etypecase a
                         ,@cases
                         (t (error "The given type can't be handled with a generic
                 point-wise function."))))  
                  generic-funcs))))
    `(progn ,@specific-funcs
            ,@generic-funcs)))

(def-point-wise-functions (+ - * /) (1 2 3) (ub8 sf df csf cdf))
...