/* hashmap.vala * * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald * Copyright (C) 1997-2000 GLib Team and others * Copyright (C) 2007-2009 Jürg Billeter * Copyright (C) 2009-2014 Maciej Piechotka * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * * Author: * Jürg Billeter */ using GLib; /** * Hash table implementation of the {@link Map} interface. * * This implementation is better fit for highly heterogenous key values. * In case of high key hashes redundancy or higher amount of data prefer using * tree implementation like {@link TreeMap}. * * @see TreeMap */ public class Vala.HashMap : Vala.AbstractMap { /** * {@inheritDoc} */ public override int size { get { return _nnodes; } } /** * {@inheritDoc} */ public override bool read_only { get { return false; } } /** * {@inheritDoc} */ public override Set keys { owned get { Set keys = _keys; if (_keys == null) { keys = new KeySet (this); _keys = keys; keys.add_weak_pointer ((void**) (&_keys)); } return keys; } } /** * {@inheritDoc} */ public override Collection values { owned get { Collection values = _values; if (_values == null) { values = new ValueCollection (this); _values = values; values.add_weak_pointer ((void**) (&_values)); } return values; } } /** * {@inheritDoc} */ public override Set> entries { owned get { Set> entries = _entries; if (_entries == null) { entries = new EntrySet (this); _entries = entries; entries.add_weak_pointer ((void**) (&_entries)); } return entries; } } /** * The keys' hash function. */ [CCode (notify = false)] public HashDataFunc key_hash_func { private set {} get { return _key_hash_func.func; } } /** * The keys' equality testing function. */ [CCode (notify = false)] public EqualDataFunc key_equal_func { private set {} get { return _key_equal_func.func; } } /** * The values' equality testing function. */ [CCode (notify = false)] public EqualDataFunc value_equal_func { private set {} get { return _value_equal_func.func; } } private int _array_size; private int _nnodes; private Node[] _nodes; private Functions.HashDataFuncClosure _key_hash_func; private Functions.EqualDataFuncClosure _key_equal_func; private Functions.EqualDataFuncClosure _value_equal_func; private weak Set _keys; private weak Collection _values; private weak Set> _entries; // concurrent modification protection private int _stamp = 0; private const int MIN_SIZE = 11; private const int MAX_SIZE = 13845163; /** * Constructs a new, empty hash map. * * If not provided, the functions parameters are requested to the * {@link Functions} function factory methods. * * @param key_hash_func an optional key hash function * @param key_equal_func an optional key equality testing function * @param value_equal_func an optional value equality testing function */ public HashMap (owned HashDataFunc? key_hash_func = null, owned EqualDataFunc? key_equal_func = null, owned EqualDataFunc? value_equal_func = null) { if (key_hash_func == null) { key_hash_func = Functions.get_hash_func_for (typeof (K)); } if (key_equal_func == null) { key_equal_func = Functions.get_equal_func_for (typeof (K)); } if (value_equal_func == null) { value_equal_func = Functions.get_equal_func_for (typeof (V)); } _key_hash_func = new Functions.HashDataFuncClosure ((owned)key_hash_func); _key_equal_func = new Functions.EqualDataFuncClosure ((owned)key_equal_func); _value_equal_func = new Functions.EqualDataFuncClosure ((owned)value_equal_func); _array_size = MIN_SIZE; _nodes = new Node[_array_size]; } internal HashMap.with_closures (owned Functions.HashDataFuncClosure key_hash_func, owned Functions.EqualDataFuncClosure key_equal_func, owned Functions.EqualDataFuncClosure value_equal_func) { _key_hash_func = key_hash_func; _key_equal_func = key_equal_func; _value_equal_func = value_equal_func; _array_size = MIN_SIZE; _nodes = new Node[_array_size]; } private Node** lookup_node (K key) { uint hash_value = key_hash_func (key); Node** node = &_nodes[hash_value % _array_size]; while ((*node) != null && (hash_value != (*node)->key_hash || !key_equal_func ((*node)->key, key))) { node = &((*node)->next); } return node; } /** * {@inheritDoc} */ public override bool has_key (K key) { Node** node = lookup_node (key); return (*node != null); } /** * {@inheritDoc} */ public override bool has (K key, V value) { Node** node = lookup_node (key); return (*node != null && value_equal_func ((*node)->value, value)); } /** * {@inheritDoc} */ public override V? get (K key) { Node* node = (*lookup_node (key)); if (node != null) { return node->value; } else { return null; } } /** * {@inheritDoc} */ public override void set (K key, V value) { Node** node = lookup_node (key); if (*node != null) { (*node)->value = value; } else { uint hash_value = key_hash_func (key); *node = new Node (key, value, hash_value); _nnodes++; resize (); } _stamp++; } /** * {@inheritDoc} */ public override bool unset (K key, out V? value = null) { bool b = unset_helper (key, out value); if(b) { resize(); } return b; } /** * {@inheritDoc} */ public override void clear () { for (int i = 0; i < _array_size; i++) { Node node = (owned) _nodes[i]; while (node != null) { Node next = (owned) node.next; node.key = null; node.value = null; node = (owned) next; } } _nnodes = 0; resize (); } /** * {@inheritDoc} */ public override Vala.MapIterator map_iterator () { return new MapIterator (this); } internal Functions.HashDataFuncClosure get_key_hash_func_closure () { return _key_hash_func; } internal Functions.EqualDataFuncClosure get_key_equal_func_closure () { return _key_equal_func; } private inline bool unset_helper (K key, out V? value = null) { Node** node = lookup_node (key); if (*node != null) { Node next = (owned) (*node)->next; value = (owned) (*node)->value; (*node)->key = null; (*node)->value = null; delete *node; *node = (owned) next; _nnodes--; _stamp++; return true; } else { value = null; } return false; } private inline void resize () { if ((_array_size >= 3 * _nnodes && _array_size >= MIN_SIZE) || (3 * _array_size <= _nnodes && _array_size < MAX_SIZE)) { int new_array_size = (int) SpacedPrimes.closest (_nnodes); new_array_size = new_array_size.clamp (MIN_SIZE, MAX_SIZE); Node[] new_nodes = new Node[new_array_size]; for (int i = 0; i < _array_size; i++) { Node node; Node next = null; for (node = (owned) _nodes[i]; node != null; node = (owned) next) { next = (owned) node.next; uint hash_val = node.key_hash % new_array_size; node.next = (owned) new_nodes[hash_val]; new_nodes[hash_val] = (owned) node; } } _nodes = (owned) new_nodes; _array_size = new_array_size; } } ~HashMap () { clear (); } [Compact] private class Node { public K key; public V value; public Node next; public uint key_hash; public unowned Map.Entry? entry; public Node (owned K k, owned V v, uint hash) { key = (owned) k; value = (owned) v; key_hash = hash; entry = null; } ~Node () { if (entry != null) { entry.remove_weak_pointer ((void**) (&entry)); } } } private class Entry : Map.Entry { private unowned Node _node; public static Map.Entry entry_for (Node node) { Map.Entry result = node.entry; if (node.entry == null) { result = new Entry (node); node.entry = result; result.add_weak_pointer ((void**) (&node.entry)); } return result; } public Entry (Node node) { _node = node; } public override K key { get { return _node.key; } } public override V value { get { return _node.value; } set { _node.value = value; } } public override bool read_only { get { return false; } } } private class KeySet : AbstractSet { private HashMap _map; public KeySet (HashMap map) { _map = map; } public override Iterator iterator () { return new KeyIterator (_map); } public override int size { get { return _map.size; } } public override bool read_only { get { return true; } } public override bool add (K key) { assert_not_reached (); } public override void clear () { assert_not_reached (); } public override bool remove (K key) { assert_not_reached (); } public override bool contains (K key) { return _map.has_key (key); } } private class ValueCollection : AbstractCollection { private HashMap _map; public ValueCollection (HashMap map) { _map = map; } public override Iterator iterator () { return new ValueIterator (_map); } public override int size { get { return _map.size; } } public override bool read_only { get { return true; } } public override bool add (V value) { assert_not_reached (); } public override void clear () { assert_not_reached (); } public override bool remove (V value) { assert_not_reached (); } public override bool contains (V value) { Iterator it = iterator (); while (it.next ()) { if (_map.value_equal_func (it.get (), value)) { return true; } } return false; } } private class EntrySet : AbstractSet> { private HashMap _map; public EntrySet (HashMap map) { _map = map; } public override Iterator> iterator () { return new EntryIterator (_map); } public override int size { get { return _map.size; } } public override bool read_only { get { return true; } } public override bool add (Map.Entry entry) { assert_not_reached (); } public override void clear () { assert_not_reached (); } public override bool remove (Map.Entry entry) { assert_not_reached (); } public override bool contains (Map.Entry entry) { return _map.has (entry.key, entry.value); } } private abstract class NodeIterator : Object { public NodeIterator (HashMap map) { _map = map; _stamp = _map._stamp; } public NodeIterator.from_iterator (NodeIterator iter) { _map = iter._map; _index = iter._index; _node = iter._node; _next = iter._next; _stamp = iter._stamp; } public bool next () { assert (_stamp == _map._stamp); if (!has_next ()) { return false; } _node = _next; _next = null; return (_node != null); } public bool has_next () { assert (_stamp == _map._stamp); if (_next == null) { _next = _node; if (_next != null) { _next = _next.next; } while (_next == null && _index + 1 < _map._array_size) { _index++; _next = _map._nodes[_index]; } } return (_next != null); } public virtual bool read_only { get { return true; } } public bool valid { get { return _node != null; } } protected HashMap _map; protected int _index = -1; protected weak Node _node; protected weak Node _next; protected int _stamp; } private class KeyIterator : NodeIterator, Traversable, Iterator { public KeyIterator (HashMap map) { base (map); } public KeyIterator.from_iterator (KeyIterator iter) { base.from_iterator (iter); } public new K get () { assert (_stamp == _map._stamp); assert (_node != null); return _node.key; } public void remove () { assert_not_reached (); } public bool foreach(ForallFunc f) { if (_node != null) { if (!f(_node.key)) { return false; } if(_next == null) { _next = _node.next; } } do { while(_next != null) { _node = _next; if (!f(_node.key)) { return false; } _next = _next.next; } if (_index + 1 < _map._array_size) { _next = _map._nodes[++_index]; } else { return true; } } while(true); } public Vala.Iterator[] tee (uint forks) { if (forks == 0) { return new Vala.Iterator[0]; } else { Vala.Iterator[] result = new Vala.Iterator[forks]; result[0] = this; for (uint i = 1; i < forks; i++) { result[i] = new KeyIterator.from_iterator (this); } return result; } } } private class MapIterator : NodeIterator, Vala.MapIterator { public MapIterator (HashMap map) { base (map); } public new K get_key () { assert (_stamp == _map._stamp); assert (_node != null); return _node.key; } public void unset () { assert (_stamp == _map._stamp); assert (_node != null); has_next (); _map.unset_helper (_node.key); _node = null; _stamp = _map._stamp; } public V get_value () { assert (_stamp == _map._stamp); assert (_node != null); return _node.value; } public void set_value (V value) { assert (_stamp == _map._stamp); assert (_node != null); _map.set (_node.key, value); _stamp = _map._stamp; } public bool mutable { get { return true; } } public override bool read_only { get { return false; } } } private class ValueIterator : NodeIterator, Traversable, Iterator { public ValueIterator (HashMap map) { base (map); } public ValueIterator.from_iterator (ValueIterator iter) { base.from_iterator (iter); } public new V get () { assert (_stamp == _map._stamp); assert (_node != null); return _node.value; } public void remove () { assert_not_reached (); } public bool foreach(ForallFunc f) { if (_node != null) { if (!f(_node.value)) { return false; } if(_next == null) { _next = _node.next; } } do { while(_next != null) { _node = _next; if (!f(_node.value)) { return false; } _next = _next.next; } if (_index + 1 < _map._array_size) { _next = _map._nodes[++_index]; } else { return true; } } while(true); } public Vala.Iterator[] tee (uint forks) { if (forks == 0) { return new Vala.Iterator[0]; } else { Vala.Iterator[] result = new Vala.Iterator[forks]; result[0] = this; for (uint i = 1; i < forks; i++) { result[i] = new ValueIterator.from_iterator (this); } return result; } } } private class EntryIterator : NodeIterator, Traversable>, Iterator> { public EntryIterator (HashMap map) { base (map); } public EntryIterator.from_iterator (EntryIterator iter) { base.from_iterator (iter); } public new Map.Entry get () { assert (_stamp == _map._stamp); assert (_node != null); return Entry.entry_for (_node); } public void remove () { assert_not_reached (); } public bool foreach(ForallFunc> f) { if (_node != null) { if (!f(Entry.entry_for (_node))) { return false; } if(_next == null) { _next = _node.next; } } do { while(_next != null) { _node = _next; if (!f(Entry.entry_for (_node))) { return false; } _next = _next.next; } if (_index + 1 < _map._array_size) { _next = _map._nodes[++_index]; } else { return true; } } while(true); } public Iterator>[] tee (uint forks) { if (forks == 0) { return new Iterator>[0]; } else { Iterator>[] result = new Iterator>[forks]; result[0] = this; for (uint i = 1; i < forks; i++) { result[i] = new EntryIterator.from_iterator (this); } return result; } } } }