File: image-table.scm

package info (click to toggle)
scheme48 1.9.2-1
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 18,232 kB
  • sloc: lisp: 88,907; ansic: 87,519; sh: 3,224; makefile: 771
file content (160 lines) | stat: -rw-r--r-- 4,920 bytes parent folder | download | duplicates (4)
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
; -*- Mode: Scheme; Syntax: Scheme; Package: Scheme; -*-
; Part of Scheme 48 1.9.  See file COPYING for notices and license.

; Authors: Richard Kelsey, Jonathan Rees

; A hash table for writing images.  Objects to be written out are saved in
; the table.

; This needs to be here because the Pre-Scheme compiler does not currently
; support polymorphic data types (so the table cannot be polymorphic, so
; we need to have this before we can define tables).

(define-record-type image-location :image-location
  (really-make-image-location new-descriptor next)
  (new-descriptor integer image-location-new-descriptor set-image-location-new-descriptor!)
  (next           integer image-location-next set-image-location-next!))

(define (make-image-location new-descriptor)
  (really-make-image-location new-descriptor 0))

;----------------------------------------------------------------

(define-record-type table :table
  (really-make-table keys values count size)
  (keys   (^ integer)        table-keys   set-table-keys!)
  (values (^ image-location) table-values set-table-values!)
  (count  integer            table-count  set-table-count!)
  (size   integer            table-size   set-table-size!))

(define initial-table-size (shift-left 1 12))

; MAKE-VECTOR uses the initial value only to determine the type of the vector.
; It doesn't do the fill (which is really dumb).

(define (make-table)
  (let ((keys (make-vector (+ initial-table-size 1) 0)))
    (vector+length-fill! keys (+ initial-table-size 1) 0)
    (really-make-table keys
		       (make-vector initial-table-size (null-pointer))
		       0
		       initial-table-size)))

(define (deallocate-table table)
  (let ((keys (table-keys table))
	(values (table-values table)))
    (do ((i 0 (+ i 1)))
	((= i (table-size table)))
      (if (not (= (vector-ref keys i) 0))
	  (deallocate (vector-ref values i))))
    (deallocate keys)
    (deallocate values)
    (deallocate table)))

; The if we run out of memory we mark the table as unusable.  The image-writing
; code does the same.

(define (table-okay? table)
  (< 0 (table-size table)))

(define (break-table! table)
  (set-table-size! table 0))

; Assumes SIZE is a power of two.
; I have no idea how effective this hash function is.

(define (hash key size)
  (bitwise-and (bitwise-xor key
			    (bitwise-xor (shift-left key 1)
					 (arithmetic-shift-right key 10)))
	       (- size 1)))

; Double the size of the table.

(define (table-grow table)
  (let ((new-size (* (table-size table) 2))
	(old-size (table-size table))
	(old-keys (table-keys table))
	(old-values (table-values table)))
    (let ((new-keys (make-vector (+ new-size 1) 0))
	  (new-values (make-vector new-size (null-pointer))))
      (cond ((or (null-pointer? new-keys)
		 (null-pointer? new-values))
	     (if (not (null-pointer? new-keys))
		 (deallocate new-keys))
	     (if (not (null-pointer? new-values))
		 (deallocate new-values))
	     (break-table! table))
	    (else
	     (set-table-keys!   table new-keys)
	     (set-table-values! table new-values)
	     (set-table-size!   table new-size)
	     (set-table-count!  table 0)
	     (vector+length-fill! new-keys	 ; MAKE-VECTOR doesn't fill
				  (+ new-size 1)
				  0)
	     (do ((i 0 (+ i 1)))
		 ((= i old-size))
	       (let ((key (vector-ref old-keys i)))
		 (if (not (= key 0))
		     (table-insert! new-size
				    new-keys
				    new-values
				    key
				    (vector-ref old-values i)))))
	     (deallocate old-keys)
	     (deallocate old-values))))))

(define (table-insert! size keys values key value)
  (let loop ((i (hash key size)))
    (cond ((not (= (vector-ref keys i) 0))
	   (loop (+ i 1)))
	  ((= i size)
	   (loop 0))
	  (else
	   (vector-set! keys   i key)
	   (vector-set! values i value)))))

(define (table-find table key found not-found)
  (let ((start (hash key (table-size table)))
	(keys (table-keys table)))
    (let loop ((i start))
      (let ((next (vector-ref keys i)))
	(cond ((= key next)
	       (found i))
	      ((not (= next 0))
	       (loop (+ i 1)))
	      ((= i (table-size table))
	       (loop 0))
	      (else
	       (not-found i)))))))

(define (table-set! table key value)
  (if (table-okay? table)
      (table-find table
		  key
		  (lambda (i)
		    ; A. this should not happen
		    ; B. if it were to, who would delete the old value?
		    (vector-set! (table-values table) i value))
		  (lambda (i)
		    (vector-set! (table-keys   table) i key)
		    (vector-set! (table-values table) i value)
		    (set-table-count! table (+ (table-count table) 1))
		    (if (= (table-count table)
			   (quotient (table-size table) 3))
			(table-grow table))
		    (unspecific)))
      (unspecific)))

(define (table-ref table key)
  (if (table-okay? table)
      (table-find table
		  key
		  (lambda (i)
		    (vector-ref (table-values table) i))
		  (lambda (i)
		    (null-pointer)))
      (null-pointer)))