예제 #1
0
  static <K, V> RegularImmutableBiMap<K, V> fromEntryArray(int n, Entry<K, V>[] entryArray) {
    checkPositionIndex(n, entryArray.length);
    int tableSize = Hashing.closedTableSize(n, MAX_LOAD_FACTOR);
    int mask = tableSize - 1;
    ImmutableMapEntry<K, V>[] keyTable = createEntryArray(tableSize);
    ImmutableMapEntry<K, V>[] valueTable = createEntryArray(tableSize);
    Entry<K, V>[] entries;
    if (n == entryArray.length) {
      entries = entryArray;
    } else {
      entries = createEntryArray(n);
    }
    int hashCode = 0;

    for (int i = 0; i < n; i++) {
      @SuppressWarnings("unchecked")
      Entry<K, V> entry = entryArray[i];
      K key = entry.getKey();
      V value = entry.getValue();
      checkEntryNotNull(key, value);
      int keyHash = key.hashCode();
      int valueHash = value.hashCode();
      int keyBucket = Hashing.smear(keyHash) & mask;
      int valueBucket = Hashing.smear(valueHash) & mask;

      ImmutableMapEntry<K, V> nextInKeyBucket = keyTable[keyBucket];
      checkNoConflictInKeyBucket(key, entry, nextInKeyBucket);
      ImmutableMapEntry<K, V> nextInValueBucket = valueTable[valueBucket];
      checkNoConflictInValueBucket(value, entry, nextInValueBucket);
      ImmutableMapEntry<K, V> newEntry;
      if (nextInValueBucket == null && nextInKeyBucket == null) {
        /*
         * TODO(user): consider using a NonTerminalImmutableMapEntry when nextInKeyBucket is
         * nonnull but nextInValueBucket is null.  This may save a few bytes on some platforms, but
         * 2-morphic call sites are often optimized much better than 3-morphic, so it'd require
         * benchmarking.
         */
        boolean reusable =
            entry instanceof ImmutableMapEntry && ((ImmutableMapEntry<K, V>) entry).isReusable();
        newEntry =
            reusable ? (ImmutableMapEntry<K, V>) entry : new ImmutableMapEntry<K, V>(key, value);
      } else {
        newEntry =
            new NonTerminalImmutableBiMapEntry<K, V>(
                key, value, nextInKeyBucket, nextInValueBucket);
      }
      keyTable[keyBucket] = newEntry;
      valueTable[valueBucket] = newEntry;
      entries[i] = newEntry;
      hashCode += keyHash ^ valueHash;
    }
    return new RegularImmutableBiMap<K, V>(keyTable, valueTable, entries, mask, hashCode);
  }
예제 #2
0
  RegularImmutableBiMap(Map.Entry<?, ?>[] entriesToAdd) {
    int n = entriesToAdd.length;
    int tableSize = Hashing.closedTableSize(n, 1.2D);
    this.mask = (tableSize - 1);
    ImmutableMapEntry<K, V>[] keyTable = createEntryArray(tableSize);
    ImmutableMapEntry<K, V>[] valueTable = createEntryArray(tableSize);
    ImmutableMapEntry<K, V>[] entries = createEntryArray(n);
    int hashCode = 0;
    for (int i = 0; i < n; i++) {
      Map.Entry<K, V> entry = entriesToAdd[i];
      K key = entry.getKey();
      V value = entry.getValue();
      CollectPreconditions.checkEntryNotNull(key, value);
      int keyHash = key.hashCode();
      int valueHash = value.hashCode();
      int keyBucket = Hashing.smear(keyHash) & this.mask;
      int valueBucket = Hashing.smear(valueHash) & this.mask;

      ImmutableMapEntry<K, V> nextInKeyBucket = keyTable[keyBucket];
      for (ImmutableMapEntry<K, V> keyEntry = nextInKeyBucket;
          keyEntry != null;
          keyEntry = keyEntry.getNextInKeyBucket()) {
        checkNoConflict(!key.equals(keyEntry.getKey()), "key", entry, keyEntry);
      }
      ImmutableMapEntry<K, V> nextInValueBucket = valueTable[valueBucket];
      for (ImmutableMapEntry<K, V> valueEntry = nextInValueBucket;
          valueEntry != null;
          valueEntry = valueEntry.getNextInValueBucket()) {
        checkNoConflict(!value.equals(valueEntry.getValue()), "value", entry, valueEntry);
      }
      ImmutableMapEntry<K, V> newEntry =
          (nextInKeyBucket == null) && (nextInValueBucket == null)
              ? new ImmutableMapEntry.TerminalEntry(key, value)
              : new NonTerminalBiMapEntry(key, value, nextInKeyBucket, nextInValueBucket);

      keyTable[keyBucket] = newEntry;
      valueTable[valueBucket] = newEntry;
      entries[i] = newEntry;
      hashCode += (keyHash ^ valueHash);
    }
    this.keyTable = keyTable;
    this.valueTable = valueTable;
    this.entries = entries;
    this.hashCode = hashCode;
  }
