com.google.common.collect.RegularImmutableMap Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of guava Show documentation
Show all versions of guava Show documentation
Guava is a suite of core and expanded libraries that include
utility classes, google's collections, io classes, and much
much more.
Guava has two code dependencies - javax.annotation
per the JSR-305 spec and javax.inject per the JSR-330 spec.
This is a fork of Guava 14.0.1 for Hudson.
The newest version!
/*
* Copyright (C) 2008 The Guava Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.common.collect;
import static com.google.common.base.Preconditions.checkArgument;
import com.google.common.annotations.GwtCompatible;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
/**
* Implementation of {@link ImmutableMap} with two or more entries.
*
* @author Jesse Wilson
* @author Kevin Bourrillion
* @author Gregory Kick
*/
@GwtCompatible(serializable = true, emulated = true)
final class RegularImmutableMap extends ImmutableMap {
// entries in insertion order
private final transient LinkedEntry[] entries;
// array of linked lists of entries
private final transient LinkedEntry[] table;
// 'and' with an int to get a table index
private final transient int mask;
// TODO(gak): investigate avoiding the creation of ImmutableEntries since we
// re-copy them anyway.
RegularImmutableMap(Entry, ?>... immutableEntries) {
int size = immutableEntries.length;
entries = createEntryArray(size);
int tableSize = Hashing.closedTableSize(size, MAX_LOAD_FACTOR);
table = createEntryArray(tableSize);
mask = tableSize - 1;
for (int entryIndex = 0; entryIndex < size; entryIndex++) {
// each of our 6 callers carefully put only Entrys into the array!
@SuppressWarnings("unchecked")
Entry entry = (Entry) immutableEntries[entryIndex];
K key = entry.getKey();
int keyHashCode = key.hashCode();
int tableIndex = Hashing.smear(keyHashCode) & mask;
@Nullable LinkedEntry existing = table[tableIndex];
// prepend, not append, so the entries can be immutable
LinkedEntry linkedEntry =
newLinkedEntry(key, entry.getValue(), existing);
table[tableIndex] = linkedEntry;
entries[entryIndex] = linkedEntry;
while (existing != null) {
checkArgument(!key.equals(existing.getKey()), "duplicate key: %s", key);
existing = existing.next();
}
}
}
/**
* Closed addressing tends to perform well even with high load factors.
* Being conservative here ensures that the table is still likely to be
* relatively sparse (hence it misses fast) while saving space.
*/
private static final double MAX_LOAD_FACTOR = 1.2;
/**
* Creates a {@link LinkedEntry} array to hold parameterized entries. The
* result must never be upcast back to LinkedEntry[] (or Object[], etc.), or
* allowed to escape the class.
*/
@SuppressWarnings("unchecked") // Safe as long as the javadocs are followed
private LinkedEntry[] createEntryArray(int size) {
return new LinkedEntry[size];
}
private static LinkedEntry newLinkedEntry(K key, V value,
@Nullable LinkedEntry next) {
return (next == null)
? new TerminalEntry(key, value)
: new NonTerminalEntry(key, value, next);
}
private interface LinkedEntry extends Entry {
/** Returns the next entry in the list or {@code null} if none exists. */
@Nullable LinkedEntry next();
}
/** {@code LinkedEntry} implementation that has a next value. */
@Immutable
@SuppressWarnings("serial") // this class is never serialized
private static final class NonTerminalEntry
extends ImmutableEntry implements LinkedEntry {
final LinkedEntry next;
NonTerminalEntry(K key, V value, LinkedEntry next) {
super(key, value);
this.next = next;
}
@Override public LinkedEntry next() {
return next;
}
}
/**
* {@code LinkedEntry} implementation that serves as the last entry in the
* list. I.e. no next entry
*/
@Immutable
@SuppressWarnings("serial") // this class is never serialized
private static final class TerminalEntry extends ImmutableEntry
implements LinkedEntry {
TerminalEntry(K key, V value) {
super(key, value);
}
@Nullable @Override public LinkedEntry next() {
return null;
}
}
@Override public V get(@Nullable Object key) {
if (key == null) {
return null;
}
int index = Hashing.smear(key.hashCode()) & mask;
for (LinkedEntry entry = table[index];
entry != null;
entry = entry.next()) {
K candidateKey = entry.getKey();
/*
* Assume that equals uses the == optimization when appropriate, and that
* it would check hash codes as an optimization when appropriate. If we
* did these things, it would just make things worse for the most
* performance-conscious users.
*/
if (key.equals(candidateKey)) {
return entry.getValue();
}
}
return null;
}
@Override
public int size() {
return entries.length;
}
@Override boolean isPartialView() {
return false;
}
@Override
ImmutableSet> createEntrySet() {
return new EntrySet();
}
@SuppressWarnings("serial") // uses writeReplace(), not default serialization
private class EntrySet extends ImmutableMapEntrySet {
@Override ImmutableMap map() {
return RegularImmutableMap.this;
}
@Override
public UnmodifiableIterator> iterator() {
return asList().iterator();
}
@Override
ImmutableList> createAsList() {
return new RegularImmutableAsList>(this, entries);
}
}
// This class is never actually serialized directly, but we have to make the
// warning go away (and suppressing would suppress for all nested classes too)
private static final long serialVersionUID = 0;
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy