Usually lisp, how can I check the type of an object in portable mode

I want to define a method that will specialize in an array type object with unsigned byte 8 elements. In sbcl, when you (make-array x :element-type '(unsigned-byte 8)) , the object class is implemented by SB-KERNEL :: SIMPLE -ARRAY-UNSIGNED-BYTE-8. Is there an implementation-independent way of specializing in unsigned array types?

+8
lisp common-lisp
source share
3 answers

Use the sharpness point to insert the implementation-dependent object class while reading:

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

The sharpsign-dot reader macro evaluates the form as it reads, defining the array class. This method will specialize in a class that uses a Common Lisp implementation for an array.

+11
source share

Note that the argument :ELEMENT-TYPE for MAKE-ARRAY does something special, and its exact behavior may be a bit unexpected.

Using this, you tell Common Lisp that ARRAY should be able to store elements of this type of element or some of its subtypes.

Then the Common Lisp system returns an array that can store these elements. It can be a specialized array or an array that can also store more general elements.

Note that this is not a type declaration, and it will not necessarily be checked at compile time or at run time.

The UPGRADED-ARRAY-ELEMENT-TYPE function tells you which item can actually be updated.

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) 

So, Lispworks 64bit has special arrays for 4 and 8 bit elements. For 12-bit elements, it allocates an array that can store up to 16 bit elements.

We generate an array that can store ten numbers up to 12 bits:

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

Let me check its type:

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

This is a simple array (not adjustable, without padding). It can store elements of type (UNSIGNED-BYTE 16) and its subtypes. It has a length of 10 and has one size.

+4
source share

In a regular function, you can use etypecase to send:

The following code is not self-sufficient, but should give an idea of ​​how to implement a function that performs point operations when even for three-dimensional arrays:

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

Here is the code:

 (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 (ab &optional (b-start (make-vec-i))) (declare ((simple-array ,long-type ,rank) ab) (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-ix b-start))) (do-region ((i) (x)) (setf (aref result i) (,op (aref a (+ i sx)) (aref bi))))))) (2 `(destructuring-bind (yx) (array-dimensions b) (let ((sx (vec-ix b-start)) (sy (vec-iy b-start))) (do-region ((ji) (yx)) (setf (aref result ji) (,op (aref a (+ j sy) (+ i sx)) (aref bji))))))) (3 `(destructuring-bind (zyx) (array-dimensions b) (let ((sx (vec-ix b-start)) (sy (vec-iy b-start)) (sz (vec-iz b-start))) (do-region ((kji) (zyx)) (setf (aref result kji) (,op (aref a (+ k sz) (+ j sy) (+ i sx)) (aref bkji)))))))) 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) ab b-start)) cases))) (let ((name (format-symbol ".~a" op))) (store-new-function name) (push `(defun ,name (ab &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)) 
0
source share

All Articles