Skip to content

Commit 1dec2c8

Browse files
committed
The Hash class is still absolutely awful and a mess, but committing
current state prior to attempt at rewriting it, as this version "works" well enough to self-host the compiler.
1 parent 548e82a commit 1dec2c8

File tree

1 file changed

+108
-33
lines changed

1 file changed

+108
-33
lines changed

lib/core/hash.rb

Lines changed: 108 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,24 @@
11

2+
3+
24
class Hash
35

46
class Deleted
5-
def self.eql? other
7+
def eql? other
68
false
79
end
10+
11+
#def self.nil?
12+
# true
13+
#end
814
end
915

16+
DELETED = Deleted.new
17+
1018
def initialize defval = nil
1119
@length = 0
12-
@capacity = 4
20+
#@deleted = 0
21+
@capacity = 7
1322
_alloc_data
1423
@first = nil
1524
@last = nil
@@ -20,24 +29,41 @@ def initialize defval = nil
2029
# but to make code that just wants to create an empty literal
2130
# Hash nicer, we do this:
2231
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]
2441
end
2542

2643
def _alloc_data
2744
# FIXME: If there's a pre-existing array, resize it
2845
@data = Array.new(@capacity * 4)
2946
end
3047

48+
def not_deleted?(o)
49+
#%s(if (ne o Deleted) true false)
50+
o != DELETED
51+
end
52+
3153
# Bulk insert all entries found by probing from slot 'first'
3254
def _bulkinsert (data,first)
3355
@length = 0
3456
cur = first
3557
while cur
3658
k = data[cur]
59+
# FIXME: Check for `Deleted`?
3760
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
4167
end
4268
cur = data[cur + 2]
4369
end
@@ -51,8 +77,8 @@ def _grow
5177
olddata = @data
5278
oldfirst = @first
5379

54-
# Grow
55-
@capacity = @capacity * 2
80+
# Grow
81+
@capacity = @capacity * 4 + 1
5682
_alloc_data
5783

5884
# For insertion order:
@@ -66,16 +92,55 @@ def _grow
6692
# the matching key *or* the first one that is unoccupied
6793
#
6894
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
70124
cap = @capacity * 4
71125

72126
# This should always eventually end as we require
73127
# @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
75129
# empty slot.
76130
#
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
79144
end
80145
pos
81146
end
@@ -90,7 +155,7 @@ def include? key
90155
end
91156

92157
def empty?
93-
@length == 0
158+
@first.nil?
94159
end
95160

96161
def [] key
@@ -106,20 +171,25 @@ def capacity_too_low
106171
end
107172

108173
def []= key,value
109-
limit = (@capacity * 3) / 4
174+
limit = @capacity / 2
110175

111176
_grow if limit <= @length
112177

113178
capacity_too_low if @capacity <= @length
114179

115-
slot = _find_slot(key)
180+
slot = _find_insertion_slot(key)
116181
new = @data[slot].nil?
117182
if new
118183
@length = @length + 1
119184
end
120185

121186
@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
123193

124194
@data[slot] = key
125195
# Maintain insertion order:
@@ -136,28 +206,14 @@ def []= key,value
136206
nil
137207
end
138208

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-
153209
def shift
154210
return nil if !@first
155211

156212
slot = @first
157213
key = @data[slot]
158214
value = @data[slot+1]
159215

160-
__delete_first
216+
delete(key)
161217
[key,value]
162218
end
163219

@@ -182,7 +238,7 @@ def each
182238
capacity = @capacity * 2
183239
slot = @first
184240
while slot
185-
if (key = @data[slot]) && Deleted != key
241+
if (key = @data[slot]) && key != DELETED
186242
value = @data[slot + 1]
187243
yield key,value
188244
end
@@ -210,8 +266,27 @@ def delete key
210266
slot = _find_slot(key)
211267
return nil if !@data[slot]
212268
value = @data[slot+1]
213-
@data[slot] = Deleted
269+
@data[slot] = DELETED
214270
@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
215290
value
216291
end
217292

0 commit comments

Comments
 (0)