Skip to content

Commit 19e5ed4

Browse files
committed
Collapse CompactStringObjectMap into single class again (remove 1/2-element optimized version)
1 parent a294f4c commit 19e5ed4

File tree

1 file changed

+90
-164
lines changed

1 file changed

+90
-164
lines changed

src/main/java/com/fasterxml/jackson/databind/util/CompactStringObjectMap.java

Lines changed: 90 additions & 164 deletions
Original file line numberDiff line numberDiff line change
@@ -14,196 +14,122 @@
1414
*
1515
* @since 2.6
1616
*/
17-
public abstract class CompactStringObjectMap
17+
public final class CompactStringObjectMap
1818
{
19-
public static CompactStringObjectMap empty() {
20-
return Small.EMPTY;
21-
}
22-
23-
public static <T> CompactStringObjectMap construct(Map<String,T> contents)
24-
{
25-
if (contents.size() == 0) { // can this occur?
26-
return empty();
27-
}
28-
Iterator<Map.Entry<String,T>> it = contents.entrySet().iterator();
29-
switch (contents.size()) {
30-
case 1:
31-
return new Small(it.next(), null);
32-
case 2:
33-
return new Small(it.next(), it.next());
34-
}
35-
// General-purpose "big" one needed:
36-
return Big.construct(contents);
37-
}
38-
39-
public abstract Object find(String key);
40-
41-
public abstract List<String> keys();
19+
/**
20+
* Shared instance that can be used when there are no contents to Map.
21+
*/
22+
private final static CompactStringObjectMap EMPTY = new CompactStringObjectMap(1, 0,
23+
new Object[4]);
4224

43-
final static class Small extends CompactStringObjectMap
44-
{
45-
public final static Small EMPTY = new Small(null, null);
46-
47-
protected final String key1, key2;
48-
protected final Object value1, value2;
25+
private final int _hashMask, _spillCount;
4926

50-
public Small(Map.Entry<String,?> e1, Map.Entry<String,?> e2)
51-
{
52-
if (e1 == null) {
53-
key1 = null;
54-
value1 = null;
55-
} else {
56-
key1 = e1.getKey();
57-
value1 = e1.getValue();
58-
}
59-
if (e2 == null) {
60-
key2 = null;
61-
value2 = null;
62-
} else {
63-
key2 = e2.getKey();
64-
value2 = e2.getValue();
65-
}
66-
}
67-
68-
@Override
69-
public Object find(String key) {
70-
// no assumption of key being intern()ed:
71-
if (key.equals(key1)) {
72-
return value1;
73-
}
74-
if (key.equals(key2)) {
75-
return value2;
76-
}
77-
return null;
78-
}
27+
private final Object[] _hashArea;
7928

80-
@Override
81-
public List<String> keys() {
82-
ArrayList<String> keys = new ArrayList<String>(2);
83-
if (key1 != null) {
84-
keys.add(key1);
85-
}
86-
if (key2 != null) {
87-
keys.add(key2);
88-
}
89-
return keys;
90-
}
91-
}
92-
93-
/**
94-
* Raw mapping from keys to indices, optimized for fast access via
95-
* better memory efficiency. Hash area divide in three; main hash,
96-
* half-size secondary, followed by as-big-as-needed spillover.
97-
*/
98-
final static class Big extends CompactStringObjectMap
29+
private CompactStringObjectMap(int hashMask, int spillCount, Object[] hashArea)
9930
{
100-
private final int _hashMask, _spillCount;
101-
102-
private final Object[] _hashArea;
31+
_hashMask = hashMask;
32+
_spillCount = spillCount;
33+
_hashArea = hashArea;
34+
}
10335

104-
private Big(int hashMask, int spillCount, Object[] hashArea)
105-
{
106-
_hashMask = hashMask;
107-
_spillCount = spillCount;
108-
_hashArea = hashArea;
36+
public static <T> CompactStringObjectMap construct(Map<String,T> all)
37+
{
38+
if (all.isEmpty()) { // can this happen?
39+
return EMPTY;
10940
}
11041

111-
public static <T> Big construct(Map<String,T> all)
112-
{
113-
// First: calculate size of primary hash area
114-
final int size = findSize(all.size());
115-
final int mask = size-1;
116-
// and allocate enough to contain primary/secondary, expand for spillovers as need be
117-
int alloc = (size + (size>>1)) * 2;
118-
Object[] hashArea = new Object[alloc];
119-
int spillCount = 0;
42+
// First: calculate size of primary hash area
43+
final int size = findSize(all.size());
44+
final int mask = size-1;
45+
// and allocate enough to contain primary/secondary, expand for spillovers as need be
46+
int alloc = (size + (size>>1)) * 2;
47+
Object[] hashArea = new Object[alloc];
48+
int spillCount = 0;
12049

121-
for (Map.Entry<String,T> entry : all.entrySet()) {
122-
String key = entry.getKey();
50+
for (Map.Entry<String,T> entry : all.entrySet()) {
51+
String key = entry.getKey();
12352

124-
int slot = key.hashCode() & mask;
125-
int ix = slot+slot;
53+
int slot = key.hashCode() & mask;
54+
int ix = slot+slot;
12655

127-
// primary slot not free?
56+
// primary slot not free?
57+
if (hashArea[ix] != null) {
58+
// secondary?
59+
ix = (size + (slot >> 1)) << 1;
12860
if (hashArea[ix] != null) {
129-
// secondary?
130-
ix = (size + (slot >> 1)) << 1;
131-
if (hashArea[ix] != null) {
132-
// ok, spill over.
133-
ix = ((size + (size >> 1) ) << 1) + spillCount;
134-
spillCount += 2;
135-
if (ix >= hashArea.length) {
136-
hashArea = Arrays.copyOf(hashArea, hashArea.length + 4);
137-
}
61+
// ok, spill over.
62+
ix = ((size + (size >> 1) ) << 1) + spillCount;
63+
spillCount += 2;
64+
if (ix >= hashArea.length) {
65+
hashArea = Arrays.copyOf(hashArea, hashArea.length + 4);
13866
}
13967
}
140-
hashArea[ix] = key;
141-
hashArea[ix+1] = entry.getValue();
14268
}
143-
return new Big(mask, spillCount, hashArea);
69+
hashArea[ix] = key;
70+
hashArea[ix+1] = entry.getValue();
14471
}
72+
return new CompactStringObjectMap(mask, spillCount, hashArea);
73+
}
14574

146-
private final static int findSize(int size)
147-
{
148-
if (size <= 5) {
149-
return 8;
150-
}
151-
if (size <= 12) {
152-
return 16;
153-
}
154-
int needed = size + (size >> 2); // at most 80% full
155-
int result = 32;
156-
while (result < needed) {
157-
result += result;
158-
}
159-
return result;
75+
private final static int findSize(int size)
76+
{
77+
if (size <= 5) {
78+
return 8;
16079
}
80+
if (size <= 12) {
81+
return 16;
82+
}
83+
int needed = size + (size >> 2); // at most 80% full
84+
int result = 32;
85+
while (result < needed) {
86+
result += result;
87+
}
88+
return result;
89+
}
16190

162-
@Override
163-
public Object find(String key) {
164-
int slot = key.hashCode() & _hashMask;
165-
int ix = (slot<<1);
166-
Object match = _hashArea[ix];
167-
if ((match == key) || key.equals(match)) {
168-
return _hashArea[ix+1];
169-
}
170-
return _find2(key, slot, match);
91+
public Object find(String key) {
92+
int slot = key.hashCode() & _hashMask;
93+
int ix = (slot<<1);
94+
Object match = _hashArea[ix];
95+
if ((match == key) || key.equals(match)) {
96+
return _hashArea[ix+1];
17197
}
98+
return _find2(key, slot, match);
99+
}
172100

173-
private final Object _find2(String key, int slot, Object match)
174-
{
175-
if (match == null) {
176-
return null;
177-
}
178-
int hashSize = _hashMask+1;
179-
int ix = hashSize + (slot>>1) << 1;
180-
match = _hashArea[ix];
181-
if (key.equals(match)) {
182-
return _hashArea[ix+1];
183-
}
184-
if (match != null) { // _findFromSpill(...)
185-
int i = (hashSize + (hashSize>>1)) << 1;
186-
for (int end = i + _spillCount; i < end; i += 2) {
187-
match = _hashArea[i];
188-
if ((match == key) || key.equals(match)) {
189-
return _hashArea[i+1];
190-
}
101+
private final Object _find2(String key, int slot, Object match)
102+
{
103+
if (match == null) {
104+
return null;
105+
}
106+
int hashSize = _hashMask+1;
107+
int ix = hashSize + (slot>>1) << 1;
108+
match = _hashArea[ix];
109+
if (key.equals(match)) {
110+
return _hashArea[ix+1];
111+
}
112+
if (match != null) { // _findFromSpill(...)
113+
int i = (hashSize + (hashSize>>1)) << 1;
114+
for (int end = i + _spillCount; i < end; i += 2) {
115+
match = _hashArea[i];
116+
if ((match == key) || key.equals(match)) {
117+
return _hashArea[i+1];
191118
}
192119
}
193-
return null;
194120
}
121+
return null;
122+
}
195123

196-
@Override
197-
public List<String> keys() {
198-
final int end = _hashArea.length;
199-
List<String> keys = new ArrayList<String>(end >> 2);
200-
for (int i = 0; i < end; i += 2) {
201-
Object key = _hashArea[i];
202-
if (key != null) {
203-
keys.add((String) key);
204-
}
124+
public List<String> keys() {
125+
final int end = _hashArea.length;
126+
List<String> keys = new ArrayList<String>(end >> 2);
127+
for (int i = 0; i < end; i += 2) {
128+
Object key = _hashArea[i];
129+
if (key != null) {
130+
keys.add((String) key);
205131
}
206-
return keys;
207132
}
133+
return keys;
208134
}
209135
}

0 commit comments

Comments
 (0)