001: /* Copyright (C) 2004 - 2007 db4objects Inc. http://www.db4o.com
002:
003: This file is part of the db4o open source object database.
004:
005: db4o is free software; you can redistribute it and/or modify it under
006: the terms of version 2 of the GNU General Public License as published
007: by the Free Software Foundation and as clarified by db4objects' GPL
008: interpretation policy, available at
009: http://www.db4o.com/about/company/legalpolicies/gplinterpretation/
010: Alternatively you can write to db4objects, Inc., 1900 S Norfolk Street,
011: Suite 350, San Mateo, CA 94403, USA.
012:
013: db4o is distributed in the hope that it will be useful, but WITHOUT ANY
014: WARRANTY; without even the implied warranty of MERCHANTABILITY or
015: FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
016: for more details.
017:
018: You should have received a copy of the GNU General Public License along
019: with this program; if not, write to the Free Software Foundation, Inc.,
020: 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
021: package com.db4o.collections;
022:
023: import java.io.*;
024: import java.util.*;
025:
026: import com.db4o.activation.*;
027: import com.db4o.ta.*;
028:
029: /**
030: * db4o <code>ArrayMap4</code> is an implementation of java.util.Map, which
031: * supports Transparent Activate.
032: *
033: * db4o <code>ArrayMap4</code> uses two separate arrays to store keys and
034: * Values
035: */
036:
037: public class ArrayMap4<K, V> implements Map<K, V>, Serializable,
038: Cloneable, Activatable {
039:
040: private static final long serialVersionUID = 1L;
041:
042: private K[] _keys;
043:
044: private V[] _values;
045:
046: private int _startIndex;
047:
048: private int _endIndex;
049:
050: private transient Activator _activator;
051:
052: public ArrayMap4() {
053: this (16);
054: }
055:
056: public ArrayMap4(int initialCapacity) {
057: initializeBackingArray(initialCapacity);
058: }
059:
060: public void activate() {
061: if (_activator != null) {
062: _activator.activate();
063: }
064: }
065:
066: public void bind(Activator activator) {
067: if (_activator != null || activator == null) {
068: throw new IllegalStateException();
069: }
070: _activator = activator;
071: }
072:
073: public void clear() {
074: activate();
075:
076: _startIndex = 0;
077: _endIndex = 0;
078: Arrays.fill(_keys, null);
079: Arrays.fill(_values, null);
080: }
081:
082: public boolean containsKey(Object key) {
083: activate();
084:
085: return indexOf(_keys, key) != -1;
086: }
087:
088: public boolean containsValue(Object value) {
089: activate();
090:
091: return indexOf(_values, value) != -1;
092: }
093:
094: public Set<Map.Entry<K, V>> entrySet() {
095: activate();
096:
097: HashSet<Map.Entry<K, V>> set = new HashSet<Entry<K, V>>();
098: for (int i = _startIndex; i < _endIndex; i++) {
099: MapEntry4<K, V> entry = new MapEntry4<K, V>(_keys[i],
100: _values[i]);
101: set.add(entry);
102: }
103: return set;
104: }
105:
106: public V get(Object key) {
107: activate();
108:
109: int index = indexOf(_keys, key);
110: return index == -1 ? null : _values[index];
111: }
112:
113: public boolean isEmpty() {
114: activate();
115:
116: return (_endIndex - _startIndex) == 0;
117: }
118:
119: public Set<K> keySet() {
120: activate();
121:
122: HashSet<K> set = new HashSet<K>();
123: for (int i = _startIndex; i < _endIndex; i++) {
124: set.add(_keys[i]);
125: }
126: return set;
127: }
128:
129: public V put(K key, V value) {
130: activate();
131:
132: int index = indexOf(_keys, key);
133: V oldValue = null;
134: if (index == -1) {
135: add(key, value);
136: } else {
137: oldValue = _values[index];
138: _values[index] = value;
139: }
140:
141: return oldValue;
142: }
143:
144: public void putAll(Map<? extends K, ? extends V> t) {
145: for (Map.Entry<? extends K, ? extends V> entry : t.entrySet()) {
146: put(entry.getKey(), entry.getValue());
147: }
148: }
149:
150: @SuppressWarnings("unchecked")
151: public V remove(Object key) {
152: activate();
153:
154: int index = indexOf(_keys, key);
155: if (index == -1) {
156: return null;
157: }
158: return (V) delete(index);
159: }
160:
161: public int size() {
162: activate();
163:
164: return _endIndex - _startIndex;
165: }
166:
167: public Collection<V> values() {
168: activate();
169:
170: ArrayList<V> list = new ArrayList<V>();
171: for (int i = _startIndex; i < _endIndex; i++) {
172: list.add(_values[i]);
173: }
174: return list;
175: }
176:
177: @SuppressWarnings("unchecked")
178: public Object clone() {
179: activate();
180: try {
181: ArrayMap4<K, V> mapClone = (ArrayMap4<K, V>) super .clone();
182: mapClone._keys = _keys.clone();
183: mapClone._values = _values.clone();
184: return mapClone;
185: } catch (CloneNotSupportedException e) {
186: throw new Error(e);
187: }
188: }
189:
190: @SuppressWarnings("unchecked")
191: public boolean equals(Object obj) {
192: if (this == obj) {
193: return true;
194: }
195: if (!(obj instanceof Map)) {
196: return false;
197: }
198: Map<K, V> other = (Map<K, V>) obj;
199: if (size() != other.size()) {
200: return false;
201: }
202:
203: Set<K> otherKeySet = other.keySet();
204: for (Map.Entry<K, V> entry : entrySet()) {
205: K key = entry.getKey();
206: if (!otherKeySet.contains(key)) {
207: return false;
208: }
209:
210: V value = entry.getValue();
211: if (!(value == null ? other.get(key) == null : value
212: .equals(other.get(key)))) {
213: return false;
214: }
215: }
216: return true;
217: }
218:
219: public int hashCode() {
220: int hashCode = 0;
221: for (Map.Entry<K, V> entry : entrySet()) {
222: hashCode += entry.hashCode();
223: }
224: return hashCode;
225: }
226:
227: @SuppressWarnings("unchecked")
228: private void initializeBackingArray(int length) {
229: _keys = (K[]) new Object[length];
230: _values = (V[]) new Object[length];
231: }
232:
233: private int indexOf(Object[] array, Object obj) {
234: int index = -1;
235: for (int i = _startIndex; i < _endIndex; i++) {
236: if (array[i] == null ? obj == null : array[i].equals(obj)) {
237: index = i;
238: break;
239: }
240: }
241: return index;
242: }
243:
244: private void add(K key, V value) {
245: ensureCapacity();
246: _keys[_endIndex] = key;
247: _values[_endIndex] = value;
248:
249: _endIndex++;
250: }
251:
252: @SuppressWarnings("unchecked")
253: private void ensureCapacity() {
254: if (_endIndex == _keys.length) {
255: Object[] newKeys = new Object[_keys.length * 2];
256: Object[] newValues = new Object[_values.length * 2];
257: System.arraycopy(_keys, _startIndex, newKeys, 0, _endIndex
258: - _startIndex);
259: System.arraycopy(_values, _startIndex, newValues, 0,
260: _endIndex - _startIndex);
261: Arrays.fill(_keys, null);
262: Arrays.fill(_values, null);
263: _keys = (K[]) newKeys;
264: _values = (V[]) newValues;
265: }
266: }
267:
268: private Object delete(int index) {
269: Object value = _values[index];
270: for (int i = index; i < _endIndex - 1; i++) {
271: _keys[i] = _keys[i + 1];
272: _values[i] = _values[i + 1];
273: }
274: _endIndex--;
275: _keys[_endIndex] = null;
276: _values[_endIndex] = null;
277: return value;
278: }
279:
280: public static class MapEntry4<K, V> implements Map.Entry<K, V> {
281:
282: private K _key;
283:
284: private V _value;
285:
286: public MapEntry4(K key, V value) {
287: _key = key;
288: _value = value;
289: }
290:
291: public K getKey() {
292: return _key;
293: }
294:
295: public V getValue() {
296: return _value;
297: }
298:
299: public V setValue(V value) {
300: V oldValue = value;
301: this ._value = value;
302: return oldValue;
303: }
304:
305: @SuppressWarnings("unchecked")
306: public boolean equals(Object o) {
307: if (this == o) {
308: return true;
309: }
310: if (!(o instanceof Map.Entry)) {
311: return false;
312: }
313:
314: MapEntry4<K, V> other = (MapEntry4<K, V>) o;
315:
316: return (_key == null ? other.getKey() == null : _key
317: .equals(other.getKey())
318: && _value == null ? other.getValue() == null
319: : _value.equals(other.getValue()));
320:
321: }
322:
323: public int hashCode() {
324: return (_key == null ? 0 : _key.hashCode())
325: ^ (_value == null ? 0 : _value.hashCode());
326: }
327: }
328: }
|