Chris@2: /* Chris@2: Copyright (C) 2001, 2006 by Simon Dixon Chris@2: Chris@2: This program is free software; you can redistribute it and/or modify Chris@2: it under the terms of the GNU General Public License as published by Chris@2: the Free Software Foundation; either version 2 of the License, or Chris@2: (at your option) any later version. Chris@2: Chris@2: This program is distributed in the hope that it will be useful, Chris@2: but WITHOUT ANY WARRANTY; without even the implied warranty of Chris@2: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the Chris@2: GNU General Public License for more details. Chris@2: Chris@2: You should have received a copy of the GNU General Public License along Chris@2: with this program (the file gpl.txt); if not, download it from Chris@2: http://www.gnu.org/licenses/gpl.txt or write to the Chris@2: Free Software Foundation, Inc., Chris@2: 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Chris@2: */ Chris@2: Chris@2: package at.ofai.music.util; Chris@2: Chris@2: import java.util.ArrayList; Chris@2: import java.util.Collection; Chris@2: import java.util.Map; Chris@2: import java.util.Set; Chris@2: import java.util.TreeSet; Chris@2: Chris@2: // An implementation of the Map interface, backed by an ArrayList, which Chris@2: // preserves the elements in the order that they are added to the map. Chris@2: // Operations will take linear rather than constant time (as for the efficient Chris@2: // implementations of Map). Operations are not synchronized; caveat programmer! Chris@2: // Used by class Parameters Chris@2: // Updated to use generics; demonstrates that generics do not necessarily make Chris@2: // programs more readable, simple, safe, etc. Chris@2: class ArrayMap implements Map { Chris@2: Chris@2: protected ArrayList entries; Chris@2: Chris@2: protected class Entry implements Map.Entry, Chris@2: Comparable { Chris@2: protected String key; Chris@2: protected Object value; Chris@2: protected Entry(String k, Object v) { Chris@2: key = k; Chris@2: value = v; Chris@2: } // constructor Chris@2: public boolean equals(Object o) { Chris@2: return (o instanceof Entry) && key.equals(((Entry)o).key) && Chris@2: value.equals(((Entry)o).value); Chris@2: } // equals() Chris@2: public String getKey() { return key; } Chris@2: public Object getValue() { return value; } Chris@2: public Object setValue(Object newValue) { Chris@2: Object oldValue = value; Chris@2: value = newValue; Chris@2: return oldValue; Chris@2: } // setValue() Chris@2: public int hashCode() { Chris@2: return (key==null? 0 : key.hashCode()) ^ Chris@2: (value==null? 0 : value.hashCode()); Chris@2: } // hashCode() Chris@2: public int compareTo(Object o) { Chris@2: return key.compareTo(((Entry)o).key); Chris@2: } // compareTo() Chris@2: } // inner class Entry Chris@2: Chris@2: public ArrayMap() { entries = new ArrayList(); }//default constructor Chris@2: public ArrayMap(Map m) { this(); putAll(m); } // copy constructor Chris@2: Chris@2: // Returns the index of an entry, given its key, or -1 if it is not in map. Chris@2: // Note that ArrayList.indexOf() can't be used, because it doesn't call Chris@2: // ArrayMap$Entry.equals() [bug?? or does it call key.equals(entry)??] Chris@2: public int indexOf(String key) { Chris@2: for (int i = 0; i < size(); i++) Chris@2: if (key.equals(entries.get(i).key)) Chris@2: return i; Chris@2: return -1; Chris@2: } // indexOf() Chris@2: Chris@2: // Returns the map entry at the given index Chris@2: public Entry getEntry(int i) { return entries.get(i); } Chris@2: Chris@2: // Removes all mappings from this map (optional operation). Chris@2: public void clear() { entries.clear(); } Chris@2: Chris@2: // Returns true if this map contains a mapping for the specified key. Chris@2: public boolean containsKey(Object key) { Chris@2: return indexOf((String)key) >= 0; Chris@2: } // containsKey() Chris@2: Chris@2: // Returns true if this map maps one or more keys to the specified value. Chris@2: public boolean containsValue(Object value) { Chris@2: for (int i = 0; i < size(); i++) Chris@2: if (value.equals(entries.get(i).value)) Chris@2: return true; Chris@2: return false; Chris@2: } // containsValue() Chris@2: Chris@2: // Returns a set view of the mappings contained in this map. Chris@2: public Set> entrySet() { Chris@2: TreeSet> s = Chris@2: new TreeSet>(); Chris@2: for (int i = 0; i < size(); i++) Chris@2: s.add(entries.get(i)); Chris@2: return s; Chris@2: } // entrySet() Chris@2: Chris@2: // Compares the specified object with this map for equality. Chris@2: public boolean equals(Object o) { return (o == this); } Chris@2: Chris@2: // Returns the value to which this map maps the specified key. Chris@2: public Object get(Object key) { Chris@2: int i = indexOf((String)key); Chris@2: if (i == -1) Chris@2: return null; Chris@2: return entries.get(i).value; Chris@2: } // get() Chris@2: Chris@2: // Returns the hash code value for this map. Chris@2: public int hashCode() { Chris@2: int h = 0; Chris@2: for (int i = 0; i < size(); i++) Chris@2: h ^= entries.get(i).hashCode(); Chris@2: return h; Chris@2: } // hashCode() Chris@2: Chris@2: // Returns true if this map contains no key-value mappings. Chris@2: public boolean isEmpty() { return entries.isEmpty(); } Chris@2: Chris@2: // Returns a set view of the keys contained in this map. Chris@2: public Set keySet() { Chris@2: TreeSet s = new TreeSet(); Chris@2: for (int i = 0; i < size(); i++) Chris@2: s.add(entries.get(i).key); Chris@2: return s; Chris@2: } // keySet() Chris@2: Chris@2: // Associates the specified value with the specified key in this map Chris@2: public Object put(String key, Object value) { Chris@2: int i = indexOf(key); Chris@2: if (i < 0) { Chris@2: entries.add(new Entry(key, value)); Chris@2: return null; Chris@2: } else Chris@2: return entries.get(i).setValue(value); Chris@2: } // put() Chris@2: Chris@2: // Copies all of the mappings from the specified map to this map Chris@2: public void putAll(Map m) { Chris@2: // The following warning seems to be unavoidable: Chris@2: // warning: [unchecked] unchecked conversion Chris@2: Map m1 = (Map)m; Chris@2: for (Map.Entry me : m1.entrySet()) { Chris@2: put(me.getKey(), me.getValue()); Chris@2: } Chris@2: } // putAll() Chris@2: Chris@2: // Removes the mapping for this key from this map if present Chris@2: public Object remove(Object key) { Chris@2: int i = indexOf((String)key); Chris@2: if (i < 0) Chris@2: return null; Chris@2: return entries.remove(i); Chris@2: } // remove() Chris@2: Chris@2: // Returns the number of key-value mappings in this map. Chris@2: public int size() { return entries.size(); } Chris@2: Chris@2: // Returns a collection view of the values contained in this map. Chris@2: public Collection values() { Chris@2: ArrayList s = new ArrayList(); Chris@2: for (int i = 0; i < size(); i++) Chris@2: s.add(entries.get(i).value); Chris@2: return s; Chris@2: } // values() Chris@2: Chris@2: } // class ArrayMap