Make EQUAL faster (about 50% improvement for short lists on x86-64).
As amazing as it might seem, there are actually real-world
applications where significant time is spent in EQUAL.
* Inline EQL in EQUAL
* Rearrange things a bit to enable the inlining
* Rewrite EQUAL to use a local helper function
;;;; -*- coding: utf-8; -*-
+changes in sbcl-0.9.9 relative to sbcl-0.9.8:
+ * optimization: faster implementation of EQUAL
+
changes in sbcl-0.9.8 relative to sbcl-0.9.7:
* minor incompatible change: (SETF CLASS-NAME) and (SETF
GENERIC-FUNCTION-NAME) are generic functions once more (reverting
"%CHECK-BOUND" "%CHECK-VECTOR-SEQUENCE-BOUNDS"
"%CLOSURE-FUN" "%CLOSURE-INDEX-REF" "%COS" "%COS-QUICK"
"%COSH" "%DATA-VECTOR-AND-INDEX" "%DEPOSIT-FIELD"
- "%DOUBLE-FLOAT" "%DPB" "%EXP" "%EXPM1" "%FIND-POSITION"
+ "%DOUBLE-FLOAT" "%DPB" "%EQL" "%EXP" "%EXPM1" "%FIND-POSITION"
"%FIND-POSITION-VECTOR-MACRO" "%FIND-POSITION-IF"
"%FIND-POSITION-IF-VECTOR-MACRO" "%FIND-POSITION-IF-NOT"
"%FIND-POSITION-IF-NOT-VECTOR-MACRO" "%FUN-DOC"
((complex (or float rational))
(and (= (realpart x) y)
(zerop (imagpart x))))))
-
-(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))))))))))
\f
;;;; logicals
"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)
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)))
+ (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))))
+ (declare (maybe-inline equal-aux))
+ (equal-aux x y)))
;;; EQUALP comparison of HASH-TABLE values
(defun hash-table-equalp (x y)
;;; checkins which aren't released. (And occasionally for internal
;;; versions, especially for internal versions off the main CVS
;;; branch, it gets hairier, e.g. "0.pre7.14.flaky4.13".)
-"0.9.8.2"
+"0.9.8.3"