1
1
2
+
3
+
2
4
class Hash
3
5
4
6
class Deleted
5
- def self . eql? other
7
+ def eql? other
6
8
false
7
9
end
10
+
11
+ #def self.nil?
12
+ # true
13
+ #end
8
14
end
9
15
16
+ DELETED = Deleted . new
17
+
10
18
def initialize defval = nil
11
19
@length = 0
12
- @capacity = 4
20
+ #@deleted = 0
21
+ @capacity = 7
13
22
_alloc_data
14
23
@first = nil
15
24
@last = nil
@@ -20,24 +29,41 @@ def initialize defval = nil
20
29
# but to make code that just wants to create an empty literal
21
30
# Hash nicer, we do this:
22
31
def self . []
23
- Hash . new
32
+ self . new
33
+ end
34
+
35
+ def _data
36
+ @data
37
+ end
38
+
39
+ def _state
40
+ [ @first , @last ]
24
41
end
25
42
26
43
def _alloc_data
27
44
# FIXME: If there's a pre-existing array, resize it
28
45
@data = Array . new ( @capacity * 4 )
29
46
end
30
47
48
+ def not_deleted? ( o )
49
+ #%s(if (ne o Deleted) true false)
50
+ o != DELETED
51
+ end
52
+
31
53
# Bulk insert all entries found by probing from slot 'first'
32
54
def _bulkinsert ( data , first )
33
55
@length = 0
34
56
cur = first
35
57
while cur
36
58
k = data [ cur ]
59
+ # FIXME: Check for `Deleted`?
37
60
if k
38
- # FIXME: Combining these on one line triggers bug.
39
- v = data [ cur + 1 ]
40
- self [ k ] = v
61
+ if not_deleted? ( k )
62
+ # FIXME: Doing k == Deleted or k != Deleted here fails.
63
+ # FIXME: Combining these on one line triggers bug.
64
+ v = data [ cur + 1 ]
65
+ self [ k ] = v
66
+ end
41
67
end
42
68
cur = data [ cur + 2 ]
43
69
end
@@ -51,8 +77,8 @@ def _grow
51
77
olddata = @data
52
78
oldfirst = @first
53
79
54
- # Grow
55
- @capacity = @capacity * 2
80
+ # Grow
81
+ @capacity = @capacity * 4 + 1
56
82
_alloc_data
57
83
58
84
# For insertion order:
@@ -66,16 +92,55 @@ def _grow
66
92
# the matching key *or* the first one that is unoccupied
67
93
#
68
94
def _find_slot ( key )
69
- pos = ( key . hash % @capacity ) * 4
95
+ h = key . hash
96
+ # s = key.to_s
97
+ pos = ( h % @capacity ) * 4
98
+ # %s(printf "key='%s'\n" (callm s __get_raw))
99
+ # %s(printf "hash=%ld,pos=%d\n" (callm h __get_raw) (callm pos __get_raw))
100
+ cap = @capacity * 4
101
+
102
+
103
+
104
+
105
+ # This should always eventually end as we require
106
+ # @capacity to be larger than @length, which should
107
+ # mean that there should always be at least one
108
+ # empty slot.
109
+ #
110
+ #puts "START FOR KEY: #{key}"
111
+ while !( d = @data [ pos ] ) . nil? and !key . eql? ( d )
112
+ %s(__docnt)
113
+ pos = ( pos + 4 )
114
+ if pos >= cap
115
+ pos -= cap
116
+ end
117
+ end
118
+ pos
119
+ end
120
+
121
+ def _find_insertion_slot ( key )
122
+ h = key . hash
123
+ pos = ( h % @capacity ) * 4
70
124
cap = @capacity * 4
71
125
72
126
# This should always eventually end as we require
73
127
# @capacity to be larger than @length, which should
74
- # mean that there should always be at least one
128
+ # mean that there should always be at least one
75
129
# empty slot.
76
130
#
77
- while d = @data [ pos ] and !key . eql? ( d )
78
- pos = ( pos + 4 % cap )
131
+ #puts "START FOR KEY: #{key}"
132
+ while !( d = @data [ pos ] ) . nil? and !key . eql? ( d )
133
+ oldpos = pos
134
+ pos = ( pos + 4 )
135
+ if pos >= cap
136
+ pos -= cap
137
+ end
138
+
139
+ if !not_deleted? ( d )
140
+ if @data [ pos ] . nil?
141
+ return oldpos
142
+ end
143
+ end
79
144
end
80
145
pos
81
146
end
@@ -90,7 +155,7 @@ def include? key
90
155
end
91
156
92
157
def empty?
93
- @length == 0
158
+ @first . nil?
94
159
end
95
160
96
161
def [] key
@@ -106,20 +171,25 @@ def capacity_too_low
106
171
end
107
172
108
173
def []= key , value
109
- limit = ( @capacity * 3 ) / 4
174
+ limit = @capacity / 2
110
175
111
176
_grow if limit <= @length
112
177
113
178
capacity_too_low if @capacity <= @length
114
179
115
- slot = _find_slot ( key )
180
+ slot = _find_insertion_slot ( key )
116
181
new = @data [ slot ] . nil?
117
182
if new
118
183
@length = @length + 1
119
184
end
120
185
121
186
@data [ slot +1 ] = value
122
- return if !new
187
+ ndel = not_deleted? ( @data [ slot ] )
188
+ if !new
189
+ if ndel
190
+ return
191
+ end
192
+ end
123
193
124
194
@data [ slot ] = key
125
195
# Maintain insertion order:
@@ -136,28 +206,14 @@ def []= key,value
136
206
nil
137
207
end
138
208
139
- def __delete_first
140
- return if !@first
141
- old = @first
142
- @first = @data [ @first +2 ]
143
- if old == @last
144
- @last = @first
145
- end
146
- @data [ old ] = nil
147
- @data [ old +1 ] = nil
148
- @data [ old +2 ] = nil
149
- @data [ old +3 ] = nil
150
- @length -= 1
151
- end
152
-
153
209
def shift
154
210
return nil if !@first
155
211
156
212
slot = @first
157
213
key = @data [ slot ]
158
214
value = @data [ slot +1 ]
159
215
160
- __delete_first
216
+ delete ( key )
161
217
[ key , value ]
162
218
end
163
219
@@ -182,7 +238,7 @@ def each
182
238
capacity = @capacity * 2
183
239
slot = @first
184
240
while slot
185
- if ( key = @data [ slot ] ) && Deleted != key
241
+ if ( key = @data [ slot ] ) && key != DELETED
186
242
value = @data [ slot + 1 ]
187
243
yield key , value
188
244
end
@@ -210,8 +266,27 @@ def delete key
210
266
slot = _find_slot ( key )
211
267
return nil if !@data [ slot ]
212
268
value = @data [ slot +1 ]
213
- @data [ slot ] = Deleted
269
+ @data [ slot ] = DELETED
214
270
@data [ slot +1 ] = nil
271
+
272
+ # Unlink record
273
+ n = @data [ slot +2 ]
274
+ prev = @data [ slot +3 ]
275
+ if prev
276
+ @data [ prev +2 ] = n
277
+ end
278
+ if n
279
+ @data [ n +3 ] = prev
280
+ end
281
+ if @first == slot
282
+ @first = n
283
+ end
284
+ if @last == slot
285
+ @last = prev
286
+ end
287
+
288
+ # FIXME: It fails without this, which indicates a bug.
289
+ #@length -= 1
215
290
value
216
291
end
217
292
0 commit comments