root/trunk/thirdparty/cl-store_0.8.4/default-backend.lisp

Revision 2554, 29.0 kB (checked in by ksprotte, 11 months ago)

added cl-store

  • Property svn:executable set to *
Line 
1 7;;; -*- Mode: LISP; Syntax: ANSI-Common-Lisp; Base: 10 -*-
2 ;; See the file LICENCE for licence information.
3
4 ;; The cl-store backend.
5 (in-package :cl-store)
6
7 (defbackend cl-store :magic-number 1395477571
8             :stream-type '(unsigned-byte 8)
9             :old-magic-numbers (1912923 1886611788 1347635532 1886611820 1414745155
10                                 1349740876 1884506444 1347643724 1349732684 1953713219
11                                 1416850499)
12             :extends (resolving-backend)
13             :fields ((restorers :accessor restorers
14                                 :initform (make-hash-table :size 100))))
15
16 (defun register-code (code name &optional (errorp nil))
17   (aif (and (gethash code (restorers (find-backend 'cl-store))) errorp)
18        (error "Code ~A is already defined for ~A." code name)
19        (setf (gethash code (restorers (find-backend 'cl-store)))
20              name))
21   code)
22
23
24 ;;  Type code constants
25 (defparameter +referrer-code+ (register-code 1 'referrer))
26 (defparameter +special-float-code+ (register-code 2 'special-float))
27 (defparameter +unicode-string-code+ (register-code 3 'unicode-string))
28 (defparameter +integer-code+ (register-code 4 'integer))
29 (defparameter +simple-string-code+ (register-code 5 'simple-string))
30 (defparameter +float-code+ (register-code 6 'float))
31 (defparameter +ratio-code+ (register-code 7 'ratio))
32 (defparameter +character-code+ (register-code 8 'character))
33 (defparameter +complex-code+ (register-code 9 'complex))
34 (defparameter +symbol-code+ (register-code 10 'symbol))
35 (defparameter +cons-code+ (register-code 11 'cons))
36 (defparameter +pathname-code+ (register-code 12 'pathname))
37 (defparameter +hash-table-code+ (register-code 13 'hash-table))
38 (defparameter +standard-object-code+ (register-code 14 'standard-object))
39 (defparameter +condition-code+ (register-code 15 'condition))
40 (defparameter +structure-object-code+ (register-code 16 'structure-object))
41 (defparameter +standard-class-code+ (register-code 17 'standard-class))
42 (defparameter +built-in-class-code+ (register-code 18 'built-in-class))
43 (defparameter +array-code+ (register-code 19 'array))
44 (defparameter +simple-vector-code+ (register-code 20 'simple-vector))
45 (defparameter +package-code+ (register-code 21 'package))
46 (defparameter +simple-byte-vector-code+ (register-code 22 'simple-byte-vector))
47
48 ;; fast storing for 32 bit ints
49 (defparameter +32-bit-integer-code+ (register-code 24 '32-bit-integer))
50 (defparameter +built-in-function-code+ (register-code 25 'built-in-function))
51 (defparameter +function-code+ (register-code 26 'function nil))
52 (defparameter +gf-code+ (register-code 27 'generic-function nil))
53
54 ;; Used by SBCL and CMUCL.
55 (defparameter +structure-class-code+ (register-code 28 'structure-class))
56 (defparameter +struct-def-code+ (register-code 29 'struct-def))
57
58 (defparameter +gensym-code+ (register-code 30 'gensym))
59
60 (defparameter +unicode-base-string-code+ (register-code 34 'unicode-base-string))
61 (defparameter +simple-base-string-code+ (register-code 35 'simple-base-string))
62
63 ;; setups for type code mapping
64 (defun output-type-code (code stream)
65   (declare (type ub32 code))
66   (write-byte (ldb (byte 8 0) code) stream))
67
68 (declaim (inline read-type-code))
69 (defun read-type-code (stream)
70   (read-byte stream))
71
72 (defmethod referrerp ((backend cl-store) (reader t))
73   (declare (optimize speed (safety 0) (space 0) (debug 0)))
74   (eql reader 'referrer))
75
76 (defparameter *restorers* (restorers (find-backend 'cl-store)))
77
78 ;; get-next-reader needs to return a symbol which will be used by the
79 ;; backend to lookup the function that was defined by
80 ;; defrestore-cl-store to restore it, or nil if not found.
81 (defun lookup-code (code)
82   (declare (optimize speed (safety 0) (space 0) (debug 0)))
83   (gethash code *restorers*))
84
85 (defmethod get-next-reader ((backend cl-store) (stream stream))
86   (declare (optimize speed (safety 0) (space 0) (debug 0)))
87   (let ((type-code (read-type-code stream)))
88     (or (lookup-code type-code)
89         (error "Type code ~A is not registered." type-code))))
90
91
92 ;; referrer, Required for a resolving backend
93 (defmethod store-referrer ((backend cl-store) (ref t) (stream t))
94   (output-type-code +referrer-code+ stream)
95   (dump-int ref stream))
96
97 (defrestore-cl-store (referrer stream)
98   (make-referrer :val (undump-int stream)))
99
100
101
102 ;; integers
103 ;; The theory is that most numbers will fit in 32 bits
104 ;; so we we have a little optimization for it
105
106 ;; We need this for circularity stuff.
107 (defmethod int-or-char-p ((backend cl-store) (type symbol))
108   (declare (optimize speed (safety 0) (space 0) (debug 0)))
109   (or (eql type '32-bit-integer)
110       (eql type 'integer)
111       (eql type 'character)))
112
113 (defstore-cl-store (obj integer stream)
114   (declare (optimize speed (safety 1) (debug 0)))
115   (if (typep obj 'sb32)
116       (store-32-bit-integer obj stream)
117       (store-arbitrary-integer obj stream)))
118
119 (defun dump-int (obj stream)
120   (declare (optimize speed (safety 0) (debug 0)))
121   (etypecase obj
122     ((unsigned-byte 8) (write-byte 1 stream) (write-byte obj stream))
123     ((unsigned-byte 32) (write-byte 2 stream) (store-32-bit obj stream))))
124
125 (defun undump-int (stream)
126   (declare (optimize speed (safety 0) (debug 0)))
127   (ecase (read-byte stream)
128     (1 (read-byte stream))
129     (2 (read-32-bit stream nil))))
130
131 (defun store-32-bit-integer (obj stream)
132   (declare (optimize speed (safety 1) (debug 0)) (type sb32 obj))
133   (output-type-code +32-bit-integer-code+ stream)
134   (write-byte (if (minusp obj) 1 0) stream)
135   (dump-int (abs obj) stream))
136
137 (defrestore-cl-store (32-bit-integer stream)
138   (declare (optimize speed (safety 1) (debug 0)))
139   (funcall (if (zerop (the fixnum (read-byte stream))) #'+ #'-)
140            (undump-int stream)))
141
142
143 (defun num->bits (num )
144   (loop for val = (abs num) then (ash val -8 )
145         for count from 0
146         until (zerop val)
147         collect (logand val #XFF) into bits
148         finally (return (values bits count))))
149
150 (defun store-arbitrary-integer (obj stream)
151   (declare (type integer obj) (stream stream)
152            (optimize speed))
153   (output-type-code +integer-code+ stream)
154   (multiple-value-bind (bits count) (num->bits obj)
155     (store-object (if (minusp obj) (- count) count)
156                   stream)
157     (dolist (x bits) (store-32-bit x stream))))
158
159
160 (defrestore-cl-store (integer buff)
161   (declare (optimize speed))
162   (let ((count (restore-object buff)))
163     (loop repeat (abs count)
164           with sum = 0
165           for pos from 0 by 8
166           for bit = (read-32-bit buff nil)
167           finally (return (if (minusp count) (- sum) sum))
168           :do
169           (incf sum (* bit (expt 2 pos))))))
170
171        
172
173 (defun bits->num (bits)
174   (loop with sum = 0
175         for pos from 0 by 8
176         for bit in bits
177         finally (return sum)
178         :do (incf sum (* bit (expt 2 pos)))))
179
180
181
182 ;; Floats (*special-floats* are setup in the custom.lisp files)
183
184 (defconstant +short-float-inf+ 0)
185 (defconstant +short-float-neg-inf+ 1)
186 (defconstant +short-float-nan+ 2)
187
188 (defconstant +single-float-inf+ 3)
189 (defconstant +single-float-neg-inf+ 4)
190 (defconstant +single-float-nan+ 5)
191
192 (defconstant +double-float-inf+ 6)
193 (defconstant +double-float-neg-inf+ 7)
194 (defconstant +double-float-nan+ 8)
195
196 (defconstant +long-float-inf+ 9)
197 (defconstant +long-float-neg-inf+ 10)
198 (defconstant +long-float-nan+ 11)
199
200 (defvar *special-floats* nil)
201
202 ;; Implementations are to provide an implementation for the create-float-value
203 ;; function
204 (defun create-float-values (value &rest codes)
205   "Returns a alist of special float to float code mappings."
206   (declare (ignore value codes))
207   nil)
208
209 (defun setup-special-floats ()
210   (setf *special-floats*
211         (nconc (create-float-values most-negative-short-float +short-float-inf+
212                                     +short-float-neg-inf+ +short-float-nan+)
213                (create-float-values most-negative-single-float +single-float-inf+
214                                     +single-float-neg-inf+ +single-float-nan+)
215                (create-float-values most-negative-double-float +double-float-inf+
216                                     +double-float-neg-inf+ +double-float-nan+)
217                (create-float-values most-negative-long-float +long-float-inf+
218                                     +long-float-neg-inf+ +long-float-nan+))))
219
220 (defstore-cl-store (obj float stream)
221   (declare (optimize speed))
222   (block body
223     (let (significand exponent sign)
224       (handler-bind (((or simple-error arithmetic-error type-error)
225                       #'(lambda (err)
226                           (declare (ignore err))
227                           (when-let (type (cdr (assoc obj *special-floats*)))
228                             (output-type-code +special-float-code+ stream)
229                             (write-byte type stream)
230                             (return-from body)))))
231         (multiple-value-setq (significand exponent sign)
232             (integer-decode-float obj))
233         (output-type-code +float-code+ stream)
234         (write-byte (float-type obj) stream)
235         (store-object significand stream)
236         (store-object (float-radix obj) stream)
237         (store-object exponent stream)
238         (store-object sign stream)))))
239
240 (defrestore-cl-store (float stream)
241   (float (* (the float (get-float-type (read-byte stream)))
242             (* (the integer (restore-object stream))
243                (expt (the integer (restore-object stream))
244                      (the integer (restore-object stream))))
245             (the integer (restore-object stream)))))
246
247 (defrestore-cl-store (special-float stream)
248   (or (car (rassoc (read-byte stream) *special-floats*))
249       (restore-error "Float ~S is not a valid special float.")))
250
251
252 ;; ratio
253 (defstore-cl-store (obj ratio stream)
254   (output-type-code +ratio-code+ stream)
255   (store-object (numerator obj) stream)
256   (store-object (denominator obj) stream))
257
258 (defrestore-cl-store (ratio stream)
259   (/ (the integer (restore-object stream))
260      (the integer (restore-object stream))))
261
262 ;; chars
263 (defstore-cl-store (obj character stream)
264   (output-type-code +character-code+ stream)   
265   (store-object (char-code obj) stream))
266
267 (defrestore-cl-store (character stream)
268   (code-char (restore-object stream)))
269
270 ;; complex
271 (defstore-cl-store (obj complex stream)
272   (output-type-code +complex-code+ stream)   
273   (store-object (realpart obj) stream)
274   (store-object (imagpart obj) stream))
275
276 (defrestore-cl-store (complex stream)
277   (complex (restore-object stream)
278            (restore-object stream)))
279
280 ;; symbols
281 (defstore-cl-store (obj symbol stream)
282   (declare (optimize speed))
283   (cond ((symbol-package obj)
284          (output-type-code +symbol-code+ stream)
285          (store-object (symbol-name obj) stream)
286          (store-object (package-name (symbol-package obj))
287                        stream))
288         ;; Symbols with no home package
289         (t (output-type-code +gensym-code+ stream)
290            (store-object (symbol-name obj) stream))))
291
292 (defrestore-cl-store (symbol stream)
293   (values (intern (restore-object stream)
294                   (restore-object stream))))
295
296 (defrestore-cl-store (gensym stream)
297   (make-symbol (restore-object stream)))
298
299
300 ;; Lists
301 (defun dump-list (list length last stream)
302   (declare (optimize speed (safety 1) (debug 0))
303            (type cons list))
304   (output-type-code +cons-code+ stream)
305   (store-object length stream)
306   (loop repeat length
307         for x on list do
308         (store-object (car x) stream))
309   (store-object last stream))
310
311 (defun restore-list (stream)
312   (declare (optimize speed (safety 1) (debug 0)))
313   (let* ((conses (restore-object stream))
314          (ret ())
315          (tail ret))
316     (dotimes (x conses)
317       (let ((obj (restore-object stream)))
318         ;; we can't use setting here since we wan't to
319         ;; be fairly efficient when adding objects to the
320         ;; end of the list.
321         (when (and *check-for-circs* (referrer-p obj))
322           (let ((x x))
323             (push (delay (setf (nth x ret)
324                                (referred-value obj *restored-values*)))
325                   *need-to-fix*)))
326         (if ret
327             (setf (cdr tail) (list obj)
328                   tail (cdr tail))
329             (setf ret (list obj)
330                   tail (last ret)))))
331     (let ((last1 (restore-object stream)))
332       ;; and check for the last possible circularity
333       (if (and *check-for-circs* (referrer-p last1))
334           (push (delay (setf (cdr tail)
335                              (referred-value last1 *restored-values*)))
336                 *need-to-fix*)
337           (setf (cdr tail) last1)))
338     ret))
339
340 (defstore-cl-store (list cons stream)
341   (multiple-value-bind (length last) (safe-length list)
342     (dump-list list length last stream)))
343
344 (defrestore-cl-store (cons stream)
345   (restore-list stream))
346
347
348 ;; pathnames
349 (defstore-cl-store (obj pathname stream)
350   (output-type-code +pathname-code+ stream)
351   (store-object #-sbcl (pathname-host obj)
352                 #+sbcl (host-namestring obj) stream)
353   (store-object (pathname-device obj) stream)
354   (store-object (pathname-directory obj) stream)
355   (store-object (pathname-name obj) stream)
356   (store-object (pathname-type obj) stream)
357   (store-object (pathname-version obj) stream))
358
359 (defrestore-cl-store (pathname stream)
360   (make-pathname
361    :host (restore-object stream)
362    :device (restore-object stream)
363    :directory (restore-object stream)
364    :name (restore-object stream)
365    :type (restore-object stream)
366    :version (restore-object stream)))
367
368
369 ;; hash tables
370 (defstore-cl-store (obj hash-table stream)
371   (declare (optimize speed))
372   (output-type-code +hash-table-code+ stream)   
373   (store-object (hash-table-rehash-size obj) stream)
374   (store-object (hash-table-rehash-threshold obj) stream)
375   (store-object (hash-table-size obj) stream)
376   (store-object (hash-table-test obj) stream)
377   (store-object (hash-table-count obj) stream)
378   (loop for key being the hash-keys of obj
379         using (hash-value value) do
380         (store-object key stream)
381         (store-object value stream)))
382
383 (defrestore-cl-store (hash-table stream)
384   (let ((rehash-size (restore-object stream))
385         (rehash-threshold (restore-object stream))
386         (size (restore-object stream))
387         (test (restore-object stream))
388         (count (restore-object stream)))
389     (declare (type integer count size))
390     (let ((hash (make-hash-table :test test
391                                  :rehash-size rehash-size
392                                  :rehash-threshold rehash-threshold
393                                  :size size)))
394       (resolving-object (x hash)
395         (loop repeat count do
396               ;; Unfortunately we can't use the normal setting here
397               ;; since there could be a circularity in the key
398               ;; and we need to make sure that both objects are
399               ;; removed from the stream at this point.
400               (setting-hash (restore-object stream)
401                             (restore-object stream))))
402       hash)))
403
404 ;; The dumping of objects works by serializing  the type of the object which
405 ;; is followed by applicable slot-name and value (depending on whether the
406 ;; slot is bound, it's allocation and *store-class-slots*). Once each slot
407 ;; is serialized a counter is incremented which is stored  at the end.
408 ;; When restoring the object a new instance is allocated and then
409 ;; restore-type-object starts reading objects from the stream.
410 ;; If the restored object is a symbol the it names a slot and it's value
411 ;; is pulled out and set on the newly allocated object.
412 ;; If the restored object is an integer then this is the end marker
413 ;; for the object and the number of slots restored is checked against
414 ;; this counter.
415
416 ;; Object and Conditions
417 (defun store-type-object (obj stream)
418   (declare (optimize speed))
419   (let ((all-slots (serializable-slots obj))
420         (length 0))
421     (store-object (type-of obj) stream)
422     (dolist (slot all-slots)
423       (let ((slot-name (slot-definition-name slot)))
424         (when (and (slot-boundp obj slot-name)
425                    (or *store-class-slots*
426                        (not (eql (slot-definition-allocation slot)
427                                  :class))))
428           (store-object (slot-definition-name slot) stream)
429           (store-object (slot-value obj slot-name) stream)
430           (incf length))))
431     (store-object length stream)))
432
433 (defstore-cl-store (obj standard-object stream)
434   (output-type-code +standard-object-code+ stream)   
435   (store-type-object obj stream))
436
437 (defstore-cl-store (obj condition stream)
438   (output-type-code +condition-code+ stream)   
439   (store-type-object obj stream))
440
441 (defun restore-type-object (stream)
442   (declare (optimize speed))
443   (let* ((class (find-class (restore-object stream)))
444          (new-instance (allocate-instance class)))
445     (resolving-object (obj new-instance)
446       (loop for count from 0 do
447             (let ((slot-name (restore-object stream)))
448               (etypecase slot-name
449                 (integer (assert (= count slot-name) (count slot-name)
450                            "Number of slots restored does not match slots stored.")
451                          (return))
452                 (symbol
453                  ;; slot-names are always symbols so we don't
454                  ;; have to worry about circularities
455                  (setting (slot-value obj slot-name) (restore-object stream)))))))
456     new-instance))
457
458 (defrestore-cl-store (standard-object stream)
459   (restore-type-object stream))
460
461 (defrestore-cl-store (condition stream)
462   (restore-type-object stream))
463
464
465 ;; classes
466 (defstore-cl-store (obj standard-class stream)
467   (output-type-code +standard-class-code+ stream)
468   (store-object (class-name obj) stream)
469   (store-object (mapcar #'get-slot-details (class-direct-slots obj))
470                 stream)
471   (store-object (mapcar (if *store-class-superclasses*
472                             #'identity
473                             #'class-name)
474                         (class-direct-superclasses obj))
475                 stream)
476   (store-object (type-of obj) stream))
477
478 (defrestore-cl-store (standard-class stream)
479   (let* ((class (restore-object stream))
480          (slots (restore-object stream))
481          (supers (restore-object stream))
482          (meta (restore-object stream))
483          (keywords '(:direct-slots :direct-superclasses
484                      :metaclass))
485          (final (loop for keyword in keywords
486                       for slot in (list slots
487                                         (or supers (list 'standard-object))
488                                         meta)
489                       nconc (list keyword slot))))
490     (cond ((find-class class nil)
491            (cond (*nuke-existing-classes*
492                   (apply #'ensure-class class final)
493                   #+(and clisp (not mop)) (add-methods-for-class class slots))
494                  (t (find-class class))))
495           (t (apply #'ensure-class class final)
496              #+(and clisp (not mop)) (add-methods-for-class class slots)))))
497
498 ;; built in classes
499
500 (defstore-cl-store (obj built-in-class stream)
501   (output-type-code +built-in-class-code+ stream)
502   (store-object (class-name obj) stream))
503
504 #-ecl ;; for some reason this doesn't work with ecl
505 (defmethod internal-store-object ((backend cl-store) (obj (eql (find-class 'hash-table))) stream)
506   (output-type-code +built-in-class-code+ stream)
507   (store-object 'cl:hash-table stream))
508
509 (defrestore-cl-store (built-in-class stream)
510   (find-class (restore-object stream)))
511
512
513 ;; Arrays, vectors and strings.
514 (defstore-cl-store (obj array stream)
515   (declare (optimize speed (safety 1) (debug 0)))
516   (typecase obj
517     (simple-base-string (store-simple-base-string obj stream))
518     (simple-string (store-simple-string obj stream))
519     (simple-vector (store-simple-vector obj stream))
520     ((simple-array (unsigned-byte 8) (*)) (store-simple-byte-vector obj stream))
521     (t (store-array obj stream))))
522
523
524 (defun store-array (obj stream)
525   (declare (optimize speed (safety 0) (debug 0))
526            (type array obj))
527   (output-type-code +array-code+ stream)
528   (if (and (= (array-rank obj) 1)
529            (array-has-fill-pointer-p obj))
530       (store-object (fill-pointer obj) stream)
531       (store-object nil stream))
532   (store-object (array-element-type obj) stream)
533   (store-object (adjustable-array-p obj) stream)
534   (store-object (array-dimensions obj) stream)
535   (dolist (x (multiple-value-list (array-displacement obj)))
536     (store-object x stream))
537   (store-object (array-total-size obj) stream)
538   (loop for x from 0 below (array-total-size obj) do
539         (store-object (row-major-aref obj x) stream)))
540
541  
542
543
544 (defrestore-cl-store (array stream)
545   (declare (optimize speed (safety 1) (debug 0)))
546   (let* ((fill-pointer (restore-object stream))
547          (element-type (restore-object stream))
548          (adjustable (restore-object stream))
549          (dimensions (restore-object stream))
550          (displaced-to (restore-object stream))
551          (displaced-offset (restore-object stream))
552          (size (restore-object stream))
553          (res (make-array dimensions 
554                           :element-type element-type
555                           :adjustable adjustable
556                           :fill-pointer fill-pointer)))
557     (declare (type cons dimensions) (type array-tot-size size))
558     (when displaced-to
559       (adjust-array res dimensions :displaced-to displaced-to
560                     :displaced-index-offset displaced-offset))
561     (resolving-object (obj res)
562       (loop for x from 0 below size do
563             (let ((pos x))
564               (setting (row-major-aref obj pos) (restore-object stream)))))))
565
566 (defun store-simple-vector (obj stream)
567   (declare (optimize speed (safety 0) (debug 0))
568            (type simple-vector obj))
569   (output-type-code +simple-vector-code+ stream)
570   (store-object (length obj) stream)
571   (loop for x across obj do
572     (store-object x stream)))
573
574 (defrestore-cl-store (simple-vector stream)
575   (declare (optimize speed (safety 1) (debug 0)))
576   (let* ((size (restore-object stream))
577          (res (make-array size)))
578     (declare (type array-size size))
579     (resolving-object (obj res)
580       (dotimes (i size)
581         ;; we need to copy the index so that
582         ;; it's value at this time is preserved.
583         (let ((x i))
584           (setting (aref obj x) (restore-object stream)))))
585     res))
586
587 (defun store-simple-byte-vector (obj stream)
588   (declare (optimize speed (safety 0) (debug 0))
589            (type (simple-array (unsigned-byte 8) (*)) obj))
590   (output-type-code +simple-byte-vector-code+ stream)
591   (store-object (length obj) stream)
592   (loop for x across obj do
593         (write-byte x stream)))
594  
595 (defrestore-cl-store (simple-byte-vector stream)
596   (declare (optimize speed (safety 1) (debug 0)))
597   (let* ((size (restore-object stream))
598          (res (make-array size :element-type '(unsigned-byte 8))))
599     (declare (type array-size size))
600     (resolving-object (obj res)
601       (dotimes (i size)
602         ;; we need to copy the index so that
603         ;; it's value at this time is preserved.
604         (let ((x i))
605           (setting (aref obj x) (read-byte stream)))))
606     res))
607
608 ;; Dumping (unsigned-byte 32) for each character seems
609 ;; like a bit much when most of them will be
610 ;; base-chars. So we try to cater for them.
611 (defvar *char-marker* (code-char 255)
612   "Largest character that can be represented in 8 bits")
613
614 (defun unicode-string-p (string)
615   "An implementation specific test for a unicode string."
616   (declare (optimize speed (safety 0) (debug 0))
617            (type simple-string string))
618   #+cmu nil ;; cmucl doesn't support unicode yet.
619   #+lispworks (not (typep string 'lw:8-bit-string))
620   #-(or cmu lispworks) (some #'(lambda (x) (char> x *char-marker*)) string))
621
622 (defun store-simple-string (obj stream)
623   (declare (type simple-string obj)
624            (optimize speed (safety 1) (debug 0)))
625   (cond ((unicode-string-p obj)
626          (output-type-code +unicode-string-code+ stream)
627          (dump-string #'dump-int obj stream))
628         (t (output-type-code +simple-string-code+ stream)
629            (dump-string #'write-byte obj stream))))
630
631 (defun store-simple-base-string (obj stream)
632   (declare (type simple-string obj)
633            (optimize speed (safety 1) (debug 0)))
634   (cond ((unicode-string-p obj)
635          (output-type-code +unicode-base-string-code+ stream)
636          (dump-string #'dump-int obj stream))
637         (t (output-type-code +simple-base-string-code+ stream)
638            (dump-string #'write-byte obj stream))))
639
640 (defun dump-string (dumper obj stream)
641   (declare (simple-string obj) (function dumper) (stream stream)
642            (optimize speed (safety 1) (debug 0)))
643   (dump-int (the array-size (length obj)) stream)
644   (loop for x across obj do (funcall dumper (char-code x) stream)))
645
646 (defrestore-cl-store (simple-string stream)
647   (declare (optimize speed))
648   (undump-string #'read-byte 'character stream))
649
650 (defrestore-cl-store (unicode-string stream)
651   (declare (optimize speed))
652   (undump-string #'undump-int 'character stream))
653
654 (defrestore-cl-store (simple-base-string stream)
655   (declare (optimize speed))
656   (undump-string #'read-byte 'base-char stream))
657
658 (defrestore-cl-store (unicode-base-string stream)
659   (declare (optimize speed))
660   (undump-string #'undump-int 'base-char stream))
661
662 (defun undump-string (reader type stream)
663   (declare (type function reader) (type stream stream)
664            (optimize speed (safety 1) (debug 0)))
665   (let* ((length (the array-size (undump-int stream)) )
666          (res (make-string length :element-type type)))
667     (declare (type simple-string res))
668     (dotimes (x length)
669       (setf (schar res x) (code-char (funcall reader stream))))
670     res))
671
672 ;; packages (from Thomas Stenhaug)
673 (defstore-cl-store (obj package stream)
674   (output-type-code +package-code+ stream) 
675   (store-object (package-name obj) stream)
676   (store-object (package-nicknames obj) stream)
677   (store-object (mapcar (if *store-used-packages* #'identity #'package-name)
678                         (package-use-list obj))
679                 stream)
680   (store-object (internal-symbols obj) stream)
681   (store-object (package-shadowing-symbols obj) stream)
682   (store-object (external-symbols obj) stream))
683
684 (defun remove-remaining (times stream)
685   (declare (optimize speed) (type fixnum times))
686   (dotimes (x times)
687     (restore-object stream)))
688
689 (defrestore-cl-store (package stream)
690   (let* ((package-name (restore-object stream))
691          (existing-package (find-package package-name)))
692     (cond ((or (not existing-package)
693                (and existing-package *nuke-existing-packages*))
694            (restore-package package-name stream :force *nuke-existing-packages*))
695           (t (remove-remaining 5 stream)
696              existing-package))))
697
698 (defun internal-symbols (package)
699   (let ((acc (make-array 100 :adjustable t :fill-pointer 0))
700         (used (package-use-list package)))
701     (do-symbols (symbol package)
702       (unless (find (symbol-package symbol) used)
703         (vector-push-extend symbol acc)))
704     acc))
705
706 (defun external-symbols (package)
707   (let ((acc (make-array 100 :adjustable t :fill-pointer 0)))
708     (do-external-symbols (symbol package)
709       (vector-push-extend symbol acc))
710     acc))
711
712 (defun restore-package (package-name stream &key force)
713   (when (and force (find-package package-name))
714     (delete-package package-name))
715   (let ((package (make-package package-name
716                                :nicknames (restore-object stream)
717                                :use (restore-object stream))))
718     (loop for symbol across (restore-object stream) do
719       (import symbol package))
720     (shadow (restore-object stream) package)
721     (loop for symbol across (restore-object stream) do
722       (export symbol package))
723     package))
724
725 ;; Function storing hack.
726 ;; This just stores the function name if we can find it
727 ;; or signal a store-error.
728 (defun parse-name (name)
729   (let ((name (subseq name 21)))
730     (declare (type simple-string name))
731     (if (search name "SB!" :end1 3)
732         (replace name "SB-" :end1 3)
733         name)))
734
735 #+sbcl
736 (defvar *sbcl-readtable* (copy-readtable nil))
737 #+sbcl
738 (set-macro-character #\# #'(lambda (c s)
739                              (declare (ignore c s))
740                              (store-error "Invalid character in function name."))
741                      nil
742                      *sbcl-readtable*)
743
744 (defun get-function-name (obj)
745   (multiple-value-bind (l cp name) (function-lambda-expression obj)
746     (declare (ignore l cp))
747     (cond ((and name (or (symbolp name) (consp name))) name)
748           ;;  Try to deal with sbcl's naming convention
749           ;; of built in functions (pre 0.9)
750           #+sbcl
751           ((and name (stringp name)
752                 (search "top level local call " (the simple-string name)))
753            (let ((new-name (parse-name name))
754                  (*readtable* *sbcl-readtable*))
755              (unless (string= new-name "")
756                (handler-case (read-from-string new-name)
757                  (error (c)
758                    (declare (ignore c))
759                    (store-error "Unable to determine function name for ~A."
760                                 obj))))))
761           (t (store-error "Unable to determine function name for ~A."
762                           obj)))))
763  
764
765 #-clisp
766 (defstore-cl-store (obj function stream)
767   (output-type-code +function-code+ stream)
768   (store-object (get-function-name obj) stream))
769
770 #-clisp
771 (defrestore-cl-store (function stream)
772   (fdefinition (restore-object stream)))
773
774 ;; Generic function, just dumps the gf-name
775 (defstore-cl-store (obj generic-function stream)
776   (output-type-code +gf-code+ stream)
777   (aif (generic-function-name obj)
778        (store-object it stream)
779        (store-error "No generic function name for ~A." obj)))
780
781 (defrestore-cl-store (generic-function stream)
782   (fdefinition (restore-object stream)))
783
784
785 (setf *default-backend* (find-backend 'cl-store))
786
787 ;; EOF
Note: See TracBrowser for help on using the browser.