1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Copyright 2004-2009 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 # Introduce Hashmap and Hashset.
14 package hash_collection
19 # A HashCollection is an array of HashNode[K] indexed by the K hash value
20 private class HashCollection[K
: Object, N
: HashNode[K
], E
]
22 special ArrayCapable[nullable N
]
23 var _array
: nullable NativeArray[nullable N
] = null # Used to store items
24 var _capacity
: Int = 0 # Size of _array
25 redef readable var _length
: Int = 0 # Number of items in the map
27 readable var _first_item
: nullable N
= null # First added item (used to visit items in nice order)
28 var _last_item
: nullable N
= null # Last added item (same)
30 # The last index accessed
31 var _last_accessed_index
: Int = -1
33 # The last key accessed
34 var _last_accessed_key
: nullable K
= null
36 # Return the index of the k element
37 fun index_at
(k
: K
): Int
41 # Fisrt step: look in the last indexed elt
42 if k
== _last_accessed_key
then return _last_accessed_index
44 # Compute the base position of the key
45 var base
= k
.hash
% _capacity
46 if base
< 0 then base
= - base
48 # Look for the key in the array
52 if c
== null or c
._key
== k
then # REAL equals
53 _last_accessed_index
= cur
54 _last_accessed_key
= k
58 if cur
< 0 then cur
= _capacity
- 1
59 assert no_loop
: cur
!= base
60 if false then break # FIXME remove once unreach loop exits are in c_src
62 abort #FIXME remove once unreach loop exits are in c_src
65 # Return the node assosiated with the key
66 fun node_at
(k
: K
): nullable N
68 var res
= node_at_idx
(index_at
(k
), k
)
72 # Return the node assosiated with the key (but with the index already known)
73 fun node_at_idx
(i
: Int, k
: K
): nullable N
78 # Add a new node (should be free)
79 fun store
(index
: Int, node
: N
)
81 # Store the item in the list
82 if _first_item
== null then
85 _last_item
._next_item
= node
87 node
._prev_item
= _last_item
88 node
._next_item
= null
90 # Then store it in the array
91 assert _array
[index
] == null
95 l
= (l
+ 5) * 150 / 100
96 if l
>= _capacity
then
101 # Remove the node assosiated with the key
102 fun remove_node
(k
: K
)
106 if node
== null then return
107 # Remove the item in the list
108 var prev
= node
._prev_item
109 var next
= node
._next_item
111 prev
._next_item
= next
116 next
._prev_item
= prev
120 # Remove the item in the array
123 # Now replaces things before if needed
133 var i2
= index_at
(n
._key
)
136 assert _array
[i2
] == null
144 var i
= _capacity
- 1
152 _last_accessed_key
= null
155 fun enlarge
(cap
: Int)
157 var old_cap
= _capacity
159 if cap
< _length
+ 1 then cap
= _length
+ 1
160 if cap
<= _capacity
then return
162 _last_accessed_key
= null
165 var new_array
= calloc_array
(cap
)
168 # clean the new array
175 if _capacity
<= old_cap
then return
177 # Reput items in the array
178 var node
= _first_item
179 while node
!= null do
180 var ind
= index_at
(node
._key
)
181 assert new_array
[ind
] == null
182 new_array
[ind
] = node
183 node
= node
._next_item
185 _last_accessed_key
= null
189 private class HashNode[K
]
192 readable writable var _next_item
: nullable N
= null
193 readable writable var _prev_item
: nullable N
= null
202 special HashCollection[K
, HashMapNode[K
, V
], V
]
214 redef fun has_key
(key
) do return node_at
(key
) != null
216 redef fun iterator
: HashMapIterator[K
, V
] do return new HashMapIterator[K
,V
](self)
231 return _first_item
._value
234 redef fun is_empty
do return _length
== 0
236 redef fun count
(item
)
241 if c
._value
== item
then nb
+= 1
251 if c
._value
== item
then return true
257 redef fun has_only
(item
)
261 if c
._value
!= item
then return false
267 redef fun []=(key
, v
)
270 var i
= index_at
(key
)
271 var c
= node_at_idx
(i
, key
)
276 store
(i
, new HashMapNode[K
, V
](key
, v
))
280 redef fun remove
(item
)
284 if c
._value
== item
then
292 redef fun remove_at
(key
) do remove_node
(key
)
294 redef fun clear
do raz
304 class HashMapNode[K
, V
]
306 redef type N
: HashMapNode[K
, V
]
316 class HashMapIterator[K
, V
]
317 special MapIterator[K
, V
]
318 redef fun is_ok
do return _node
!= null
326 #redef fun item=(value)
329 # _node.second = value
341 _node
= _node
._next_item
344 # The map to iterate on
345 var _map
: HashMap[K
, V
]
348 var _node
: nullable HashMapNode[K
, V
]
350 init(map
: HashMap[K
, V
])
353 _node
= map
.first_item
359 special HashCollection[E
, HashSetNode[E
], E
]
361 redef fun is_empty
do return _length
== 0
366 return _first_item
._key
371 return node_at
(item
) != null
376 var i
= index_at
(item
)
377 var c
= node_at_idx
(i
, item
)
381 store
(i
,new HashSetNode[E
](item
))
385 redef fun remove
(item
) do remove_node
(item
)
387 redef fun clear
do raz
389 redef fun iterator
do return new HashSetIterator[E
](self)
401 redef type N
: HashSetNode[E
]
409 class HashSetIterator[E
]
411 redef fun is_ok
do return _node
!= null
422 _node
= _node
._next_item
425 # The set to iterate on
428 # The position in the internal map storage
429 var _node
: nullable HashSetNode[E
]
431 init(set
: HashSet[E
])
434 _node
= set
._first_item