Optimizations
[clg] / glib / genums.lisp
index 4fb3c10..a2ef6cd 100644 (file)
@@ -15,7 +15,7 @@
 ;; License along with this library; if not, write to the Free Software
 ;; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
-;; $Id: genums.lisp,v 1.4 2004-11-06 21:39:58 espen Exp $
+;; $Id: genums.lisp,v 1.8 2005-02-10 20:27:54 espen Exp $
 
 (in-package "GLIB")
 
 (defun query-enum-values (type)
   (%query-enum-or-flags-values #'%enum-class-values '%enum-value type))
 
+(defun enum-int (enum type)
+  (funcall (to-alien-function type) enum))
+
+(defun int-enum (int type)
+  (funcall (from-alien-function type) int))
+
+(defun enum-mapping (type)
+  (rest (type-expand-to 'enum type)))
+
+
+;;;; Named enum types
+
+(defmacro define-enum-type (name &rest args)
+  (let ((enum-int (intern (format nil "~A-TO-INT" name)))
+       (int-enum (intern (format nil "INT-TO-~A" name))))
+    `(progn
+       (deftype ,name () '(enum ,@args))
+       (defun ,enum-int (value)
+        (ecase value
+          ,@(%map-enum args :enum-int)))
+       (defun ,int-enum (value)
+        (ecase value
+          ,@(%map-enum args :int-enum)))
+       (defmethod to-alien-form (form (type (eql ',name)) &rest args)
+        (declare (ignore type args))
+        (list ',enum-int form))
+       (defmethod from-alien-form (form (type (eql ',name)) &rest args)
+        (declare (ignore type args))
+        (list ',int-enum form))
+       (defmethod to-alien-function ((type (eql ',name)) &rest args)
+        (declare (ignore type args))
+        #',enum-int)
+       (defmethod from-alien-function ((type (eql ',name)) &rest args)
+        (declare (ignore type args))
+        #',int-enum)
+       (defmethod writer-function ((type (eql ',name)) &rest args)
+        (declare (ignore type args))
+        (let ((writer (writer-function 'signed)))
+          #'(lambda (enum location &optional (offset 0))
+              (funcall writer (,enum-int enum) location offset))))    
+       (defmethod reader-function ((type (eql ',name)) &rest args)
+        (declare (ignore type args))
+        (let ((reader (reader-function 'signed)))
+          #'(lambda (location &optional (offset 0))
+              (,int-enum (funcall reader location offset))))))))
 
 
 ;;;;  Generic flags type
   (declare (ignore type))
   `(loop
     for mapping in ',(%map-enum args :int-flags)
-    unless (zerop (logand int (first mapping)))
+    unless (zerop (logand ,int (first mapping)))
     collect (second mapping)))
 
 (defmethod to-alien-function ((type (eql 'flags)) &rest args)
   (%query-enum-or-flags-values #'%flags-class-values '%flags-value type))
 
 
+;;;; Named flags types
 
-;;;;
-
-(defun expand-enum-type (type-number &optional options)
+(defmacro define-flags-type (name &rest args)
+  (let ((flags-int (intern (format nil "~A-TO-INT" name)))
+       (int-flags (intern (format nil "INT-TO-~A" name))))
+    `(progn
+       (deftype ,name () '(flags ,@args))
+       (defun ,flags-int (value)
+        (ecase value
+          ,@(%map-enum args :flags-int)))
+       (defun ,int-flags (value)
+        (ecase value
+          ,@(%map-enum args :int-flags)))
+       (defmethod to-alien-form (form (type (eql ',name)) &rest args)
+        (declare (ignore type args))
+        (list ',flags-int form))
+       (defmethod from-alien-form (form (type (eql ',name)) &rest args)
+        (declare (ignore type args))
+        (list ',int-flags form))
+       (defmethod to-alien-function ((type (eql ',name)) &rest args)
+        (declare (ignore type args))
+        #',flags-int)
+       (defmethod from-alien-function ((type (eql ',name)) &rest args)
+        (declare (ignore type args))
+        #',int-flags)
+       (defmethod writer-function ((type (eql ',name)) &rest args)
+        (declare (ignore type args))
+        (let ((writer (writer-function 'signed)))
+          #'(lambda (flags location &optional (offset 0))
+              (funcall writer (,flags-int flags) location offset))))    
+       (defmethod reader-function ((type (eql ',name)) &rest args)
+        (declare (ignore type args))
+        (let ((reader (reader-function 'signed)))
+          #'(lambda (location &optional (offset 0))
+              (,int-flags (funcall reader location offset))))))))
+
+
+
+;;;; Type definition by introspection
+
+(defun expand-enum-type (type-number forward-p options)
+  (declare (ignore forward-p))
   (let* ((super (supertype type-number))
         (type (type-from-number type-number))
         (mappings (getf options :mappings))
            #'(lambda (mapping) (eq (second mapping) nil)) mappings))))
     `(progn
        (register-type ',type ,(find-type-name type-number))
-       (deftype ,type () '(,super ,@expanded-mappings)))))
+       ,(ecase super
+         (enum `(define-enum-type ,type ,@expanded-mappings))
+         (flags `(define-flags-type ,type ,@expanded-mappings))))))
 
 
 (register-derivable-type 'enum "GEnum" 'expand-enum-type)