/* * Scriptographer * * This file is part of Scriptographer, a Scripting Plugin for Adobe Illustrator * http://scriptographer.org/ * * Copyright (c) 2002-2010, Juerg Lehni * http://scratchdisk.com/ * * All rights reserved. See LICENSE file for details. * * File created on Jun 13, 2007. */ package com.scratchdisk.util; import java.util.AbstractSet; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.Map; import java.util.Set; /** * AbstractMap is the base for wrapping native objects in a * Map interface. * * This helps easily implementing entrySet() / keySet() * * @author lehni */ public abstract class AbstractMap<K,V> implements Map<K,V> { /** * This method needs to be defined by extending classes. * It returns all the map-like object's keys in an array. */ protected abstract K[] keys(); public int size() { return keys().length; } public boolean isEmpty() { return size() == 0; } public void clear() { Object[] keys = keys(); for (int i = 0; i < keys.length; i++) remove(keys[i]); } public Collection<V> values() { // Just create an ArrayList containing the values Object[] ids = keys(); ArrayList<V> values = new ArrayList<V>(); for (int i = 0; i < ids.length; i++) { values.add(get(ids[i])); } return values; } public boolean containsKey(Object key) { Object[] keys = keys(); // Search for it the slow way... for (int i = 0; i < keys.length; i++) { if (get(keys[i]).equals(key)) return true; } return false; } public boolean containsValue(Object value) { Object[] keys = keys(); // Search for it the slow way... for (int i = 0; i < keys.length; i++) { Object obj = get(keys[i]); if (value == obj || value != null && value.equals(obj)) return true; } return false; } public void putAll(Map<? extends K, ? extends V> map) { for (Map.Entry<? extends K, ? extends V> entry : map.entrySet()) put(entry.getKey(), entry.getValue()); } public Set<Map.Entry<K, V>> entrySet() { return new MapSet<Map.Entry<K, V>>(true); } public Set<K> keySet() { return new MapSet<K>(false); } private class Entry implements Map.Entry<K,V> { private K key; Entry(K key) { this.key = key; } public K getKey() { return key; } public V getValue() { return AbstractMap.this.get(key); } public V setValue(V value) { return AbstractMap.this.put(key, value); } } private class MapSet<E> extends AbstractSet<E> { K[] keys; boolean entries; MapSet(boolean entries) { this.keys = AbstractMap.this.keys(); this.entries = entries; } public Iterator<E> iterator() { return new Iterator<E>() { int index = 0; public boolean hasNext() { return index < keys.length; } @SuppressWarnings("unchecked") public E next() { K key = keys[index++]; return (E) (entries ? new Entry(key) : key); } public void remove() { // TODO: is incrementing correct here? AbstractMap.this.remove(keys[index++]); } }; } public int size() { return keys.length; } } }