1 ;;;; -*- Mode: Lisp; Syntax: ANSI-Common-Lisp; Base: 10 -*-
2 ;;;; *************************************************************************
3 ;;;; FILE IDENTIFICATION
6 ;;;; Purpose: Generalized equal function for KMRCL package
7 ;;;; Programmer: Kevin M. Rosenberg
8 ;;;; Date Started: Apr 2000
12 ;;;; This file, part of KMRCL, is Copyright (c) 2002 by Kevin M. Rosenberg
14 ;;;; KMRCL users are granted the rights to distribute and use this software
15 ;;;; as governed by the terms of the Lisp Lesser GNU Public License
16 ;;;; (http://opensource.franz.com/preamble.html), also known as the LLGPL.
17 ;;;; *************************************************************************
23 (defun generalized-equal (obj1 obj2)
24 (if (not (equal (type-of obj1) (type-of obj2)))
32 (let ((diff (abs (/ (- obj1 obj2) obj1))))
33 (if (> diff (* 10 double-float-epsilon))
37 (and (generalized-equal (realpart obj1) (realpart obj2))
38 (generalized-equal (imagpart obj1) (imagpart obj2))))
40 (generalized-equal-fielded-object obj1 obj2))
42 (generalized-equal-fielded-object obj1 obj2))
44 (generalized-equal-hash-table obj1 obj2)
47 (generalized-equal-function obj1 obj2))
51 (generalized-equal-array obj1 obj2))
56 (defun generalized-equal-function (obj1 obj2)
57 (string= (function-to-string obj1) (function-to-string obj2)))
59 (defun generalized-equal-array (obj1 obj2)
61 (when (not (= (array-total-size obj1) (array-total-size obj2)))
62 (return-from test nil))
63 (dotimes (i (array-total-size obj1))
64 (unless (generalized-equal (aref obj1 i) (aref obj2 i))
65 (return-from test nil)))
66 (return-from test t)))
68 (defun generalized-equal-hash-table (obj1 obj2)
70 (when (not (= (hash-table-count obj1) (hash-table-count obj2)))
71 (return-from test nil))
74 (multiple-value-bind (value found) (gethash k obj2)
75 (unless (and found (generalized-equal v value))
76 (return-from test nil))))
78 (return-from test t)))
80 (defun generalized-equal-fielded-object (obj1 obj2)
82 (when (not (equal (class-of obj1) (class-of obj2)))
83 (return-from test nil))
84 (dolist (field (class-slot-names (class-name (class-of obj1))))
85 (unless (generalized-equal (slot-value obj1 field) (slot-value obj2 field))
86 (return-from test nil)))
87 (return-from test t)))
89 (defun class-slot-names (c-name)
90 "Given a CLASS-NAME, returns a list of the slots in the class."
91 #+(or allegro cmu lispworks sbcl scl)
92 (mapcar #'kmr-mop:slot-definition-name
93 (kmr-mop:class-slots (kmr-mop:find-class c-name)))
94 #+(and mcl (not openmcl))
95 (let* ((class (find-class c-name nil)))
96 (when (typep class 'standard-class)
97 (nconc (mapcar #'car (ccl:class-instance-slots class))
98 (mapcar #'car (ccl:class-class-slots class)))))
99 #-(or allegro lispworks cmu sbcl scl (and mcl (not openmcl)))
100 (declare (ignore c-name))
101 #-(or allegro lispworks cmu sbcl scl (and mcl (not openmcl)))
102 (error "class-slot-names is not defined on this platform")
105 (defun structure-slot-names (s-name)
106 "Given a STRUCTURE-NAME, returns a list of the slots in the structure."
107 #+allegro (class-slot-names s-name)
108 #+lispworks (structure:structure-class-slot-names
110 #+(or sbcl cmu) (mapcar #'kmr-mop:slot-definition-name
111 (kmr-mop:class-slots (kmr-mop:find-class s-name)))
112 #+scl (mapcar #'kernel:dsd-name
115 (kernel:class-layout (find-class s-name)))))
116 #+(and mcl (not openmcl))
117 (let* ((sd (gethash s-name ccl::%defstructs%))
118 (slots (if sd (ccl::sd-slots sd))))
119 (mapcar #'car (if (symbolp (caar slots)) slots (cdr slots))))
120 #-(or allegro lispworks cmu sbcl scl (and mcl (not openmcl)))
121 (declare (ignore s-name))
122 #-(or allegro lispworks cmu sbcl scl (and mcl (not openmcl)))
123 (error "structure-slot-names is not defined on this platform")
126 (defun function-to-string (obj)
127 "Returns the lambda code for a function. Relies on
128 Allegro implementation-dependent features."
129 (multiple-value-bind (lambda closurep name) (function-lambda-expression obj)
130 (declare (ignore closurep))
132 (format nil "#'~s" lambda)
134 (format nil "#'~s" name)