1 /*
2 * Copyright (C) 2009, Google Inc.
3 * and other copyright owners as documented in the project's IP log.
4 *
5 * This program and the accompanying materials are made available
6 * under the terms of the Eclipse Distribution License v1.0 which
7 * accompanies this distribution, is reproduced below, and is
8 * available at http://www.eclipse.org/org/documents/edl-v10.php
9 *
10 * All rights reserved.
11 *
12 * Redistribution and use in source and binary forms, with or
13 * without modification, are permitted provided that the following
14 * conditions are met:
15 *
16 * - Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 *
19 * - Redistributions in binary form must reproduce the above
20 * copyright notice, this list of conditions and the following
21 * disclaimer in the documentation and/or other materials provided
22 * with the distribution.
23 *
24 * - Neither the name of the Eclipse Foundation, Inc. nor the
25 * names of its contributors may be used to endorse or promote
26 * products derived from this software without specific prior
27 * written permission.
28 *
29 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
30 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
31 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
32 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
34 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
35 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
36 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
37 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
38 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
40 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
41 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42 */
43
44 package org.eclipse.jgit.util;
45
46 /**
47 * Simple Map<long, Object>.
48 *
49 * @param <V>
50 * type of the value instance.
51 * @since 4.9
52 */
53 public class LongMap<V> {
54 private static final float LOAD_FACTOR = 0.75f;
55
56 private Node<V>[] table;
57
58 /** Number of entries currently in the map. */
59 private int size;
60
61 /** Next {@link #size} to trigger a {@link #grow()}. */
62 private int growAt;
63
64 /**
65 * Initialize an empty LongMap.
66 */
67 public LongMap() {
68 table = createArray(64);
69 growAt = (int) (table.length * LOAD_FACTOR);
70 }
71
72 /**
73 * Whether {@code key} is present in the map.
74 *
75 * @param key
76 * the key to find.
77 * @return {@code true} if {@code key} is present in the map.
78 */
79 public boolean containsKey(long key) {
80 return get(key) != null;
81 }
82
83 /**
84 * Get value for this {@code key}
85 *
86 * @param key
87 * the key to find.
88 * @return stored value for this key, or {@code null}.
89 */
90 public V get(long key) {
91 for (Node<V> n = table[index(key)]; n != null; n = n.next) {
92 if (n.key == key)
93 return n.value;
94 }
95 return null;
96 }
97
98 /**
99 * Remove an entry from the map
100 *
101 * @param key
102 * key to remove from the map.
103 * @return old value of the key, or {@code null}.
104 */
105 public V remove(long key) {
106 Node<V> n = table[index(key)];
107 Node<V> prior = null;
108 while (n != null) {
109 if (n.key == key) {
110 if (prior == null)
111 table[index(key)] = n.next;
112 else
113 prior.next = n.next;
114 size--;
115 return n.value;
116 }
117 prior = n;
118 n = n.next;
119 }
120 return null;
121 }
122
123 /**
124 * Put a new entry into the map
125 *
126 * @param key
127 * key to store {@code value} under.
128 * @param value
129 * new value.
130 * @return prior value, or null.
131 */
132 public V put(long key, V value) {
133 for (Node<V> n = table[index(key)]; n != null; n = n.next) {
134 if (n.key == key) {
135 final V o = n.value;
136 n.value = value;
137 return o;
138 }
139 }
140
141 if (++size == growAt)
142 grow();
143 insert(new Node<>(key, value));
144 return null;
145 }
146
147 private void insert(Node<V> n) {
148 final int idx = index(n.key);
149 n.next = table[idx];
150 table[idx] = n;
151 }
152
153 private void grow() {
154 final Node<V>[] oldTable = table;
155 final int oldSize = table.length;
156
157 table = createArray(oldSize << 1);
158 growAt = (int) (table.length * LOAD_FACTOR);
159 for (int i = 0; i < oldSize; i++) {
160 Node<V> e = oldTable[i];
161 while (e != null) {
162 final Node<V> n = e.next;
163 insert(e);
164 e = n;
165 }
166 }
167 }
168
169 private final int index(long key) {
170 int h = ((int) key) >>> 1;
171 h ^= (h >>> 20) ^ (h >>> 12);
172 return h & (table.length - 1);
173 }
174
175 @SuppressWarnings("unchecked")
176 private static final <V> Node<V>[] createArray(int sz) {
177 return new Node[sz];
178 }
179
180 private static class Node<V> {
181 final long key;
182 V value;
183 Node<V> next;
184
185 Node(long k, V v) {
186 key = k;
187 value = v;
188 }
189 }
190 }