/* abstractmultimap.vala * * Copyright (C) 2009 Ali Sabil * * 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: * Ali Sabil * Didier 'Ptitjes Villevalois */ /** * Skeletal implementation of the {@link MultiMap} interface. * * @see HashMultiMap * @see TreeMultiMap */ public abstract class Gee.AbstractMultiMap : Object, MultiMap { public int size { get { return _nitems; } } public bool read_only { get { return false; } } protected Map> _storage_map; private int _nitems = 0; public AbstractMultiMap (Map> storage_map) { this._storage_map = storage_map; } public Set get_keys () { return _storage_map.keys; } public MultiSet get_all_keys () { return new AllKeys (this); } public Collection get_values () { return new Values (this); } public bool contains (K key) { return _storage_map.has_key (key); } public new Collection get (K key) { Collection? col = _storage_map.get (key); return col != null ? col.read_only_view : Set.empty (); } public new void set (K key, V value) { if (_storage_map.has_key (key)) { if (_storage_map.get (key).add (value)) { _nitems++; } } else { var s = create_value_storage (); s.add (value); _storage_map.set (key, s); _nitems++; } } public bool remove (K key, V value) { if (_storage_map.has_key (key)) { var values = _storage_map.get (key); if (values.contains (value)) { values.remove (value); _nitems--; if (values.size == 0) { _storage_map.unset (key); } return true; } } return false; } public bool remove_all (K key) { if (_storage_map.has_key (key)) { int size = _storage_map.get (key).size; if (_storage_map.unset (key)) { _nitems -= size; return true; } } return false; } public void clear () { _storage_map.clear (); _nitems = 0; } public Gee.MapIterator map_iterator () { return new MapIterator (_storage_map.map_iterator ()); } protected abstract Collection create_value_storage (); protected abstract MultiSet create_multi_key_set (); protected abstract EqualDataFunc get_value_equal_func (); private class AllKeys : AbstractCollection, MultiSet { protected AbstractMultiMap _multi_map; public AllKeys (AbstractMultiMap multi_map) { _multi_map = multi_map; } public override Gee.Iterator iterator () { return new KeyIterator (_multi_map._storage_map.map_iterator ()); } public override int size { get { return _multi_map.size; } } public override bool read_only { get { return true; } } public override bool contains (K key) { return _multi_map._storage_map.has_key (key); } public override bool add (K key) { assert_not_reached (); } public override bool remove (K item) { assert_not_reached (); } public override void clear () { assert_not_reached (); } public int count (K item) { Collection? collection = _multi_map._storage_map.get (item); return collection != null ? collection.size : 0; } } private class Values : AbstractCollection { protected AbstractMultiMap _multi_map; public Values (AbstractMultiMap multi_map) { _multi_map = multi_map; } public override Gee.Iterator iterator () { return new ValueIterator (_multi_map._storage_map.map_iterator ()); } public override int size { get { return _multi_map.size; } } public override bool read_only { get { return true; } } public override bool contains (V value) { foreach (var col in _multi_map._storage_map.values) { if (col.contains (value)) { return true; } } return false; } public override bool add (K key) { assert_not_reached (); } public override bool remove (K item) { assert_not_reached (); } public override void clear () { assert_not_reached (); } } private class MappingIterator : Object { protected Gee.MapIterator> outer; protected Iterator? inner = null; public MappingIterator (Gee.MapIterator>? outer) { this.outer = outer; } public bool next () { if (inner != null && inner.next ()) { return true; } else if (outer.next ()) { inner = outer.get_value ().iterator (); assert (inner.next ()); return true; } else { return false; } } public bool has_next () { return inner.has_next () || outer.has_next (); } public void remove () { assert_not_reached (); } public virtual bool read_only { get { return true; } } public void unset () { inner.remove (); if (outer.get_value ().is_empty) { outer.unset (); } } public bool valid { get { return inner != null && inner.valid; } } } private class KeyIterator : MappingIterator, Traversable, Iterator { public KeyIterator (Gee.MapIterator>? outer) { base (outer); } public new K get () { assert (valid); return outer.get_key (); } public bool foreach (ForallFunc f) { if (inner != null && outer.valid) { K key = outer.get_key (); if (!inner.foreach ((v) => {return f (key);})) { return false; } outer.next (); } return outer.foreach ((key, col) => { return col.foreach ((v) => {return f (key);}); }); } } private class ValueIterator : MappingIterator, Traversable, Iterator { public ValueIterator (Gee.MapIterator>? outer) { base (outer); } public new V get () { assert (valid); return inner.get (); } public bool foreach (ForallFunc f) { if (inner != null && outer.valid) { if (!inner.foreach (f)) { return false; } outer.next (); } return outer.foreach ((key, col) => { return col.foreach (f); }); } } private class MapIterator : MappingIterator, Gee.MapIterator { public MapIterator (Gee.MapIterator>? outer) { base (outer); } public K get_key () { assert (valid); return outer.get_key (); } public V get_value () { assert (valid); return inner.get (); } public void set_value (V value) { assert_not_reached (); } public bool mutable { get { return false; } } } private weak MultiMap _read_only_view; public virtual new MultiMap read_only_view { owned get { MultiMap instance = _read_only_view; if (_read_only_view == null) { instance = new ReadOnlyMultiMap (this); _read_only_view = instance; instance.add_weak_pointer ((void**) (&_read_only_view)); } return instance; } } // Future-proofing internal new virtual void reserved0() {} internal new virtual void reserved1() {} internal new virtual void reserved2() {} internal new virtual void reserved3() {} internal new virtual void reserved4() {} internal new virtual void reserved5() {} internal new virtual void reserved6() {} internal new virtual void reserved7() {} internal new virtual void reserved8() {} }