3 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
4 * Copyright (C) 1997-2000 GLib Team and others
5 * Copyright (C) 2007-2008 Jürg Billeter
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 * Jürg Billeter <j@bitron.ch>
28 * Hashtable implementation of the Map interface.
30 public class Gee
.HashMap
<K
,V
> : CollectionObject
, Map
<K
,V
> {
32 get { return _nnodes
; }
35 public HashFunc key_hash_func
{
36 set { _key_hash_func
= value
; }
39 public EqualFunc key_equal_func
{
40 set { _key_equal_func
= value
; }
43 public EqualFunc value_equal_func
{
44 set { _value_equal_func
= value
; }
47 private int _array_size
;
49 private Node
<K
,V
>[] _nodes
;
51 // concurrent modification protection
52 private int _stamp
= 0;
54 private HashFunc _key_hash_func
;
55 private EqualFunc _key_equal_func
;
56 private EqualFunc _value_equal_func
;
58 private const int MIN_SIZE
= 11;
59 private const int MAX_SIZE
= 13845163;
61 public HashMap (HashFunc key_hash_func
= GLib
.direct_hash
, EqualFunc key_equal_func
= GLib
.direct_equal
, EqualFunc value_equal_func
= GLib
.direct_equal
) {
62 this
.key_hash_func
= key_hash_func
;
63 this
.key_equal_func
= key_equal_func
;
64 this
.value_equal_func
= value_equal_func
;
65 _array_size
= MIN_SIZE
;
66 _nodes
= new Node
<K
,V
>[_array_size
];
69 public Set
<K
> get_keys () {
70 return new KeySet
<K
,V
> (this
);
73 public Collection
<V
> get_values () {
74 return new ValueCollection
<K
,V
> (this
);
77 private Node
<K
,V
>** lookup_node (K key
) {
78 uint hash_value
= _key_hash_func (key
);
79 Node
<K
,V
>** node
= &_nodes
[hash_value
% _array_size
];
80 while ((*node
) != null && (hash_value
!= (*node
)->key_hash
|| !_key_equal_func ((*node
)->key
, key
))) {
81 node
= &((*node
)->next
);
86 public bool contains (K key
) {
87 Node
<K
,V
>** node
= lookup_node (key
);
88 return (*node
!= null);
91 public V?
get (K key
) {
92 Node
<K
,V
>* node
= (*lookup_node (key
));
100 public void set (K key
, V value
) {
101 Node
<K
,V
>** node
= lookup_node (key
);
103 (*node
)->value
= value
;
105 uint hash_value
= _key_hash_func (key
);
106 *node
= new Node
<K
,V
> (key
, value
, hash_value
);
113 public bool remove (K key
) {
114 Node
<K
,V
>** node
= lookup_node (key
);
117 (*node
)->value
= null;
118 *node
= (*node
)->next
;
127 public void clear () {
128 for (int i
= 0; i
< _array_size
; i
++) {
129 Node
<K
,V
> node
= #_nodes[i];
130 while (node
!= null) {
131 Node next
= #node.next;
141 private void resize () {
142 if ((_array_size
>= 3 * _nnodes
&& _array_size
>= MIN_SIZE
) ||
143 (3 * _array_size
<= _nnodes
&& _array_size
< MAX_SIZE
)) {
144 int new_array_size
= (int) SpacedPrimes
.closest (_nnodes
);
145 new_array_size
= new_array_size
.clamp (MIN_SIZE
, MAX_SIZE
);
147 Node
<K
,V
>[] new_nodes
= new Node
<K
,V
>[new_array_size
];
149 for (int i
= 0; i
< _array_size
; i
++) {
152 for (node
= #_nodes[i]; node != null; node = #next) {
154 uint hash_val
= node
.key_hash
% new_array_size
;
155 node
.next
= #new_nodes[hash_val];
156 new_nodes
[hash_val
] = #node;
160 _array_size
= new_array_size
;
169 private class Node
<K
,V
> {
172 public Node
<K
,V
> next
;
173 public uint key_hash
;
175 public Node (K
# k, V# v, uint hash) {
182 private class KeySet
<K
,V
> : CollectionObject
, Iterable
<K
>, Collection
<K
>, Set
<K
> {
183 public HashMap
<K
,V
> map
{
184 set { _map
= value
; }
187 private HashMap
<K
,V
> _map
;
189 public KeySet (HashMap map
) {
193 public Type
get_element_type () {
197 public Iterator
<K
> iterator () {
198 return new KeyIterator
<K
,V
> (_map
);
202 get { return _map
.size
; }
205 public bool add (K key
) {
206 assert_not_reached ();
209 public void clear () {
210 assert_not_reached ();
213 public bool remove (K key
) {
214 assert_not_reached ();
217 public bool contains (K key
) {
218 return _map
.contains (key
);
222 private class KeyIterator
<K
,V
> : CollectionObject
, Iterator
<K
> {
223 public HashMap
<K
,V
> map
{
226 _stamp
= _map
._stamp
;
230 private HashMap
<K
,V
> _map
;
231 private int _index
= -1;
232 private weak Node
<K
,V
> _node
;
234 // concurrent modification protection
237 public KeyIterator (HashMap map
) {
241 public bool next () {
245 while (_node
== null && _index
+ 1 < _map
._array_size
) {
247 _node
= _map
._nodes
[_index
];
249 return (_node
!= null);
253 assert (_stamp
== _map
._stamp
);
254 assert (_node
!= null);
259 private class ValueCollection
<K
,V
> : CollectionObject
, Iterable
<V
>, Collection
<V
> {
260 public HashMap
<K
,V
> map
{
261 set { _map
= value
; }
264 private HashMap
<K
,V
> _map
;
266 public ValueCollection (HashMap map
) {
270 public Type
get_element_type () {
274 public Iterator
<V
> iterator () {
275 return new ValueIterator
<K
,V
> (_map
);
279 get { return _map
.size
; }
282 public bool add (V value
) {
283 assert_not_reached ();
286 public void clear () {
287 assert_not_reached ();
290 public bool remove (V value
) {
291 assert_not_reached ();
294 public bool contains (V value
) {
295 Iterator
<V
> it
= iterator ();
297 if (_map
._value_equal_func (it
.get (), value
)) {
305 private class ValueIterator
<K
,V
> : CollectionObject
, Iterator
<V
> {
306 public HashMap
<K
,V
> map
{
309 _stamp
= _map
._stamp
;
313 private HashMap
<V
,K
> _map
;
314 private int _index
= -1;
315 private weak Node
<K
,V
> _node
;
317 // concurrent modification protection
320 public ValueIterator (HashMap map
) {
324 public bool next () {
328 while (_node
== null && _index
+ 1 < _map
._array_size
) {
330 _node
= _map
._nodes
[_index
];
332 return (_node
!= null);
336 assert (_stamp
== _map
._stamp
);
337 assert (_node
!= null);