/gee/gee/hashset.vala

http://libgdom3.googlecode.com/ · Vala · 205 lines · 146 code · 31 blank · 28 comment · 28 complexity · 1da1e22e8e51a1b4edd0ee7b8af7daa8 MD5 · raw file

  1. /* hashset.vala
  2. *
  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
  6. *
  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.
  11. * This library is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. * You should have received a copy of the GNU Lesser General Public
  16. * License along with this library; if not, write to the Free Software
  17. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  18. *
  19. * Author:
  20. * J?rg Billeter <j@bitron.ch>
  21. */
  22. using GLib;
  23. /**
  24. * Hashtable implementation of the Set interface.
  25. */
  26. public class Gee.HashSet<G> : Object, Iterable<G>, Collection<G>, Set<G> {
  27. public int size {
  28. get { return _nnodes; }
  29. }
  30. public HashFunc hash_func {
  31. set { _hash_func = value; }
  32. }
  33. public EqualFunc equal_func {
  34. set { _equal_func = value; }
  35. }
  36. private int _array_size;
  37. private int _nnodes;
  38. private Node<G>[] _nodes;
  39. // concurrent modification protection
  40. private int _stamp = 0;
  41. private HashFunc _hash_func;
  42. private EqualFunc _equal_func;
  43. private const int MIN_SIZE = 11;
  44. private const int MAX_SIZE = 13845163;
  45. public HashSet (HashFunc hash_func = GLib.direct_hash, EqualFunc equal_func = GLib.direct_equal) {
  46. this.hash_func = hash_func;
  47. this.equal_func = equal_func;
  48. }
  49. construct {
  50. _array_size = MIN_SIZE;
  51. _nodes = new Node<G>[_array_size];
  52. }
  53. private Node<G>** lookup_node (G key) {
  54. uint hash_value = _hash_func (key);
  55. Node<G>** node = &_nodes[hash_value % _array_size];
  56. while ((*node) != null && (hash_value != (*node)->key_hash || !_equal_func ((*node)->key, key))) {
  57. node = &((*node)->next);
  58. }
  59. return node;
  60. }
  61. public bool contains (G key) {
  62. Node<G>** node = lookup_node (key);
  63. return (*node != null);
  64. }
  65. public Type get_element_type () {
  66. return typeof (G);
  67. }
  68. public Gee.Iterator<G> iterator () {
  69. return new Iterator<G> (this);
  70. }
  71. public bool add (G key) {
  72. Node<G>** node = lookup_node (key);
  73. if (*node != null) {
  74. return false;
  75. } else {
  76. uint hash_value = _hash_func (key);
  77. *node = new Node<G> (key, hash_value);
  78. _nnodes++;
  79. resize ();
  80. _stamp++;
  81. return true;
  82. }
  83. }
  84. public bool remove (G key) {
  85. Node<G>** node = lookup_node (key);
  86. if (*node != null) {
  87. (*node)->key = null;
  88. *node = (*node)->next;
  89. _nnodes--;
  90. resize ();
  91. _stamp++;
  92. return true;
  93. }
  94. return false;
  95. }
  96. public void clear () {
  97. for (int i = 0; i < _array_size; i++) {
  98. Node<G> node = #_nodes[i];
  99. while (node != null) {
  100. Node next = #node.next;
  101. node.key = null;
  102. node = #next;
  103. }
  104. }
  105. _nnodes = 0;
  106. resize ();
  107. }
  108. private void resize () {
  109. if ((_array_size >= 3 * _nnodes && _array_size >= MIN_SIZE) ||
  110. (3 * _array_size <= _nnodes && _array_size < MAX_SIZE)) {
  111. int new_array_size = (int) SpacedPrimes.closest (_nnodes);
  112. new_array_size = new_array_size.clamp (MIN_SIZE, MAX_SIZE);
  113. Node<G>[] new_nodes = new Node<G>[new_array_size];
  114. for (int i = 0; i < _array_size; i++) {
  115. Node<G> node;
  116. Node<G> next;
  117. for (node = #_nodes[i]; node != null; node = #next) {
  118. next = #node.next;
  119. uint hash_val = node.key_hash % new_array_size;
  120. node.next = #new_nodes[hash_val];
  121. new_nodes[hash_val] = #node;
  122. }
  123. }
  124. _nodes = #new_nodes;
  125. _array_size = new_array_size;
  126. }
  127. }
  128. ~HashSet () {
  129. clear ();
  130. }
  131. [Compact]
  132. private class Node<G> {
  133. public G key;
  134. public Node<G> next;
  135. public uint key_hash;
  136. public Node (G# k, uint hash) {
  137. key = #k;
  138. key_hash = hash;
  139. }
  140. }
  141. private class Iterator<G> : Object, Gee.Iterator<G> {
  142. public HashSet<G> set {
  143. set {
  144. _set = value;
  145. _stamp = _set._stamp;
  146. }
  147. }
  148. private HashSet<G> _set;
  149. private int _index = -1;
  150. private weak Node<G> _node;
  151. // concurrent modification protection
  152. private int _stamp = 0;
  153. public Iterator (HashSet set) {
  154. this.set = set;
  155. }
  156. public bool next () {
  157. if (_node != null) {
  158. _node = _node.next;
  159. }
  160. while (_node == null && _index + 1 < _set._array_size) {
  161. _index++;
  162. _node = _set._nodes[_index];
  163. }
  164. return (_node != null);
  165. }
  166. public weak G? get () {
  167. assert (_stamp == _set._stamp);
  168. assert (_node != null);
  169. return _node.key;
  170. }
  171. }
  172. }