Switch jgit library to the EDL (3-clause BSD)
[jgit.git] / org.spearce.jgit / src / org / spearce / jgit / lib / ObjectIdMap.java
blob600d0f47fe3acf512d633c6366181f67de97ccdf
1 /*
2 * Copyright (C) 2007, Robin Rosenberg <robin.rosenberg@dewire.com>
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or
7 * without modification, are permitted provided that the following
8 * conditions are met:
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * - Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials provided
16 * with the distribution.
18 * - Neither the name of the Git Development Community nor the
19 * names of its contributors may be used to endorse or promote
20 * products derived from this software without specific prior
21 * written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
24 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
25 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
26 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
28 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
29 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
30 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
31 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
32 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
33 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
35 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 package org.spearce.jgit.lib;
40 import java.lang.reflect.InvocationTargetException;
41 import java.lang.reflect.Method;
42 import java.util.AbstractMap;
43 import java.util.AbstractSet;
44 import java.util.Iterator;
45 import java.util.Map;
46 import java.util.Set;
47 import java.util.TreeMap;
49 /**
50 * Very much like a map, but specialized to partition the data on the first byte
51 * of the key. This is about twice as fast. See test class.
53 * Inspiration is taken from the Git pack file format which uses this technique
54 * to improve lookup performance.
56 * @param <V>
57 * The value we map ObjectId's to.
60 public class ObjectIdMap<V> extends AbstractMap<ObjectId, V> {
62 @SuppressWarnings("unchecked")
63 final Map<ObjectId, V>[] level0 = new Map[256];
65 /**
66 * Construct an ObjectIdMap with an underlying TreeMap implementation
68 public ObjectIdMap() {
69 this(new TreeMap());
72 /**
73 * Construct an ObjectIdMap with the same underlying map implementation as
74 * the provided example.
76 * @param sample
78 @SuppressWarnings("unchecked")
79 public ObjectIdMap(Map sample) {
80 try {
81 Method m=sample.getClass().getMethod("clone", (Class[])null);
82 for (int i=0; i<256; ++i) {
83 level0[i] = (Map)m.invoke(sample, (Object[])null);
85 } catch (IllegalAccessException e) {
86 throw new IllegalArgumentException(e);
87 } catch (IllegalArgumentException e) {
88 throw new IllegalArgumentException(e);
89 } catch (InvocationTargetException e) {
90 throw new IllegalArgumentException(e);
91 } catch (SecurityException e) {
92 throw new IllegalArgumentException(e);
93 } catch (NoSuchMethodException e) {
94 throw new IllegalArgumentException(e);
98 public void clear() {
99 for (int i=0; i<256; ++i)
100 level0[i].clear();
103 public boolean containsKey(Object key) {
104 return submap((ObjectId)key).containsKey(key);
107 private final Map<ObjectId, V> submap(ObjectId key) {
108 return level0[key.getFirstByte()];
111 public boolean containsValue(Object value) {
112 for (int i=0; i<256; ++i)
113 if (level0[i].containsValue(value))
114 return true;
115 return false;
118 private Set<Map.Entry<ObjectId, V>> entrySet =
119 new AbstractSet<Map.Entry<ObjectId, V>>() {
121 @Override
122 final public Iterator<Map.Entry<ObjectId, V>> iterator() {
123 return new Iterator<Entry<ObjectId,V>>() {
124 private int levelIndex;
125 private boolean hasNext;
126 private Iterator<Map.Entry<ObjectId, V>> levelIterator;
127 private Iterator<Map.Entry<ObjectId, V>> lastIterator;
129 step();
131 public boolean hasNext() {
132 return hasNext;
134 public java.util.Map.Entry<ObjectId, V> next() {
135 Entry<ObjectId, V> ret = levelIterator.next();
136 step();
137 return ret;
139 public void remove() {
140 lastIterator.remove();
143 private void step() {
144 hasNext = false;
145 lastIterator = levelIterator;
146 while ((levelIterator==null || !(hasNext=levelIterator.hasNext()))) {
147 if (levelIndex < level0.length)
148 levelIterator = level0[levelIndex++].entrySet().iterator();
149 else
150 break;
156 @Override
157 public int size() {
158 int ret=0;
159 for (int i=0; i<256; ++i)
160 ret += level0[i].size();
161 return ret;
166 public Set<Map.Entry<ObjectId, V>> entrySet() {
167 return entrySet;
170 public V get(Object key) {
171 return submap((ObjectId)key).get(key);
174 public boolean isEmpty() {
175 for (int i=0; i<256; ++i)
176 if (!level0[i].isEmpty())
177 return false;
178 return true;
181 @SuppressWarnings("unchecked")
182 public V put(ObjectId key, V value) {
183 return submap(key).put(key, value);
186 public void putAll(Map<? extends ObjectId, ? extends V> arg0) {
187 for (ObjectId k : arg0.keySet()) {
188 V v=arg0.get(k);
189 put(k,v);
193 public V remove(Object key) {
194 return submap((ObjectId) key).remove(key);
197 public int size() {
198 return entrySet().size();