1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Copyright 2004-2008 Jean Privat <jean@pryen.org>
5 # This file is free software, which comes along with NIT. This software is
6 # distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
7 # without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
8 # PARTICULAR PURPOSE. You can modify it is you want, provided this header
9 # is kept unaltered, and a notification of the changes is added.
10 # You are allowed to redistribute it and sell it, alone or is a part of
13 # This module is about hashable things.
14 # It introduces an hash funtion in objects.
15 # It also introduces two classes, an Hashmap and an Hashset.
21 # The hash code of the object.
22 # Assuming that a = b -> a.hash = b.hash
24 # Without redefinition, it is the `id' of the instance.
25 meth hash
: Int do return object_id
/ 8
36 h
= (h
* 32) + h
+ it
[i
].ascii
45 redef meth hash
do return self
49 redef meth hash
do return ascii
63 # A HashCollection is an array of HashNode[K] indexed by the K hash value
64 private class HashCollection[K
: Object, N
: HashNode[K
], E
]
66 special ArrayCapable[nullable N
]
67 attr _array
: nullable NativeArray[nullable N
] = null # Used to store items
68 attr _capacity
: Int = 0 # Size of _array
69 redef readable attr _length
: Int = 0 # Number of items in the map
71 readable attr _first_item
: nullable N
= null # First added item (used to visit items in nice order)
72 attr _last_item
: nullable N
= null # Last added item (same)
74 # The last index accessed
75 attr _last_accessed_index
: Int = -1
77 # The last key accessed
78 attr _last_accessed_key
: nullable K
= null
80 # Return the index of the k element
81 meth index_at
(k
: K
): Int
85 # Fisrt step: look in the last indexed elt
86 if k
== _last_accessed_key
then return _last_accessed_index
88 # Compute the base position of the key
89 var base
= k
.hash
% _capacity
90 if base
< 0 then base
= - base
92 # Look for the key in the array
96 if c
== null or c
.key
== k
then # REAL equals
97 _last_accessed_index
= cur
98 _last_accessed_key
= k
102 if cur
< 0 then cur
= _capacity
- 1
103 assert no_loop
: cur
!= base
108 # Add a new node (should be free)
109 meth store
(index
: Int, node
: N
)
111 # Store the item in the list
112 if _first_item
== null then
115 _last_item
.next_item
= node
117 node
.prev_item
= _last_item
118 node
.next_item
= null
120 # Then store it in the array
121 assert _array
[index
] == null
125 l
= (l
+ 5) * 150 / 100
126 if l
>= _capacity
then
131 meth remove_index
(i
: Int)
133 assert correct_index
: i
>= 0 and i
< _capacity
135 assert has_couple
: node
!= null
136 # Remove the item in the list
137 var prev
= node
.prev_item
138 var next
= node
.next_item
140 prev
.next_item
= next
145 next
.prev_item
= prev
149 # Remove the item in the array
152 # Now replaces things before if needed
162 var i2
= index_at
(n
.key
)
165 assert _array
[i2
] == null
173 var i
= _capacity
- 1
181 _last_accessed_key
= null
184 meth enlarge
(cap
: Int)
186 var old_cap
= _capacity
188 # cap = cap * 130 / 100 + 5 + 1000 # /
189 if cap
< _length
+ 1 then cap
= _length
+ 1
190 if cap
<= _capacity
then return
192 _last_accessed_key
= null
195 var new_array
= calloc_array
(cap
)
198 # clean the new array
205 if _capacity
<= old_cap
then return
207 var new_array
= _array
208 # Reput items in the array
209 var node
= _first_item
210 while node
!= null do
211 var ind
= index_at
(node
.key
)
212 assert new_array
[ind
] == null
213 new_array
[ind
] = node
214 node
= node
.next_item
216 _last_accessed_key
= null
220 private class HashNode[K
]
221 meth key
: K
is abstract
223 readable writable attr _next_item
: nullable N
= null
224 readable writable attr _prev_item
: nullable N
= null
228 special CoupleMap[K
, V
]
229 special HashCollection[K
, HashMapNode[K
, V
], V
]
231 redef meth iterator
: HashMapIterator[K
, V
] do return new HashMapIterator[K
,V
](self)
236 return _first_item
.second
239 redef meth is_empty
do return _length
== 0
241 redef meth count
(item
)
245 while i
< _capacity
do
247 if c
!= null and c
.second
== item
then nb
+= 1
256 while i
< _capacity
do
258 if c
!= null and c
.second
== item
then return true
264 redef meth has_only
(item
)
267 while i
< _capacity
do
269 if c
!= null and c
.second
!= item
then return false
275 redef meth
[]=(key
, v
)
278 var i
= index_at
(key
)
284 store
(i
, new HashMapNode[K
, V
](key
, v
))
288 redef meth remove
(item
)
291 while i
< _capacity
do
293 if c
!= null and c
.second
== item
then
301 redef meth remove_at
(key
) do remove_index
(index_at
(key
))
303 redef meth clear
do raz
305 redef meth couple_at
(key
) do return _array
[index_at
(key
)]
315 class HashMapNode[K
, V
]
318 redef meth key
do return first
319 redef type N
: HashMapNode[K
, V
]
328 class HashMapIterator[K
, V
]
329 special MapIterator[K
, V
]
330 redef meth is_ok
do return _node
!= null
338 #redef meth item=(value)
341 # _node.second = value
353 _node
= _node
.next_item
356 # The map to iterate on
357 attr _map
: HashMap[K
, V
]
360 attr _node
: nullable HashMapNode[K
, V
]
362 init(map
: HashMap[K
, V
])
365 _node
= map
.first_item
371 special HashCollection[E
, HashSetNode[E
], E
]
373 redef meth is_empty
do return _length
== 0
378 return _first_item
.key
383 return _array
[index_at
(item
)] != null
388 var i
= index_at
(item
)
393 store
(i
,new HashSetNode[E
](item
))
397 redef meth remove
(item
) do remove_index
(index_at
(item
))
399 redef meth clear
do raz
401 redef meth iterator
do return new HashSetIterator[E
](self)
413 redef type N
: HashSetNode[E
]
415 redef readable writable attr _key
: E
423 class HashSetIterator[E
]
425 redef meth is_ok
do return _node
!= null
436 _node
= _node
.next_item
439 # The set to iterate on
440 attr _set
: HashSet[E
]
442 # The position in the internal map storage
443 attr _node
: nullable HashSetNode[E
]
445 init(set
: HashSet[E
])
448 _node
= set
.first_item