/usr/share/common-lisp/source/mcclim/Apps/Scigraph/scigraph/copy.lisp is in cl-mcclim 0.9.6.dfsg.cvs20100315-2.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 | ;;; -*- Syntax: Common-lisp; Package: TOOL -*-
#|
Copyright (c) 1987-1993 by BBN Systems and Technologies,
A Division of Bolt, Beranek and Newman Inc.
All rights reserved.
Permission to use, copy, modify and distribute this software and its
documentation is hereby granted without fee, provided that the above
copyright notice of BBN Systems and Technologies, this paragraph and the
one following appear in all copies and in supporting documentation, and
that the name Bolt Beranek and Newman Inc. not be used in advertising or
publicity pertaining to distribution of the software without specific,
written prior permission. Any distribution of this software or derivative
works must comply with all applicable United States export control laws.
BBN makes no representation about the suitability of this software for any
purposes. It is provided "AS IS", without express or implied warranties
including (but not limited to) all implied warranties of merchantability
and fitness for a particular purpose, and notwithstanding any other
provision contained herein. In no event shall BBN be liable for any
special, indirect or consequential damages whatsoever resulting from loss
of use, data or profits, whether in an action of contract, negligence or
other tortuous action, arising out of or in connection with the use or
performance of this software, even if BBN Systems and Technologies is
advised of the possiblity of such damages.
|#
(in-package :tool)
(eval-when (compile load eval)
(export 'with-stack-list-copy 'tool)
(export '(with-slot-copying copy-slot copy-set-slot copy-slots) 'tool)
(export '(copyable-mixin copy-inner-class) 'tool)
(export '(copy-self copy-inner) 'tool)
(export '(copy-top-level copy) 'tool))
;;; COPY-TOP-LEVEL:
;;; Copy objects with aribtrarily complex substructure.
;;; Objects are kept track of in a HashTable, so only make one copy of each.
;;; Things which are EQ in the original (i.e. objects, sublists, etc.) come out
;;; EQ in the corresponding places in the copy.
(let ((copy-htable (make-hash-table)))
(defmethod copy-top-level (ORIGINAL-THING)
(clrhash COPY-HTABLE)
(copy ORIGINAL-THING COPY-HTABLE)))
(defgeneric copy (SELF COPY-HTABLE)
(:documentation "Returns a fullfledged copy of SELF, set-up and ready to go."))
;;;********************************************************************************
;;; Some simple cases.
;;; Copies these objects are always eq to the original and have no
;;; internal structure. --> So just use the objects use themselves.
;;; (I.e. no need to worry about caching them).
;;;**********************************************************************NLC21NOV90
(defmethod copy ((ORINGINAL-SYMBOL symbol) COPY-HTABLE)
(declare (ignore COPY-HTABLE))
ORINGINAL-SYMBOL)
(defmethod copy ((ORINGINAL-NUMBER number) COPY-HTABLE)
(declare (ignore COPY-HTABLE))
ORINGINAL-NUMBER)
;;;********************************************************************************
;;; The hairier, default case.
;;; In general,
;;; 1] Objects can have internal structure (and, for instance, circular
;;; refrences) and/or
;;; 2] Copies are not eql to the original.
;;;
;;; The basic idea here is to only make one copy of the ORIGINAL-THING and
;;; store it in the HashTable for future use. In this way, the Copied
;;; Object has the same "eq-connectedness" that the original had.
;;;**********************************************************************NLC21NOV90
(defgeneric copy-self (SELF)
(:documentation "Return a new, empty version of SELF"))
(defgeneric copy-inner (SELF COPY-OBJECT COPY-HTABLE)
(:documentation
"Copy the relevant portions of SELF into COPY-OBJECT.
OK if it calls COPY on sub-objects."))
(defgeneric copy-final (SELF)
(:documentation "Last pass to make sure everything is in place."))
;;;NLC21NOV90 - The call to COPY-INNER has to be inside this guy, else it
;;; will loose if ORIGINAL-THING contains a pointer to itself.
;;;
;;; So, in short there are three steps (if I've not already been Copied):
;;; 1] Create a new, empty copy (using COPY-SELF).
;;; 2] Shove it in the HashTable.
;;; 3] Setup its internal structure, as needed (using COPY-INNER).
(defmethod copy (ORIGINAL-THING COPY-HTABLE)
(multiple-value-bind (VALUE FOUND?) (gethash ORIGINAL-THING COPY-HTABLE)
(or (and FOUND? VALUE)
(let ((COPY-THING (copy-self ORIGINAL-THING)))
(setf (gethash ORIGINAL-THING COPY-HTABLE) COPY-THING)
(copy-inner ORIGINAL-THING COPY-THING COPY-HTABLE)
(copy-final ORIGINAL-THING)
COPY-THING))))
(defmethod copy-self (SELF)
(error "Don't know how to copy ~A" self))
(defmethod copy-self ((ORIGINAL string))
(subseq ORIGINAL 0 (length ORIGINAL)))
(defmethod copy-self ((original array))
(subseq original 0 (length original)))
(defmethod copy-inner (SELF COPY-OBJECT COPY-HTABLE)
"Default is to do nothing."
(declare (ignore SELF COPY-OBJECT COPY-HTABLE))
nil)
(defmethod copy-final ((self t))
"Default is to do nothing."
nil)
;;;********************************************************************************
;;; Lists
;;;**********************************************************************NLC14DEC90
;;; The Old, Boring, Common-Lisp compatible Way.
#-lispm
(defmethod copy-self ((ORIGINAL-LIST list))
(and ORIGINAL-LIST (cons nil nil)))
(defmethod copy-inner ((ORIGINAL-LIST list) COPY-LIST COPY-HTABLE)
;; This handles circular lists, but is slower and isn't cdr coded.
(unless (null ORIGINAL-LIST)
(setf (car COPY-LIST) (copy (car ORIGINAL-LIST) COPY-HTABLE))
(setf (cdr COPY-LIST) (copy (cdr ORIGINAL-LIST) COPY-HTABLE))))
;;;NLC15DEC90 - New, improved copy on lists.
;;; This isn't as "elegant" as the above, but it preserves Cdr-coding.
#+lispm
(defmethod copy ((ORIGINAL-LIST list) COPY-HTABLE)
(and ORIGINAL-LIST
(multiple-value-bind (VALUE FOUND?) (gethash ORIGINAL-LIST COPY-HTABLE)
(if FOUND?
VALUE
(let (COPY-LIST)
(multiple-value-bind (NUM-CDR-NEXT LAST-CONTIG-PART)
(si:contiguous-list-info ORIGINAL-LIST)
(if (eq LAST-CONTIG-PART ORIGINAL-LIST)
;;; THIS CONS (AT LEAST) ISN'T CDR-CODED.
;;; SO MAKE A COPY OF THIS CONS, AND CACHE IT
;;; THEN COPY BOTH SIDES OF THE ITS SUB-TREE.
(setf COPY-LIST (cons nil nil)
(gethash ORIGINAL-LIST COPY-HTABLE) COPY-LIST
(car COPY-LIST) (copy (car ORIGINAL-LIST) COPY-HTABLE)
(cdr COPY-LIST) (copy (cdr ORIGINAL-LIST) COPY-HTABLE))
;;; ELSE, THE LIST STARTS WITH (AT LEAST SOME) CDR-CODING.
;;; SO GET A CDR-CODED COPY OF THE SAME LENGTH
;;; AND CDR DOWN IT, COPYING EACH ELEMENT.
;;; NOTE THAT WE NEED TO CACHE EACH CONS.
(prog ((COPY-PNTR (setq COPY-LIST (make-list (1+ NUM-CDR-NEXT)))))
LOOP-TAG
(setf (gethash ORIGINAL-LIST COPY-HTABLE) COPY-PNTR
(car COPY-PNTR) (copy (car ORIGINAL-LIST) COPY-HTABLE))
(unless (eq LAST-CONTIG-PART ORIGINAL-LIST)
(setq COPY-PNTR (cdr COPY-PNTR)
ORIGINAL-LIST (cdr ORIGINAL-LIST))
(go LOOP-TAG))
;;; FINALLY, MAKE SURE THE LAST CDR IS HANDLED RIGHT.
(and (cdr ORIGINAL-LIST)
(setf (cdr COPY-PNTR)
(copy (cdr ORIGINAL-LIST) COPY-HTABLE))))))
COPY-LIST))))
)
;;;********************************************************************************
;;; Copy-able Class objects.
;;;**********************************************************************NLC21NOV90
(defclass copyable-mixin
()
()
(:documentation
"Provides method for doing COPY that creates a copy on an object.
Each mixin should provide an COPY-INNER-CLASS method to copy its
slots appropriately."))
(defmethod copy-self ((SELF copyable-mixin))
(make-instance (class-of SELF)))
(defgeneric copy-inner-class (SELF COPY-OBJECT COPY-HTABLE)
(:method-combination progn)
(:documentation
"Defined for each component class of an object with mixin COPYABLE-MIXIN.
It should setup its slots as appropriate.
This needs to be a seperate method (from COPY-INNER) because it has
to be done with a PROGN Method-Combination."))
(defmethod copy-inner-class progn ((ORIGINAL-OBJECT copyable-mixin) COPY-LIST COPY-HTABLE)
(declare (ignore COPY-LIST COPY-HTABLE))
nil)
(defmethod copy-inner ((ORIGINAL-OBJECT copyable-mixin) COPY-LIST COPY-HTABLE)
(copy-inner-class ORIGINAL-OBJECT COPY-LIST COPY-HTABLE))
(defgeneric copy-final-class (SELF)
(:method-combination progn)
(:documentation
"Defined for each component class of an object with mixin COPYABLE-MIXIN.
It should setup its slots as appropriate.
This needs to be a seperate method (from COPY-FINAL) because it has
to be done with a PROGN Method-Combination."))
(defmethod copy-final-class progn ((ORIGINAL-OBJECT copyable-mixin))
nil)
(defmethod copy-final ((ORIGINAL-OBJECT copyable-mixin))
(copy-final-class ORIGINAL-OBJECT))
;;;********************************************************************************
;;; Things to make using COPY-INNER-CLASS easier.
;;;**********************************************************************NLC06DEC90
;;; KRA: these 2 macros should be macrolet inside with-slot-copying.
(defmacro copy-set-slot-1 (COPY-OBJECT SLOT-NAME VALUE)
`(setf (slot-value ,COPY-OBJECT ,SLOT-NAME)
,VALUE))
(defmacro copy-slot-1 (COPY-OBJECT SLOT-NAME ORIGINAL-OBJECT COPY-HTABLE)
`(copy-set-slot-1 ,COPY-OBJECT ,SLOT-NAME (copy (slot-value ,ORIGINAL-OBJECT ,SLOT-NAME)
,COPY-HTABLE)))
;;; (copy-set-slot (SLOT-NAME VALUE)
;;; Set the contents of SLOT-NAME in COPY-OBJECT to VALUE.
;;; (copy-slot (SLOT-NAME) ...
;;; Set the contents of SLOT-NAME in COPY-OBJECT to be a copyicate of the
;;; contents of the same slot in ORIGINAL-OBJECT.
(defmacro with-slot-copying
((COPY-OBJECT COPY-HTABLE &optional (ORIGINAL-OBJECT 'SELF)) &body BODY)
`(macrolet ((copy-slot (SLOT-NAME)
`(copy-slot-1 ,',COPY-OBJECT ',SLOT-NAME ,',ORIGINAL-OBJECT ,',COPY-HTABLE))
(copy-set-slot (SLOT-NAME VALUE)
`(copy-set-slot-1 ,',COPY-OBJECT ',SLOT-NAME ,VALUE)))
(macrolet ((copy-slots (&rest SLOT-NAMES)
`(progn
,@(loop for SLOT-NAME in SLOT-NAMES
collecting `(copy-slot ,SLOT-NAME)))))
,@BODY)))
;;;
;;;
;;;
(defmacro WITH-STACK-LIST-COPY ((variable list) &body body)
"Like `((let ((,variable (copy-list ,list))) ,@body)
except that the copy is consed on the stack."
#+Genera
`(let ((.n. (length ,list))
(.l. ,list))
(flet ((.body. (&rest ,variable)
,@body))
(sys:%start-function-call #'.body. return .n. nil)
(do () ((null .l.)) (sys:%push (pop .l.)))
(sys:%finish-function-call #'.body. return .n. nil)))
#-Genera
`(let ((,variable (copy-list ,list))) ,@body))
|