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-2009 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 Set interface.
30 public class Gee
.HashSet
<G
> : CollectionObject
, Iterable
<G
>, Collection
<G
>, Set
<G
> {
32 get { return _nnodes
; }
35 public HashFunc hash_func
{
36 set { _hash_func
= value
; }
39 public EqualFunc equal_func
{
40 set { _equal_func
= value
; }
43 private int _array_size
;
45 private Node
<G
>[] _nodes
;
47 // concurrent modification protection
48 private int _stamp
= 0;
50 private HashFunc _hash_func
;
51 private EqualFunc _equal_func
;
53 private const int MIN_SIZE
= 11;
54 private const int MAX_SIZE
= 13845163;
56 public HashSet (HashFunc hash_func
= GLib
.direct_hash
, EqualFunc equal_func
= GLib
.direct_equal
) {
57 this
.hash_func
= hash_func
;
58 this
.equal_func
= equal_func
;
59 _array_size
= MIN_SIZE
;
60 _nodes
= new Node
<G
>[_array_size
];
63 private Node
<G
>** lookup_node (G key
) {
64 uint hash_value
= _hash_func (key
);
65 Node
<G
>** node
= &_nodes
[hash_value
% _array_size
];
66 while ((*node
) != null && (hash_value
!= (*node
)->key_hash
|| !_equal_func ((*node
)->key
, key
))) {
67 node
= &((*node
)->next
);
72 public bool contains (G key
) {
73 Node
<G
>** node
= lookup_node (key
);
74 return (*node
!= null);
77 public Type
get_element_type () {
81 public Gee
.Iterator
<G
> iterator () {
82 return new Iterator
<G
> (this
);
85 public bool add (G key
) {
86 Node
<G
>** node
= lookup_node (key
);
90 uint hash_value
= _hash_func (key
);
91 *node
= new Node
<G
> (key
, hash_value
);
99 public bool remove (G key
) {
100 Node
<G
>** node
= lookup_node (key
);
102 Node
<G
> next
= (owned
) (*node
)->next
;
107 *node
= (owned
) next
;
117 public void clear () {
118 for (int i
= 0; i
< _array_size
; i
++) {
119 Node
<G
> node
= (owned
) _nodes
[i
];
120 while (node
!= null) {
121 Node next
= (owned
) node
.next
;
130 private void resize () {
131 if ((_array_size
>= 3 * _nnodes
&& _array_size
>= MIN_SIZE
) ||
132 (3 * _array_size
<= _nnodes
&& _array_size
< MAX_SIZE
)) {
133 int new_array_size
= (int) SpacedPrimes
.closest (_nnodes
);
134 new_array_size
= new_array_size
.clamp (MIN_SIZE
, MAX_SIZE
);
136 Node
<G
>[] new_nodes
= new Node
<G
>[new_array_size
];
138 for (int i
= 0; i
< _array_size
; i
++) {
141 for (node
= (owned
) _nodes
[i
]; node
!= null; node
= (owned
) next
) {
142 next
= (owned
) node
.next
;
143 uint hash_val
= node
.key_hash
% new_array_size
;
144 node
.next
= (owned
) new_nodes
[hash_val
];
145 new_nodes
[hash_val
] = (owned
) node
;
148 _nodes
= (owned
) new_nodes
;
149 _array_size
= new_array_size
;
158 private class Node
<G
> {
161 public uint key_hash
;
163 public Node (owned G k
, uint hash
) {
169 private class Iterator
<G
> : CollectionObject
, Gee
.Iterator
<G
> {
170 public HashSet
<G
> set {
173 _stamp
= _set
._stamp
;
177 private HashSet
<G
> _set
;
178 private int _index
= -1;
179 private weak Node
<G
> _node
;
181 // concurrent modification protection
182 private int _stamp
= 0;
184 public Iterator (HashSet
set) {
188 public bool next () {
192 while (_node
== null && _index
+ 1 < _set
._array_size
) {
194 _node
= _set
._nodes
[_index
];
196 return (_node
!= null);
200 assert (_stamp
== _set
._stamp
);
201 assert (_node
!= null);