Handle run-program with :directory nil.
[sbcl.git] / src / code / pred.lisp
index 1ce49e1..f2e2e6b 100644 (file)
 (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)))))))
 \f
 ;;;; primitive predicates. These must be supported directly by the
 ;;;; compiler.
 
 ;;; 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)
   ;; 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)
   (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)))
+
 \f
 ;;; Return the specifier for the type of object. This is not simply
 ;;; (TYPE-SPECIFIER (CTYPE-OF OBJECT)) because CTYPE-OF has different
 (defun type-of (object)
   #!+sb-doc
   "Return the type of OBJECT."
-  (if (typep object '(or function array complex))
-    (type-specifier (ctype-of object))
-    (let* ((class (layout-class (layout-of object)))
-          (name (class-name class)))
-      (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
-        (class-proper-name class)))
-      name))))
-\f
-;;; FIXME: This belongs somewhere else, perhaps in code/array.lisp.
-(defun upgraded-array-element-type (spec)
-  #!+sb-doc
-  "Return the element type that will actually be used to implement an array
-   with the specifier :ELEMENT-TYPE Spec."
-  (if (unknown-type-p (specifier-type spec))
-      (error "undefined type: ~S" spec)
-      (type-specifier (array-type-specialized-element-type
-                      (specifier-type `(array ,spec))))))
+  (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)))))
 \f
 ;;;; equality predicates
 
   "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))
+  (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
-  "Returns 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)
-             (= (the fixnum (length x))
-                (the fixnum (length y)))
-             (do ((i 0 (1+ i))
-                  (length (length x)))
-                 ((= i length) t)
-               (declare (fixnum i))
-               (or (= (the fixnum (bit x i))
-                      (the fixnum (bit y i)))
-                   (return nil)))))
-       (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
   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-class-p (layout-class 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 -0.0 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))))
+(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.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")