;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; ;;;
-;;; Confidential and proprietary information of ITA Software, Inc. ;;;
+;;; Free Software published under an MIT-like license. See LICENSE ;;;
;;; ;;;
-;;; Copyright (c) 2012 ITA Software, Inc. All rights reserved. ;;;
+;;; Copyright (c) 2012 Google, Inc. All rights reserved. ;;;
;;; ;;;
;;; Original author: Scott McKay ;;;
;;; ;;;
(in-package "PROTO-IMPL")
-;;; Code generation utilities
-
-(defun class-name->proto (x)
- "Given a Lisp class name, returns a Protobufs message or enum name."
- (remove-if-not #'alphanumericp
- (camel-case (format nil "~A" x) :separators '(#\- #\_ #\/))))
-
-(defun enum-name->proto (x &optional prefix)
- "Given a Lisp enum value name, returns a Protobufs enum value name."
- (let* ((x (string-upcase (string x)))
- (x (if (and prefix (starts-with x prefix)) (subseq x (length prefix)) x)))
- (remove-if-not #'(lambda (x) (or (alphanumericp x) (eql x #\_)))
- (format nil "~{~A~^_~}" (split-string x :separators '(#\- #\_ #\/ #\.))))))
-
-(defun slot-name->proto (x)
- "Given a Lisp slot name, returns a Protobufs field name."
- (remove-if-not #'alphanumericp
- (camel-case-but-one (format nil "~A" x) :separators '(#\- #\_ #\/ #\.))))
-
-
-(defun proto->class-name (x &optional package)
- "Given a Protobufs message or enum type name, returns a Lisp class or type name."
- (let ((name (nstring-upcase (uncamel-case x))))
- (if package (intern name package) (make-symbol name))))
-
-(defun proto->enum-name (x &optional package)
- "Given a Protobufs enum value name, returns a Lisp enum value name."
- (let ((name (format nil "~{~A~^-~}" (split-string (string-upcase x) :separators '(#\_)))))
- (if package (intern name package) (make-symbol name))))
-
-(defun proto->slot-name (x &optional package)
- "Given a Protobufs field value name, returns a Lisp slot name."
- (let ((name (nstring-upcase (uncamel-case x))))
- (if package (intern name package) (make-symbol name))))
-
-
-(defun make-lisp-symbol (string)
- "Intern a string of the 'package:string' and return the symbol."
- (let* ((colon (position #\: string))
- (pkg (if colon (subseq string 0 colon) "KEYWORD"))
- (sym (if colon (subseq string (+ colon 1)) string)))
- (intern sym pkg)))
-
-#-quux
-(defun fintern (format-string &rest format-args)
- "Interns a new symbol in the current package."
- (declare (dynamic-extent format-args))
- (intern (nstring-upcase (apply #'format nil format-string format-args))))
-
-#-quux
-(defun kintern (format-string &rest format-args)
- "Interns a new symbol in the keyword package."
- (declare (dynamic-extent format-args))
- (intern (nstring-upcase (apply #'format nil format-string format-args)) "KEYWORD"))
-
-
-(define-condition protobufs-warning (warning simple-condition) ())
-
-(defun protobufs-warn (format-control &rest format-arguments)
- (warn 'protobufs-warning
- :format-control format-control
- :format-arguments format-arguments))
-
-\f
-;;; Other utilities
-
-#-quux
-(progn
+;;; Optimized fixnum arithmetic
-;;; Parameterized list types
+(eval-when (:compile-toplevel :load-toplevel :execute)
-(deftype list-of (type)
- (cond ((eq type t) 'list)
- ((eq type 'null) 'null)
- (t
- (let ((predicate (%declare-list-of type)))
- `(and list (satisfies ,predicate))))))
-
-(defmacro declare-list-of (type)
- `(eval-when (:compile-toplevel :load-toplevel :execute)
- (%declare-list-of ',type)))
-
-(defun %declare-list-of (type)
- (unless (or (eq type t)
- (eq type 'null))
- (let ((predicate (intern (format nil "~A-~A" 'list-of type) (symbol-package type))))
- (unless (fboundp predicate)
- (setf (symbol-function predicate)
- #'(lambda (list)
- (and (listp list)
- (loop for elt in list
- always (typep elt type))))))
- predicate)))
-
-(declare-list-of integer)
-(declare-list-of string)
-(declare-list-of keyword)
-(declare-list-of symbol)
-(declare-list-of single-float)
-(declare-list-of double-float)
+(defparameter $optimize-default '(optimize (speed 1) (safety 3) (debug 3))
+ "Compiler optimization settings for safe, debuggable code.")
+(defparameter $optimize-fast-unsafe '(optimize (speed 3) (safety 0) (debug 0))
+ "Compiler optimization settings for fast, unsafe, hard-to-debug code.")
+) ;eval-when
-;;; Optimized fixnum arithmetic
(defmacro i+ (&rest fixnums)
`(the fixnum (+ ,@(loop for n in fixnums collect `(the fixnum ,n)))))
(define-modify-macro idecf (&optional (delta 1)) i-)
(defmacro ildb (bytespec value)
- `(ldb ,bytespec (the fixnum ,value)))
+ `(the fixnum (ldb ,bytespec (the fixnum ,value))))
-;;; Collectors, etc
+;;; String utilities
+
+(defun starts-with (string prefix &key (start 0))
+ "Returns true if 'string' starts with the prefix 'prefix' (case insensitive)."
+ (and (i>= (length string) (i+ start (length prefix)))
+ (string-equal string prefix :start1 start :end1 (i+ start (length prefix)))
+ prefix))
+
+(defun ends-with (string suffix &key (end (length string)))
+ "Returns true if 'string' ends with the prefix 'prefix' (case insensitive)."
+ (and (i>= end (length suffix))
+ (string-equal string suffix :start1 (i- end (length suffix)) :end1 end)
+ suffix))
+
+(defun strcat (&rest strings)
+ "Concatenate a bunch of strings."
+ (declare (dynamic-extent strings))
+ (apply #'concatenate 'string strings))
+
+
+;; (camel-case "camel-case") => "CamelCase"
+(defun camel-case (string &optional (separators '(#\-)))
+ "Take a hyphen-separated string and turn it into a camel-case string."
+ (let ((words (split-string string :separators separators)))
+ (format nil "~{~@(~A~)~}" words)))
+
+;; (camel-case-but-one "camel-case") => "camelCase"
+(defun camel-case-but-one (string &optional (separators '(#\-)))
+ "Take a hyphen-separated string and turn its tail into a camel-case string."
+ (let ((words (split-string string :separators separators)))
+ (format nil "~(~A~)~{~@(~A~)~}" (car words) (cdr words))))
+
+
+;; (uncamel-case "CamelCase") => "CAMEL-CASE"
+;; (uncamel-case "TCPConnection") => "TCP-CONNECTION"
+;; (uncamel-case "NewTCPConnection") => "NEW-TCP-CONNECTION"
+;; (uncamel-case "new_RPC_LispService") => "NEW-RPC-LISP-SERVICE"
+;; (uncamel-case "RPC_LispServiceRequest_get_request") => "RPC-LISP-SERVICE-REQUEST-GET-REQUEST"
+;; (uncamel-case "TCP2Name3") => "TCP2-NAME3"
+(defun uncamel-case (name)
+ "Take a camel-case string and turn it into a hyphen-separated string."
+ ;; We need a whole state machine to get this right
+ (labels ((uncamel (chars state result)
+ (let ((ch (first chars)))
+ (cond ((null chars)
+ result)
+ ((upper-case-p ch)
+ (uncamel (rest chars) 'upper
+ (case state
+ ((upper)
+ ;; "TCPConnection" => "TCP-CONNECTION"
+ (if (and (second chars) (lower-case-p (second chars)))
+ (list* ch #\- result)
+ (cons ch result)))
+ ((lower digit) (list* ch #\- result))
+ (otherwise (cons ch result)))))
+ ((lower-case-p ch)
+ (uncamel (rest chars) 'lower
+ (cons (char-upcase ch) result)))
+ ((digit-char-p ch)
+ (uncamel (rest chars) 'digit
+ (cons ch result)))
+ ((or (eql ch #\-) (eql ch #\_))
+ (uncamel (rest chars) 'dash
+ (cons #\- result)))
+ ((eql ch #\.)
+ (uncamel (rest chars) 'dot
+ (cons #\. result)))
+ (t
+ (error "Invalid name character: ~A" ch))))))
+ (strcat (nreverse (uncamel (concatenate 'list name) nil ())))))
+
+
+(defun split-string (line &key (start 0) (end (length line)) (separators '(#\-)))
+ "Given a string 'string', splits it at each of the separators.
+ Returns a list of the string pieces, with empty pieces removed."
+ (unless (i= start end)
+ (loop for this fixnum = start then (i+ next 1)
+ for next fixnum = (or (position-if #'(lambda (ch) (member ch separators)) line
+ :start this :end end)
+ end)
+ for piece = (string-right-trim '(#\space) (subseq line this next))
+ when (not (i= (length piece) 0))
+ collect piece
+ until (i>= next end))))
+
+
+;;; Managing symbols
(defmacro with-gensyms ((&rest bindings) &body body)
`(let ,(mapcar #'(lambda (b) `(,b (gensym ,(string b)))) bindings)
,@body))
-(defmacro with-prefixed-accessors (names (prefix object) &body body)
- `(with-accessors (,@(loop for name in names
- collect `(,name ,(fintern "~A~A" prefix name))))
- ,object
- ,@body))
+(defun make-lisp-symbol (string)
+ "Intern a string of the 'package:string' and return the symbol."
+ (let* ((string (string string))
+ (colon (position #\: string))
+ (pkg (if colon (subseq string 0 colon) "KEYWORD"))
+ (sym (if colon (subseq string (+ colon 1)) string)))
+ (intern sym pkg)))
+(defun fintern (format-string &rest format-args)
+ "Interns a new symbol in the current package."
+ (declare (dynamic-extent format-args))
+ (intern (nstring-upcase (apply #'format nil format-string format-args))))
+
+(defun kintern (format-string &rest format-args)
+ "Interns a new symbol in the keyword package."
+ (declare (dynamic-extent format-args))
+ (intern (nstring-upcase (apply #'format nil format-string format-args)) "KEYWORD"))
+
+(defun keywordify (x)
+ "Given a symbol designator 'x', return a keyword whose name is 'x'.
+ If 'x' is nil, this returns nil."
+ (check-type x (or string symbol null))
+ (cond ((null x) nil)
+ ((keywordp x) x)
+ ((symbolp x) (keywordify (symbol-name x)))
+ ((zerop (length x)) nil)
+ ((string-not-equal x "nil")
+ (intern (string-upcase x) (find-package "KEYWORD")))
+ (t nil)))
+
+
+;;; Collectors, etc
(defmacro with-collectors ((&rest collection-descriptions) &body body)
+ "'collection-descriptions' is a list of clauses of the form (coll function).
+ The body can call each 'function' to add a value to 'coll'. 'function'
+ runs in constant time, regardless of the length of the list."
(let ((let-bindings ())
(flet-bindings ())
(dynamic-extents ())
`((declare (dynamic-extent ,@dynamic-extents))))
,@body))))
+(defmacro with-prefixed-accessors (names (prefix object) &body body)
+ `(with-accessors (,@(loop for name in names
+ collect `(,name ,(fintern "~A~A" prefix name))))
+ ,object
+ ,@body))
+
+(defmacro dovector ((var vector &optional value) &body body)
+ "Like 'dolist', but iterates over the vector 'vector'."
+ (with-gensyms (vidx vlen vvec)
+ `(let* ((,vvec ,vector)
+ (,vlen (length ,vvec)))
+ (loop for ,vidx fixnum from 0 below ,vlen
+ as ,var = (aref ,vvec ,vidx)
+ do (progn ,@body)
+ finally (return ,value)))))
+
+(defmacro doseq ((var sequence &optional value) &body body)
+ "Iterates over a sequence, using 'dolist' or 'dovector' depending on
+ the type of the sequence. In optimized code, this turns out to be
+ faster than (map () #'f sequence).
+ Note that the body gets expanded twice!"
+ (with-gensyms (vseq)
+ `(let ((,vseq ,sequence))
+ (if (vectorp ,vseq)
+ (dovector (,var ,vseq ,value)
+ ,@body)
+ (dolist (,var ,vseq ,value)
+ ,@body)))))
+
+
+;;; Functional programming, please
(defun curry (function &rest args)
+ "Returns a function that applies 'function' to 'args', plus any
+ additional arguments given at the call site."
(if (and args (null (cdr args))) ;fast test for length = 1
(let ((arg (car args)))
#'(lambda (&rest more-args)
form))
-;;; String utilities
+;;; Types
-(defun starts-with (string prefix &key (start 0))
- (and (i>= (length string) (i+ start (length prefix)))
- (string-equal string prefix :start1 start :end1 (i+ start (length prefix)))
- prefix))
+;; A parameterized list type for repeated fields
+;; The elements aren't type-checked
+(deftype list-of (type)
+ (if (eq type 'nil) ;a list that cannot have any element (element-type nil) is null
+ 'null
+ 'list))
+
+;; The same, but use a (stretchy) vector
+(deftype vector-of (type)
+ (if (eq type 'nil) ;an array that cannot have any element (element-type nil) is of size 0
+ '(array * (0))
+ '(array * (*)))) ;a 1-dimensional array of any type
+
+;; This corresponds to the :bytes Protobufs type
+(deftype byte-vector () '(array (unsigned-byte 8) (*)))
+
+(defun make-byte-vector (size)
+ (make-array size :element-type '(unsigned-byte 8)))
+
+;; The Protobufs integer types
+(deftype int32 () '(signed-byte 32))
+(deftype int64 () '(signed-byte 64))
+(deftype uint32 () '(unsigned-byte 32))
+(deftype uint64 () '(unsigned-byte 64))
+(deftype sint32 () '(signed-byte 32))
+(deftype sint64 () '(signed-byte 64))
+(deftype fixed32 () '(signed-byte 32))
+(deftype fixed64 () '(signed-byte 64))
+(deftype sfixed32 () '(signed-byte 32))
+(deftype sfixed64 () '(signed-byte 64))
+
+;; Type expansion
+(defun type-expand (type)
+ #+allegro (excl:normalize-type type :default type)
+ #+ccl (ccl::type-expand type)
+ #+clisp (ext:type-expand type)
+ #+cmu (kernel:type-expand type)
+ #+lispworks (type:expand-user-type type)
+ #+sbcl (sb-ext:typexpand type)
+ #-(or allegro ccl clisp cmu lispworks sbcl) type)
-(defun ends-with (string suffix &key (end (length string)))
- (and (i>= end (length suffix))
- (string-equal string suffix :start1 (i- end (length suffix)) :end1 end)
- suffix))
+;;; Code generation utilities
+(defvar *proto-name-separators* '(#\- #\_ #\/ #\space))
+(defvar *camel-case-field-names* nil)
+
+(defun find-proto-package (name)
+ "A very fuzzy definition of 'find-package'."
+ (typecase name
+ ((or string symbol)
+ ;; Try looking under the given name and the all-uppercase name
+ (or (find-package (string name))
+ (find-package (string-upcase (string name)))))
+ (cons
+ ;; If 'name' is a list, it's actually a fully-qualified path
+ (or (find-proto-package (first name))
+ (find-proto-package (format nil "~{~A~^.~}" name))))))
+
+;; "class-name" -> "ClassName", ("ClassName")
+;; "outer-class.inner-class" -> "InnerClass", ("OuterClass" "InnerClass")
+(defun class-name->proto (x)
+ "Given a Lisp class name, returns a Protobufs message or enum name.
+ The second value is the fully qualified name, as a list."
+ (let* ((xs (split-string (string x) :separators '(#\.)))
+ (ns (loop for x in (butlast xs)
+ collect (remove-if-not #'alphanumericp
+ (camel-case (format nil "~A" x) *proto-name-separators*))))
+ (nx (car (last xs)))
+ (name (remove-if-not #'alphanumericp (camel-case nx *proto-name-separators*))))
+ (values name (append ns (list name))
+ ;; This might be the name of a package, too
+ (format nil "~{~A~^.~}" (butlast xs)))))
+
+;; "enum-value" -> "ENUM_VALUE", ("ENUM_VALUE")
+;; "class-name.enum-value" -> "ENUM_VALUE", ("ClassName" "ENUM_VALUE")
+(defun enum-name->proto (x &optional prefix)
+ "Given a Lisp enum value name, returns a Protobufs enum value name.
+ The second value is the fully qualified name, as a list."
+ (let* ((xs (split-string (string x) :separators '(#\.)))
+ (ns (loop for x in (butlast xs)
+ collect (remove-if-not #'alphanumericp
+ (camel-case (format nil "~A" x) *proto-name-separators*))))
+ (nx (string-upcase (car (last xs))))
+ (nx (if (and prefix (starts-with nx prefix)) (subseq nx (length prefix)) nx))
+ ;; Keep underscores, they are standards separators in Protobufs enum names
+ (name (remove-if-not #'(lambda (x) (or (alphanumericp x) (eql x #\_)))
+ (format nil "~{~A~^_~}"
+ (split-string nx :separators *proto-name-separators*)))))
+ (values name (append ns (list name))
+ (format nil "~{~A~^.~}" (butlast xs)))))
+
+;; "slot-name" -> "slot_name", ("slot_name") or "slotName", ("slotName")
+;; "class-name.slot-name" -> "Class.slot_name", ("ClassName" "slot_name")
+(defun slot-name->proto (x)
+ "Given a Lisp slot name, returns a Protobufs field name.
+ The second value is the fully qualified name, as a list."
+ (let* ((xs (split-string (string x) :separators '(#\.)))
+ (ns (loop for x in (butlast xs)
+ collect (remove-if-not #'alphanumericp
+ (camel-case (format nil "~A" x) *proto-name-separators*))))
+ (nx (string-downcase (car (last xs))))
+ (name (if *camel-case-field-names*
+ (remove-if-not #'alphanumericp
+ (camel-case-but-one (format nil "~A" nx) *proto-name-separators*))
+ ;; Keep underscores, they are standards separators in Protobufs field names
+ (remove-if-not #'(lambda (x) (or (alphanumericp x) (eql x #\_)))
+ (format nil "~{~A~^_~}"
+ (split-string nx :separators *proto-name-separators*))))))
+ (values name (append ns (list name))
+ (format nil "~{~A~^.~}" (butlast xs)))))
+
+
+;; "ClassName" -> 'class-name
+;; "cl-user.ClassName" -> 'cl-user::class-name
+;; "cl-user.OuterClass.InnerClass" -> 'cl-user::outer-class.inner-class
+(defun proto->class-name (x &optional package)
+ "Given a Protobufs message or enum type name, returns a Lisp class or type name.
+ This resolves Protobufs qualified names as best as it can."
+ (let* ((xs (split-string (substitute #\- #\_ (uncamel-case x))
+ :separators '(#\.)))
+ (pkg1 (and (cdr xs) (find-proto-package (first xs))))
+ (pkgn (and (cdr xs) (find-proto-package (butlast xs))))
+ (package (or pkg1 pkgn package))
+ (name (format nil "~{~A~^.~}" (if pkg1 (cdr xs) (if pkgn (last xs) xs)))))
+ (values (if package (intern name package) (make-symbol name)) package xs
+ ;; This might be the name of a package, too
+ (format nil "~{~A~^.~}" (butlast xs)))))
+
+;; "ENUM_VALUE" -> :enum-value
+;; "cl-user.ENUM_VALUE" -> :enum-value
+;; "cl-user.OuterClass.ENUM_VALUE" -> :enum-value
+(defun proto->enum-name (x &optional package)
+ "Given a Protobufs enum value name, returns a Lisp enum value name.
+ This resolves Protobufs qualified names as best as it can."
+ (let* ((xs (split-string (substitute #\- #\_ (uncamel-case x))
+ :separators '(#\.)))
+ (pkg1 (and (cdr xs) (find-proto-package (first xs))))
+ (pkgn (and (cdr xs) (find-proto-package (butlast xs))))
+ (package (or pkg1 pkgn package))
+ (name (format nil "~{~A~^.~}" (if pkg1 (cdr xs) (if pkgn (last xs) xs)))))
+ (values (kintern name) package xs
+ (format nil "~{~A~^.~}" (butlast xs)))))
+
+;; "slot_name" or "slotName" -> 'slot-name
+;; "cl-user.slot_name" or "cl-user.slotName" -> 'cl-user::slot-name
+;; "cl-user.OuterClass.slot_name" -> 'cl-user::outer-class.slot-name
+(defun proto->slot-name (x &optional package)
+ "Given a Protobufs field value name, returns a Lisp slot name.
+ This resolves Protobufs qualified names as best as it can."
+ (let* ((xs (split-string (substitute #\- #\_ (uncamel-case x))
+ :separators '(#\.)))
+ (pkg1 (and (cdr xs) (find-proto-package (first xs))))
+ (pkgn (and (cdr xs) (find-proto-package (butlast xs))))
+ (package (or pkg1 pkgn package))
+ (name (format nil "~{~A~^.~}" (if pkg1 (cdr xs) (if pkgn (last xs) xs)))))
+ (values (if package (intern name package) (make-symbol name)) package xs
+ (format nil "~{~A~^.~}" (butlast xs)))))
-;; (camel-case "camel-case") => "CamelCase"
-(defun camel-case (string &key (separators '(#\-)))
- (let ((words (split-string string :separators separators)))
- (format nil "~{~@(~A~)~}" words)))
-;; (camel-case-but-one "camel-case") => "camelCase"
-(defun camel-case-but-one (string &key (separators '(#\-)))
- (let ((words (split-string string :separators separators)))
- (format nil "~(~A~)~{~@(~A~)~}" (car words) (cdr words))))
+;;; Warnings
-;; (uncamel-case "CamelCase") => "Camel-Case"
-(defun uncamel-case (string &key (separator #\-))
- (format nil (format nil "~~{~~A~~^~C~~}" separator)
- (cl-ppcre:split "(?<=[a-z])(?=[A-Z])" string)))
+(define-condition protobufs-warning (warning simple-condition) ())
+(defun protobufs-warn (format-control &rest format-arguments)
+ (warn 'protobufs-warning
+ :format-control format-control
+ :format-arguments format-arguments))
-(defun split-string (line &key (start 0) (end (length line)) (separators '(#\-)))
- (unless (i= start end)
- (loop for this fixnum = start then (i+ next 1)
- for next fixnum = (or (position-if #'(lambda (ch) (member ch separators)) line
- :start this :end end)
- end)
- for piece = (string-right-trim '(#\space) (subseq line this next))
- when (not (i= (length piece) 0))
- collect piece
- until (i>= next end))))
-) ;#-quux
+#-(or allegro lispworks)
+(defmacro without-redefinition-warnings (() &body body)
+ `(progn ,@body))
+
+#+allegro
+(defmacro without-redefinition-warnings (() &body body)
+ `(excl:without-redefinition-warnings ,@body))
+
+#+lispworks
+(defmacro without-redefinition-warnings (() &body body)
+ `(let ((dspec:*redefinition-action* :quiet)) ,@body))
\f
-;;; Floating point utilities
+;;; Portable floating point utilities
-#+(or abcl allegro cmu sbcl lispworks)
+#+(or abcl allegro ccl cmu sbcl lispworks)
(defun single-float-bits (x)
(declare (type single-float x))
- #+abcl (system:single-float-bits float)
+ #+abcl (system:single-float-bits x)
#+allegro (multiple-value-bind (high low)
- (excl:single-float-to-shorts float)
+ (excl:single-float-to-shorts x)
(declare (type (unsigned-byte 16) high low))
(logior (ash high 16) low))
- #+cmu (kernel:single-float-bits float)
- #+sbcl (sb-kernel:single-float-bits float)
- #+lispworks (lispworks-float:single-float-bits float))
+ #+ccl (ccl::single-float-bits x)
+ #+cmu (kernel:single-float-bits x)
+ #+sbcl (sb-kernel:single-float-bits x)
+ #+lispworks (lispworks-float:single-float-bits x))
-#-(or abcl allegro cmu sbcl lispworks)
+#-(or abcl allegro ccl cmu sbcl lispworks)
(defun single-float-bits (x)
(declare (type single-float x))
(assert (= (float-radix x) 2))
((-1) (logior unsigned-result (- (expt 2 31)))))))))
-#+(or abcl allegro cmu sbcl lispworks)
+#+(or abcl allegro ccl cmu sbcl lispworks)
(defun double-float-bits (x)
(declare (type double-float x))
- #+abcl (values (system:double-float-low-bits float)
- (system:double-float-high-bits float))
+ #+abcl (values (system:double-float-low-bits x)
+ (system:double-float-high-bits x))
#+allegro (multiple-value-bind (us3 us2 us1 us0)
- (excl:double-float-to-shorts float)
+ (excl:double-float-to-shorts x)
(logior (ash us1 16) us0)
(logior (ash us3 16) us2))
- #+cmu (values (kernel:double-float-low-bits float)
- (kernel:double-float-high-bits float))
- #+sbcl (values (sb-kernel:double-float-low-bits float)
- (sb-kernel:double-float-high-bits float))
- #+lispworks (let ((bits (lispworks-float:double-float-bits float)))
+ #+ccl (multiple-value-bind (high low)
+ (ccl::double-float-bits x)
+ (values low high))
+ #+cmu (values (kernel:double-float-low-bits x)
+ (kernel:double-float-high-bits x))
+ #+sbcl (values (sb-kernel:double-float-low-bits x)
+ (sb-kernel:double-float-high-bits x))
+ #+lispworks (let ((bits (lispworks-float:double-float-bits x)))
(values (logand #xffffffff bits)
(ash bits -32))))
-#-(or abcl allegro cmu sbcl lispworks)
+#-(or abcl allegro ccl cmu sbcl lispworks)
(defun double-float-bits (x)
(declare (type double-float x))
(assert (= (float-radix x) 2))
(values (logand #xffffffff result) (ash result -32)))))))
-#+(or abcl allegro cmu sbcl lispworks)
+#+(or abcl allegro ccl cmu sbcl lispworks)
(defun make-single-float (bits)
(declare (type (signed-byte 32) bits))
#+abcl (system:make-single-float bits)
#+allegro (excl:shorts-to-single-float (ldb (byte 16 16) bits)
(ldb (byte 16 0) bits))
+ #+ccl (ccl::host-single-float-from-unsigned-byte-32 bits)
#+cmu (kernel:make-single-float bits)
#+sbcl (sb-kernel:make-single-float bits)
#+lispworks (lispworks-float:make-single-float bits))
-#-(or abcl allegro cmu sbcl lispworks)
+#-(or abcl allegro ccl cmu sbcl lispworks)
(defun make-single-float (bits)
(declare (type (signed-byte 32) bits))
(cond
(* sign (expt 2.0 exponent) mantissa)))))
-#+(or abcl allegro cmu sbcl lispworks)
-(defun make-double-float (low-bits high-bits)
- (declare (type (unsigned-byte 32) low-bits)
- (type (signed-byte 32) high-bits))
+#+(or abcl allegro ccl cmu sbcl lispworks)
+(defun make-double-float (low high)
+ (declare (type (unsigned-byte 32) low)
+ (type (signed-byte 32) high))
#+abcl (system:make-double-float (logior (ash high 32) low))
#+allegro (excl:shorts-to-double-float (ldb (byte 16 16) high)
(ldb (byte 16 0) high)
(ldb (byte 16 16) low)
(ldb (byte 16 0) low))
+ #+ccl (ccl::double-float-from-bits (logand high #xffffffff) low)
#+cmu (kernel:make-double-float high low)
#+sbcl (sb-kernel:make-double-float high low)
#+lispworks (lispworks-float:make-double-float high low))
-#-(or abcl allegro cmu sbcl lispworks)
-(defun make-double-float (low-bits high-bits)
- (declare (type (unsigned-byte 32) low-bits)
- (type (signed-byte 32) high-bits))
+#-(or abcl allegro ccl cmu sbcl lispworks)
+(defun make-double-float (low high)
+ (declare (type (unsigned-byte 32) low)
+ (type (signed-byte 32) high))
(cond
;; IEEE float special cases
- ((and (zerop high-bits) (zerop low-bits)) 0.0d0)
- ((and (= high-bits #x-80000000)
- (zerop low-bits)) -0.0d0)
+ ((and (zerop high) (zerop low)) 0.0d0)
+ ((and (= high #x-80000000)
+ (zerop low)) -0.0d0)
(t
- (let* ((bits (logior (ash high-bits 32) low-bits))
+ (let* ((bits (logior (ash high 32) low))
(sign (ecase (ldb (byte 1 63) bits)
(0 1.0d0)
(1 -1.0d0)))