예제 #3
0
 public K get(@Nullable Object value) {
   if (value == null) {
     return null;
   }
   int bucket = Hashing.smear(value.hashCode()) & RegularImmutableBiMap.this.mask;
   for (ImmutableMapEntry<K, V> entry = RegularImmutableBiMap.this.valueTable[bucket];
       entry != null;
       entry = entry.getNextInValueBucket()) {
     if (value.equals(entry.getValue())) {
       return (K) entry.getKey();
     }
   }
   return null;
 }
예제 #4
0
 @Nullable
 public V get(@Nullable Object key) {
   if (key == null) {
     return null;
   }
   int bucket = Hashing.smear(key.hashCode()) & this.mask;
   for (ImmutableMapEntry<K, V> entry = this.keyTable[bucket];
       entry != null;
       entry = entry.getNextInKeyBucket()) {
     if (key.equals(entry.getKey())) {
       return (V) entry.getValue();
     }
   }
   return null;
 }
 @Override
 public boolean contains(Object target) {
   if (target == null) {
     return false;
   }
   for (int i = Hashing.smear(target.hashCode()); true; i++) {
     Object candidate = table[i & mask];
     if (candidate == null) {
       return false;
     }
     if (candidate.equals(target)) {
       return true;
     }
   }
 }
예제 #6
0
 @Override
 public K get(@Nullable Object value) {
   if (value == null || valueTable == null) {
     return null;
   }
   int bucket = Hashing.smear(value.hashCode()) & mask;
   for (ImmutableMapEntry<K, V> entry = valueTable[bucket];
       entry != null;
       entry = entry.getNextInValueBucket()) {
     if (value.equals(entry.getValue())) {
       return entry.getKey();
     }
   }
   return null;
 }
예제 #7
0
 public void testValueSetHashTableExpansion() {
   LinkedHashMultimap<String, Integer> multimap = LinkedHashMultimap.create();
   for (int z = 1; z <= 100; z++) {
     multimap.put("a", z);
     // The Eclipse compiler (and hence GWT) rejects a parameterized cast.
     @SuppressWarnings("unchecked")
     LinkedHashMultimap<String, Integer>.ValueSet valueSet =
         (LinkedHashMultimap.ValueSet) multimap.backingMap().get("a");
     assertEquals(z, valueSet.size());
     assertFalse(
         Hashing.needsResizing(
             valueSet.size(),
             valueSet.hashTable.length,
             LinkedHashMultimap.VALUE_SET_LOAD_FACTOR));
   }
 }
예제 #8
0
 private void init(int paramInt)
 {
   if (paramInt >= 0);
   for (boolean bool = true; ; bool = false)
   {
     Object[] arrayOfObject = new Object[1];
     arrayOfObject[0] = Integer.valueOf(paramInt);
     Preconditions.checkArgument(bool, "expectedSize must be >= 0 but was %s", arrayOfObject);
     int i = Hashing.closedTableSize(paramInt, 1.0D);
     this.hashTableKToV = createTable(i);
     this.hashTableVToK = createTable(i);
     this.mask = (i - 1);
     this.modCount = 0;
     this.size = 0;
     return;
   }
 }
예제 #9
0
 private void rehashIfNecessary()
 {
   BiEntry[] arrayOfBiEntry = this.hashTableKToV;
   if (Hashing.needsResizing(this.size, arrayOfBiEntry.length, 1.0D))
   {
     int i = 2 * arrayOfBiEntry.length;
     this.hashTableKToV = createTable(i);
     this.hashTableVToK = createTable(i);
     this.mask = (i - 1);
     this.size = 0;
     for (int j = 0; j < arrayOfBiEntry.length; j++)
     {
       BiEntry localBiEntry;
       for (Object localObject = arrayOfBiEntry[j]; localObject != null; localObject = localBiEntry)
       {
         localBiEntry = ((BiEntry)localObject).nextInKToVBucket;
         insert((BiEntry)localObject);
       }
     }
     this.modCount = (1 + this.modCount);
   }
 }
예제 #10
0
 private static int hash(@Nullable Object paramObject)
 {
   if (paramObject == null);
   for (int i = 0; ; i = paramObject.hashCode())
     return Hashing.smear(i);
 }