X-Git-Url: http://repo.macrolet.net/gitweb/?a=blobdiff_plain;f=src%2Fcode%2Fpred.lisp;h=f2e2e6b91844ad68c0cfce547d7e9a4e4de1ca04;hb=7f1e94ae961a198e00daf281eb1dc858e5b2dcc7;hp=dd6ccb2dd196a2641784873307fbfecb44ed7a3b;hpb=22b819c0cd0ca0ea5be52ba280b9e9e0b8e86210;p=sbcl.git diff --git a/src/code/pred.lisp b/src/code/pred.lisp index dd6ccb2..f2e2e6b 100644 --- a/src/code/pred.lisp +++ b/src/code/pred.lisp @@ -17,11 +17,50 @@ (defun streamp (stream) (typep stream 'stream)) -;;; Is X a (VECTOR T)? -(defun vector-t-p (x) - (or (simple-vector-p x) - (and (complex-vector-p x) - (simple-vector-p (%array-data-vector x))))) +;;; various (VECTOR FOO) type predicates, not implemented as simple +;;; widetag tests +(macrolet + ((def () + `(progn + ,@(loop for (name spec) in *vector-without-complex-typecode-infos* + collect `(defun ,name (x) + (or (typep x '(simple-array ,spec (*))) + (and (complex-vector-p x) + (do ((data (%array-data-vector x) (%array-data-vector data))) + ((not (array-header-p data)) (typep data '(simple-array ,spec (*)))))))))))) + (def)) + +;;; Is X an extended sequence? +(defun extended-sequence-p (x) + (and (not (listp x)) + (not (vectorp x)) + (let* ((slayout #.(info :type :compiler-layout 'sequence)) + (depthoid #.(layout-depthoid (info :type :compiler-layout 'sequence))) + (layout (layout-of x))) + (when (layout-invalid layout) + (setq layout (update-object-layout-or-invalid x slayout))) + (if (eq layout slayout) + t + (let ((inherits (layout-inherits layout))) + (declare (optimize (safety 0))) + (and (> (length inherits) depthoid) + (eq (svref inherits depthoid) slayout))))))) + +;;; Is X a SEQUENCE? Harder than just (OR VECTOR LIST) +(defun sequencep (x) + (or (listp x) + (vectorp x) + (let* ((slayout #.(info :type :compiler-layout 'sequence)) + (depthoid #.(layout-depthoid (info :type :compiler-layout 'sequence))) + (layout (layout-of x))) + (when (layout-invalid layout) + (setq layout (update-object-layout-or-invalid x slayout))) + (if (eq layout slayout) + t + (let ((inherits (layout-inherits layout))) + (declare (optimize (safety 0))) + (and (> (length inherits) depthoid) + (eq (svref inherits depthoid) slayout))))))) ;;;; primitive predicates. These must be supported directly by the ;;;; compiler. @@ -33,20 +72,25 @@ ;;; All the primitive type predicate wrappers share a parallel form.. (macrolet ((def-type-predicate-wrapper (pred) - (let* ((name (symbol-name pred)) - (stem (string-left-trim "%" (string-right-trim "P-" name))) - (article (if (position (schar name 0) "AEIOU") "an" "a"))) - `(defun ,pred (object) - ,(format nil - "Return true if OBJECT is ~A ~A, and NIL otherwise." - article - stem) - ;; (falling through to low-level implementation) - (,pred object))))) + (let* ((name (symbol-name pred)) + (stem (string-left-trim "%" (string-right-trim "P-" name))) + (article (if (position (schar name 0) "AEIOU") "an" "a"))) + `(defun ,pred (object) + ,(format nil + "Return true if OBJECT is ~A ~A, and NIL otherwise." + article + stem) + ;; (falling through to low-level implementation) + (,pred object))))) (def-type-predicate-wrapper array-header-p) (def-type-predicate-wrapper arrayp) (def-type-predicate-wrapper atom) - (def-type-predicate-wrapper base-char-p) + ;; Testing for BASE-CHAR-P is usually redundant on #-sb-unicode, + ;; remove it there completely so that #-sb-unicode build will + ;; break when it's used. + #!+sb-unicode (def-type-predicate-wrapper base-char-p) + (def-type-predicate-wrapper base-string-p) + #!+sb-unicode (def-type-predicate-wrapper character-string-p) (def-type-predicate-wrapper bignump) (def-type-predicate-wrapper bit-vector-p) (def-type-predicate-wrapper characterp) @@ -63,6 +107,7 @@ ;; the type it tests for in the Common Lisp type system, and since it's ;; only used in the implementation of a few specialized things.) (def-type-predicate-wrapper double-float-p) + (def-type-predicate-wrapper extended-char-p) (def-type-predicate-wrapper fdefn-p) (def-type-predicate-wrapper fixnump) (def-type-predicate-wrapper floatp) @@ -77,34 +122,42 @@ (def-type-predicate-wrapper ratiop) (def-type-predicate-wrapper realp) (def-type-predicate-wrapper short-float-p) - (def-type-predicate-wrapper sb!kernel:simple-array-p) - (def-type-predicate-wrapper simple-bit-vector-p) - (def-type-predicate-wrapper simple-string-p) - (def-type-predicate-wrapper simple-vector-p) (def-type-predicate-wrapper single-float-p) - (def-type-predicate-wrapper stringp) + #!+sb-simd-pack (def-type-predicate-wrapper simd-pack-p) (def-type-predicate-wrapper %instancep) (def-type-predicate-wrapper symbolp) + (def-type-predicate-wrapper %other-pointer-p) (def-type-predicate-wrapper system-area-pointer-p) (def-type-predicate-wrapper weak-pointer-p) + #!+#.(cl:if (cl:= 32 sb!vm:n-word-bits) '(and) '(or)) + (progn + (def-type-predicate-wrapper unsigned-byte-32-p) + (def-type-predicate-wrapper signed-byte-32-p)) + #!+#.(cl:if (cl:= 64 sb!vm:n-word-bits) '(and) '(or)) + (progn + (def-type-predicate-wrapper unsigned-byte-64-p) + (def-type-predicate-wrapper signed-byte-64-p)) + ;; Specialized array types + (macrolet ((saetp-defs () + `(progn + ,@(map 'list + (lambda (saetp) + `(def-type-predicate-wrapper + ,(symbolicate (sb!vm:saetp-primitive-type-name saetp) "-P"))) + sb!vm:*specialized-array-element-type-properties*)))) + (saetp-defs)) + ;; Other array types + (def-type-predicate-wrapper simple-array-p) + (def-type-predicate-wrapper simple-string-p) + (def-type-predicate-wrapper stringp) (def-type-predicate-wrapper vectorp) - (def-type-predicate-wrapper unsigned-byte-32-p) - (def-type-predicate-wrapper signed-byte-32-p) - (def-type-predicate-wrapper simple-array-unsigned-byte-2-p) - (def-type-predicate-wrapper simple-array-unsigned-byte-4-p) - (def-type-predicate-wrapper simple-array-unsigned-byte-8-p) - (def-type-predicate-wrapper simple-array-unsigned-byte-16-p) - (def-type-predicate-wrapper simple-array-unsigned-byte-32-p) - (def-type-predicate-wrapper simple-array-signed-byte-8-p) - (def-type-predicate-wrapper simple-array-signed-byte-16-p) - (def-type-predicate-wrapper simple-array-signed-byte-30-p) - (def-type-predicate-wrapper simple-array-signed-byte-32-p) - (def-type-predicate-wrapper simple-array-single-float-p) - (def-type-predicate-wrapper simple-array-double-float-p) - #!+long-float (def-type-predicate-wrapper simple-array-long-float-p) - (def-type-predicate-wrapper simple-array-complex-single-float-p) - (def-type-predicate-wrapper simple-array-complex-double-float-p) - #!+long-float (def-type-predicate-wrapper simple-array-complex-long-float-p)) + (def-type-predicate-wrapper vector-nil-p)) + +#!+(or x86 x86-64) +(defun fixnum-mod-p (x limit) + (and (fixnump x) + (<= 0 x limit))) + ;;; Return the specifier for the type of object. This is not simply ;;; (TYPE-SPECIFIER (CTYPE-OF OBJECT)) because CTYPE-OF has different @@ -113,19 +166,38 @@ (defun type-of (object) #!+sb-doc "Return the type of OBJECT." - (if (typep object '(or function array complex)) - (type-specifier (ctype-of object)) - (let* ((classoid (layout-classoid (layout-of object))) - (name (classoid-name classoid))) - (if (typep object 'instance) - (case name - (sb!alien-internals:alien-value - `(sb!alien:alien - ,(sb!alien-internals:unparse-alien-type - (sb!alien-internals:alien-value-type object)))) - (t - (classoid-proper-name classoid))) - name)))) + (typecase object + (fixnum + (cond + ((<= 0 object 1) 'bit) + ((< object 0) 'fixnum) + (t '(integer 0 #.sb!xc:most-positive-fixnum)))) + (integer + (if (>= object 0) + '(integer #.(1+ sb!xc:most-positive-fixnum)) + 'bignum)) + (standard-char 'standard-char) + (base-char 'base-char) + (extended-char 'extended-char) + ((member t) 'boolean) + (keyword 'keyword) + ((or array complex #!+sb-simd-pack sb!kernel:simd-pack) + (type-specifier (ctype-of object))) + (t + (let* ((classoid (layout-classoid (layout-of object))) + (name (classoid-name classoid))) + (if (%instancep object) + (case name + (sb!alien-internals:alien-value + `(sb!alien:alien + ,(sb!alien-internals:unparse-alien-type + (sb!alien-internals:alien-value-type object)))) + (t + (let ((pname (classoid-proper-name classoid))) + (if (classoid-p pname) + (classoid-pcl-class pname) + pname)))) + name))))) ;;;; equality predicates @@ -135,54 +207,101 @@ "Return T if OBJ1 and OBJ2 are the same object, otherwise NIL." (eq obj1 obj2)) +(declaim (inline %eql)) +(defun %eql (obj1 obj2) + #!+sb-doc + "Return T if OBJ1 and OBJ2 represent the same object, otherwise NIL." + (or (eq obj1 obj2) + (if (or (typep obj2 'fixnum) + (not (typep obj2 'number))) + nil + (macrolet ((foo (&rest stuff) + `(typecase obj2 + ,@(mapcar (lambda (foo) + (let ((type (car foo)) + (fn (cadr foo))) + `(,type + (and (typep obj1 ',type) + (,fn obj1 obj2))))) + stuff)))) + (foo + (single-float eql) + (double-float eql) + #!+long-float + (long-float eql) + (bignum + (lambda (x y) + (zerop (bignum-compare x y)))) + (ratio + (lambda (x y) + (and (eql (numerator x) (numerator y)) + (eql (denominator x) (denominator y))))) + (complex + (lambda (x y) + (and (eql (realpart x) (realpart y)) + (eql (imagpart x) (imagpart y)))))))))) + +(defun eql (x y) + (%eql x y)) + (defun bit-vector-= (x y) (declare (type bit-vector x y)) - (if (and (simple-bit-vector-p x) - (simple-bit-vector-p y)) - (bit-vector-= x y) ; DEFTRANSFORM - (and (= (length x) (length y)) - (do ((i 0 (1+ i)) - (length (length x))) - ((= i length) t) - (declare (fixnum i)) - (unless (= (bit x i) (bit y i)) - (return nil)))))) + (cond ((eq x y)) + ((and (simple-bit-vector-p x) + (simple-bit-vector-p y)) + (bit-vector-= x y)) ; DEFTRANSFORM + (t + (and (= (length x) (length y)) + (do ((i 0 (1+ i)) + (length (length x))) + ((= i length) t) + (declare (fixnum i)) + (unless (= (bit x i) (bit y i)) + (return nil))))))) (defun equal (x y) #!+sb-doc - "Return T if X and Y are EQL or if they are structured components - whose elements are EQUAL. Strings and bit-vectors are EQUAL if they - are the same length and have identical components. Other arrays must be - EQ to be EQUAL." - (cond ((eql x y) t) - ((consp x) - (and (consp y) - (equal (car x) (car y)) - (equal (cdr x) (cdr y)))) - ((stringp x) - (and (stringp y) (string= x y))) - ((pathnamep x) - (and (pathnamep y) (pathname= x y))) - ((bit-vector-p x) - (and (bit-vector-p y) - (bit-vector-= x y))) - (t nil))) + "Return T if X and Y are EQL or if they are structured components whose +elements are EQUAL. Strings and bit-vectors are EQUAL if they are the same +length and have identical components. Other arrays must be EQ to be EQUAL." + ;; Non-tail self-recursion implemented with a local auxiliary function + ;; is a lot faster than doing it the straightforward way (at least + ;; on x86oids) due to calling convention differences. -- JES, 2005-12-30 + (labels ((equal-aux (x y) + (cond ((%eql x y) + t) + ((consp x) + (and (consp y) + (equal-aux (car x) (car y)) + (equal-aux (cdr x) (cdr y)))) + ((stringp x) + (and (stringp y) (string= x y))) + ((pathnamep x) + (and (pathnamep y) (pathname= x y))) + ((bit-vector-p x) + (and (bit-vector-p y) + (bit-vector-= x y))) + (t nil)))) + ;; Use MAYBE-INLINE to get the inline expansion only once (instead + ;; of 200 times with INLINE). -- JES, 2005-12-30 + (declare (maybe-inline equal-aux)) + (equal-aux x y))) ;;; EQUALP comparison of HASH-TABLE values (defun hash-table-equalp (x y) (declare (type hash-table x y)) (or (eq x y) (and (hash-table-p y) - (eql (hash-table-count x) (hash-table-count y)) - (eql (hash-table-test x) (hash-table-test y)) - (block comparison-of-entries - (maphash (lambda (key x-value) - (multiple-value-bind (y-value y-value-p) - (gethash key y) - (unless (and y-value-p (equalp x-value y-value)) - (return-from comparison-of-entries nil)))) - x) - t)))) + (eql (hash-table-count x) (hash-table-count y)) + (eql (hash-table-test x) (hash-table-test y)) + (block comparison-of-entries + (maphash (lambda (key x-value) + (multiple-value-bind (y-value y-value-p) + (gethash key y) + (unless (and y-value-p (equalp x-value y-value)) + (return-from comparison-of-entries nil)))) + x) + t)))) (defun equalp (x y) #+nil ; KLUDGE: If doc string, should be accurate: Talk about structures @@ -193,73 +312,77 @@ arrays must have identical dimensions and EQUALP elements, but may differ in their type restriction." (cond ((eq x y) t) - ((characterp x) (and (characterp y) (char-equal x y))) - ((numberp x) (and (numberp y) (= x y))) - ((consp x) - (and (consp y) - (equalp (car x) (car y)) - (equalp (cdr x) (cdr y)))) - ((pathnamep x) - (and (pathnamep y) (pathname= x y))) - ((hash-table-p x) - (and (hash-table-p y) - (hash-table-equalp x y))) - ((typep x 'instance) - (let* ((layout-x (%instance-layout x)) - (len (layout-length layout-x))) - (and (typep y 'instance) - (eq layout-x (%instance-layout y)) - (structure-classoid-p (layout-classoid layout-x)) - (do ((i 1 (1+ i))) - ((= i len) t) - (declare (fixnum i)) - (let ((x-el (%instance-ref x i)) - (y-el (%instance-ref y i))) - (unless (or (eq x-el y-el) - (equalp x-el y-el)) - (return nil))))))) - ((vectorp x) - (let ((length (length x))) - (and (vectorp y) - (= length (length y)) - (dotimes (i length t) - (let ((x-el (aref x i)) - (y-el (aref y i))) - (unless (or (eq x-el y-el) - (equalp x-el y-el)) - (return nil))))))) - ((arrayp x) - (and (arrayp y) - (= (array-rank x) (array-rank y)) - (dotimes (axis (array-rank x) t) - (unless (= (array-dimension x axis) - (array-dimension y axis)) - (return nil))) - (dotimes (index (array-total-size x) t) - (let ((x-el (row-major-aref x index)) - (y-el (row-major-aref y index))) - (unless (or (eq x-el y-el) - (equalp x-el y-el)) - (return nil)))))) - (t nil))) + ((characterp x) (and (characterp y) (char-equal x y))) + ((numberp x) (and (numberp y) (= x y))) + ((consp x) + (and (consp y) + (equalp (car x) (car y)) + (equalp (cdr x) (cdr y)))) + ((pathnamep x) + (and (pathnamep y) (pathname= x y))) + ((hash-table-p x) + (and (hash-table-p y) + (hash-table-equalp x y))) + ((%instancep x) + (let* ((layout-x (%instance-layout x)) + (raw-len (layout-n-untagged-slots layout-x)) + (total-len (layout-length layout-x)) + (normal-len (- total-len raw-len))) + (and (%instancep y) + (eq layout-x (%instance-layout y)) + (structure-classoid-p (layout-classoid layout-x)) + (dotimes (i normal-len t) + (let ((x-el (%instance-ref x i)) + (y-el (%instance-ref y i))) + (unless (or (eq x-el y-el) + (equalp x-el y-el)) + (return nil)))) + (if (zerop raw-len) + t + (raw-instance-slots-equalp layout-x x y))))) + ((vectorp x) + (let ((length (length x))) + (and (vectorp y) + (= length (length y)) + (dotimes (i length t) + (let ((x-el (aref x i)) + (y-el (aref y i))) + (unless (or (eq x-el y-el) + (equalp x-el y-el)) + (return nil))))))) + ((arrayp x) + (and (arrayp y) + (= (array-rank x) (array-rank y)) + (dotimes (axis (array-rank x) t) + (unless (= (array-dimension x axis) + (array-dimension y axis)) + (return nil))) + (dotimes (index (array-total-size x) t) + (let ((x-el (row-major-aref x index)) + (y-el (row-major-aref y index))) + (unless (or (eq x-el y-el) + (equalp x-el y-el)) + (return nil)))))) + (t nil))) (/show0 "about to do test cases in pred.lisp") #!+sb-test (let ((test-cases `((0.0 ,(load-time-value (make-unportable-float :single-float-negative-zero)) t) - (0.0 1.0 nil) - (#c(1 0) #c(1.0 0) t) - (#c(1.1 0) #c(11/10 0) nil) ; due to roundoff error - ("Hello" "hello" t) - ("Hello" #(#\h #\E #\l #\l #\o) t) - ("Hello" "goodbye" nil)))) + (0.0 1.0 nil) + (#c(1 0) #c(1.0 0.0) t) + (#c(0 1) #c(0.0 1.0) t) + (#c(1.1 0.0) #c(11/10 0) nil) ; due to roundoff error + ("Hello" "hello" t) + ("Hello" #(#\h #\E #\l #\l #\o) t) + ("Hello" "goodbye" nil)))) (/show0 "TEST-CASES bound in pred.lisp") (dolist (test-case test-cases) (/show0 "about to do a TEST-CASE in pred.lisp") (destructuring-bind (x y expected-result) test-case (let* ((result (equalp x y)) - (bresult (if result 1 0)) - (expected-bresult (if expected-result 1 0))) - (unless (= bresult expected-bresult) - (/show0 "failing test in pred.lisp") - (error "failed test (EQUALP ~S ~S)" x y)))))) + (bresult (if result 1 0)) + (expected-bresult (if expected-result 1 0))) + (unless (= bresult expected-bresult) + (/show0 "failing test in pred.lisp") + (error "failed test (EQUALP ~S ~S)" x y)))))) (/show0 "done with test cases in pred.lisp")