001: /*
002: * Primitive Collections for Java.
003: * Copyright (C) 2002, 2003 Søren Bak
004: *
005: * This library is free software; you can redistribute it and/or
006: * modify it under the terms of the GNU Lesser General Public
007: * License as published by the Free Software Foundation; either
008: * version 2.1 of the License, or (at your option) any later version.
009: *
010: * This library is distributed in the hope that it will be useful,
011: * but WITHOUT ANY WARRANTY; without even the implied warranty of
012: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
013: * Lesser General Public License for more details.
014: *
015: * You should have received a copy of the GNU Lesser General Public
016: * License along with this library; if not, write to the Free Software
017: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
018: */
019: package bak.pcj.adapter;
020:
021: import bak.pcj.Adapter;
022: import bak.pcj.FloatIterator;
023: import bak.pcj.BooleanCollection;
024: import bak.pcj.map.FloatKeyBooleanMap;
025: import bak.pcj.map.AbstractFloatKeyBooleanMap;
026: import bak.pcj.map.FloatKeyBooleanMapIterator;
027: import bak.pcj.map.MapDefaults;
028: import bak.pcj.map.NoSuchMappingException;
029: import bak.pcj.set.FloatSet;
030: import bak.pcj.util.Exceptions;
031:
032: import java.util.Map;
033: import java.util.Iterator;
034:
035: /**
036: * This class represents adaptions of Java Collections Framework
037: * maps to primitive maps from float values to boolean values.
038: * The adapter is implemented as a wrapper around the map.
039: * Thus, changes to the underlying map are reflected by this
040: * map and vice versa.
041: *
042: * <p>
043: * Adapters from JCF maps to primitive map will
044: * fail if the JCF collection contains <tt>null</tt> keys/values or
045: * keys/values of the wrong class. However, adapters are not fast
046: * failing in the case that the underlying map should
047: * contain illegal keys or values. To implement fast failure would require
048: * every operation to check every key and value of the underlying
049: * map before doing anything. Instead validation methods
050: * are provided. They can be called using the assertion facility
051: * in the client code:
052: * <pre>
053: * MapToFloatKeyBooleanMapAdapter s;
054: * ...
055: * <b>assert</b> s.validate();
056: * </pre>
057: * or by letting the adapter throw an exception on illegal values:
058: * <pre>
059: * MapToFloatKeyBooleanMapAdapter s;
060: * ...
061: * s.evalidate(); // Throws an exception on illegal values
062: * </pre>
063: * Either way, validation must be invoked directly by the client
064: * code.
065: *
066: * @author Søren Bak
067: * @version 1.3 21-08-2003 19:09
068: * @since 1.0
069: */
070: public class MapToFloatKeyBooleanMapAdapter extends
071: AbstractFloatKeyBooleanMap implements FloatKeyBooleanMap {
072:
073: /** The underlying map. */
074: protected Map map;
075:
076: /** The value corresponding to the last key found by containsKey(). */
077: protected Boolean lastValue;
078:
079: /**
080: * Creates a new adaption to a map from float
081: * values to boolean values.
082: *
083: * @param map
084: * the underlying map. This map must
085: * consist of keys of class
086: * {@link Float Float}.
087: * values of class
088: * {@link Boolean Boolean}. Otherwise a
089: * {@link ClassCastException ClassCastException}
090: * will be thrown by some methods.
091: *
092: * @throws NullPointerException
093: * if <tt>map</tt> is <tt>null</tt>.
094: */
095: public MapToFloatKeyBooleanMapAdapter(Map map) {
096: if (map == null)
097: Exceptions.nullArgument("map");
098: this .map = map;
099: lastValue = null;
100: }
101:
102: /**
103: * Creates a new adaption to a map from float
104: * values to boolean values. The map to adapt is optionally validated.
105: *
106: * @param map
107: * the underlying map. This map must
108: * consist of keys of class
109: * {@link Float Float}.
110: * values of class
111: * {@link Boolean Boolean}. Otherwise a
112: * {@link ClassCastException ClassCastException}
113: * will be thrown by some methods.
114: *
115: * @param validate
116: * indicates whether <tt>map</tt> should
117: * be checked for illegal values.
118: *
119: * @throws NullPointerException
120: * if <tt>map</tt> is <tt>null</tt>.
121: *
122: * @throws IllegalStateException
123: * if <tt>validate</tt> is <tt>true</tt> and
124: * <tt>map</tt> contains a <tt>null</tt> key/value,
125: * a key that is not of class
126: * {@link Float Float},
127: * or a value that is not of class
128: * {@link Boolean Boolean}.
129: */
130: public MapToFloatKeyBooleanMapAdapter(Map map, boolean validate) {
131: if (map == null)
132: Exceptions.nullArgument("map");
133: this .map = map;
134: lastValue = null;
135: if (validate)
136: evalidate();
137: }
138:
139: public void clear() {
140: map.clear();
141: }
142:
143: public boolean containsKey(float key) {
144: lastValue = (Boolean) map.get(new Float(key));
145: return lastValue != null;
146: }
147:
148: public boolean containsValue(boolean value) {
149: return map.containsValue(new Boolean(value));
150: }
151:
152: public FloatKeyBooleanMapIterator entries() {
153: return new FloatKeyBooleanMapIterator() {
154: Iterator i = map.entrySet().iterator();
155: Map.Entry lastEntry = null;
156:
157: public boolean hasNext() {
158: return i.hasNext();
159: }
160:
161: public void next() {
162: lastEntry = (Map.Entry) i.next();
163: }
164:
165: public float getKey() {
166: if (lastEntry == null)
167: Exceptions.noElementToGet();
168: return ((Float) lastEntry.getKey()).floatValue();
169: }
170:
171: public boolean getValue() {
172: if (lastEntry == null)
173: Exceptions.noElementToGet();
174: return ((Boolean) lastEntry.getValue()).booleanValue();
175: }
176:
177: public void remove() {
178: i.remove();
179: lastEntry = null;
180: }
181: };
182: }
183:
184: public boolean get(float key) {
185: Boolean value = (Boolean) map.get(new Float(key));
186: return value == null ? MapDefaults.defaultBoolean() : value
187: .booleanValue();
188: }
189:
190: public FloatSet keySet() {
191: return new SetToFloatSetAdapter(map.keySet());
192: }
193:
194: public boolean lget() {
195: if (lastValue == null)
196: Exceptions.noLastElement();
197: return lastValue.booleanValue();
198: }
199:
200: public boolean put(float key, boolean value) {
201: Boolean oldValue = (Boolean) map.put(new Float(key),
202: new Boolean(value));
203: return oldValue == null ? MapDefaults.defaultBoolean()
204: : oldValue.booleanValue();
205: }
206:
207: public boolean remove(float key) {
208: Boolean value = (Boolean) map.remove(new Float(key));
209: return value == null ? MapDefaults.defaultBoolean() : value
210: .booleanValue();
211: }
212:
213: public int size() {
214: return map.size();
215: }
216:
217: public BooleanCollection values() {
218: return new CollectionToBooleanCollectionAdapter(map.values());
219: }
220:
221: public boolean tget(float key) {
222: Boolean value = (Boolean) map.get(new Float(key));
223: if (value == null)
224: Exceptions.noSuchMapping(String.valueOf(key));
225: return value.booleanValue();
226: }
227:
228: /**
229: * Indicates whether the underlying map is valid for
230: * this adapter. For the underlying map to be valid, it
231: * can only contain {@link Float Float} keys, no <tt>null</tt>
232: * keys/values, and only {@link Boolean Boolean} values.
233: *
234: * @return <tt>true</tt> if the underlying map is
235: * valid; returns <tt>false</tt> otherwise.
236: */
237: public boolean validate() {
238: return Adapter.isFloatKeyBooleanAdaptable(map);
239: }
240:
241: /**
242: * Validates the map underlying this adapter and throws
243: * an exception if it is invalid. For the underlying map
244: * to be valid, it
245: * can only contain {@link Float Float} keys, no <tt>null</tt>
246: * keys/values, and only {@link Boolean Boolean} values.
247: *
248: * @throws IllegalStateException
249: * if the underlying map is invalid.
250: */
251: public void evalidate() {
252: if (!validate())
253: Exceptions.cannotAdapt("map");
254: }
255:
256: }
|