Skip to content

Commit 080ea75

Browse files
committed
GROOVY-11063
for #1482
1 parent f95dabb commit 080ea75

File tree

6 files changed

+642
-0
lines changed

6 files changed

+642
-0
lines changed

base/org.codehaus.groovy30/.checkstyle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@
7070
<file-match-pattern match-pattern="groovy/transform/trait/TraitASTTransformation.java" include-pattern="false" />
7171
<file-match-pattern match-pattern="groovy/transform/trait/TraitComposer.java" include-pattern="false" />
7272
<file-match-pattern match-pattern="groovy/transform/trait/Traits.java" include-pattern="false" />
73+
<file-match-pattern match-pattern="groovy/util/ListHashMap.java" include-pattern="false" />
7374
<file-match-pattern match-pattern="groovy/vmplugin/v8/Java8.java" include-pattern="false" />
7475
</fileset>
7576
<filter name="DerivedFiles" enabled="true" />
Lines changed: 213 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,213 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
package org.codehaus.groovy.util;
20+
21+
import java.util.Collection;
22+
import java.util.Collections;
23+
import java.util.Map;
24+
import java.util.Set;
25+
26+
/**
27+
* Represents a {@link Map} that is optimized for a small number of entries. For
28+
* a number of entries up to {@code listSize} the entries are stored in arrays.
29+
* After {@code listSize} entries are exceeded storage switches internally to a
30+
* {@link Map} and converts back to being array based when its size is less than
31+
* or equal to {@code listSize}.
32+
* <p>
33+
* Null keys or values are not supported.
34+
* <p>
35+
* This class is not thread-safe!
36+
*/
37+
public class ListHashMap<K,V> implements Map<K,V> {
38+
39+
private final K[] keys;
40+
private final V[] values;
41+
private Map<K,V> innerMap;
42+
private volatile int size;
43+
44+
public ListHashMap() {
45+
this(3);
46+
}
47+
48+
public ListHashMap(int listSize) {
49+
keys = (K[]) new Object[listSize];
50+
values = (V[]) new Object[listSize];
51+
}
52+
53+
@Override
54+
public void clear() {
55+
innerMap = null;
56+
clearArrays();
57+
size = 0;
58+
}
59+
60+
private void clearArrays() {
61+
for (int i = 0, n = keys.length; i < n; i += 1) {
62+
values[i] = null;
63+
keys[i] = null;
64+
}
65+
}
66+
67+
@Override
68+
public boolean containsKey(Object key) {
69+
if (key != null) {
70+
if (innerMap != null) {
71+
return innerMap.containsKey(key);
72+
}
73+
for (int i = 0; i < size; i += 1) {
74+
if (key.equals(keys[i])) return true;
75+
}
76+
}
77+
return false;
78+
}
79+
80+
@Override
81+
public boolean containsValue(Object value) {
82+
if (value != null) {
83+
if (innerMap != null) {
84+
return innerMap.containsValue(value);
85+
}
86+
for (int i = 0; i < size; i += 1) {
87+
if (value.equals(values[i])) return true;
88+
}
89+
}
90+
return false;
91+
}
92+
93+
@Override
94+
public Set<Entry<K,V>> entrySet() {
95+
return (innerMap != null ? Collections.unmodifiableMap(innerMap) : toMap()).entrySet();
96+
}
97+
98+
@Override
99+
public V get(Object key) {
100+
if (key != null) {
101+
if (innerMap != null) {
102+
return innerMap.get(key);
103+
}
104+
for (int i = 0; i < size; i += 1) {
105+
if (key.equals(keys[i])) return values[i];
106+
}
107+
}
108+
return null;
109+
}
110+
111+
@Override
112+
public boolean isEmpty() {
113+
return (size == 0);
114+
}
115+
116+
@Override
117+
public Set<K> keySet() {
118+
return (innerMap != null ? Collections.unmodifiableMap(innerMap) : toMap()).keySet();
119+
}
120+
121+
@Override
122+
public V put(K key, V value) {
123+
if (key != null) {
124+
if (value == null) {
125+
return remove(key);
126+
}
127+
if (innerMap != null) {
128+
V old = innerMap.put(key, value);
129+
size = innerMap.size();
130+
return old;
131+
}
132+
for (int i = 0; i < size; i += 1) {
133+
if (key.equals(keys[i])) {
134+
V old = values[i];
135+
values[i] = value;
136+
return old;
137+
}
138+
}
139+
if (size < keys.length) {
140+
values[size] = value;
141+
keys[size] = key;
142+
} else { // evolve
143+
Map<K,V> map = toMap();
144+
map.put(key, value);
145+
innerMap = map;
146+
clearArrays();
147+
}
148+
size += 1;
149+
}
150+
return null;
151+
}
152+
153+
@Override
154+
public void putAll(Map<? extends K, ? extends V> m) {
155+
for (Entry<? extends K, ? extends V> entry : m.entrySet()) {
156+
put(entry.getKey(), entry.getValue());
157+
}
158+
}
159+
160+
@Override
161+
public V remove(Object key) {
162+
if (key != null) {
163+
if (innerMap != null) {
164+
V value = innerMap.remove(key);
165+
if (value != null) {
166+
size = innerMap.size();
167+
if (size <= keys.length) { // devolve
168+
size = 0; Set<Entry<K,V>> entries = innerMap.entrySet(); innerMap = null;
169+
for (Entry<? extends K, ? extends V> entry : entries) {
170+
values[size] = entry.getValue();
171+
keys[size] = entry.getKey();
172+
size += 1;
173+
}
174+
}
175+
}
176+
return value;
177+
}
178+
for (int i = 0; i < size; i += 1) {
179+
if (key.equals(keys[i])) {
180+
V value = values[i];
181+
size -= 1;
182+
// if last element is not being removed, shift the last element into this slot
183+
if (i < size) {
184+
values[i] = values[size];
185+
keys[i] = keys[size];
186+
}
187+
values[size] = null;
188+
keys[size] = null;
189+
return value;
190+
}
191+
}
192+
}
193+
return null;
194+
}
195+
196+
@Override
197+
public int size() {
198+
return size;
199+
}
200+
201+
private Map<K,V> toMap() {
202+
Map<K,V> m = new java.util.HashMap<>();
203+
for (int i = 0; i < size; i += 1) {
204+
m.put(keys[i], values[i]);
205+
}
206+
return m;
207+
}
208+
209+
@Override
210+
public Collection<V> values() {
211+
return (innerMap != null ? Collections.unmodifiableMap(innerMap) : toMap()).values();
212+
}
213+
}

base/org.codehaus.groovy40/.checkstyle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@
6161
<file-match-pattern match-pattern="groovy/transform/trait/TraitComposer.java" include-pattern="false" />
6262
<file-match-pattern match-pattern="groovy/transform/trait/TraitReceiverTransformer.java" include-pattern="false" />
6363
<file-match-pattern match-pattern="groovy/transform/trait/Traits.java" include-pattern="false" />
64+
<file-match-pattern match-pattern="groovy/util/ListHashMap.java" include-pattern="false" />
6465
<file-match-pattern match-pattern="groovy/vmplugin/v8/Java8.java" include-pattern="false" />
6566
</fileset>
6667
<filter name="DerivedFiles" enabled="true" />

0 commit comments

Comments
 (0)