All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.camel.util.DoubleMap Maven / Gradle / Ivy

The newest version!
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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 org.apache.camel.util;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Predicate;

import org.apache.camel.util.function.TriConsumer;

@Deprecated(since = "4.1.0")
@SuppressWarnings("unchecked")
public class DoubleMap {

    private static final double MAX_LOAD_FACTOR = 1.2;
    private static final int MAX_TABLE_SIZE = 32768;
    private static final int C1 = 0xcc9e2d51;
    private static final int C2 = 0x1b873593;

    static class Entry {
        Object k1;
        Object k2;
        Object v;
        Entry next;
    }

    private final Lock lock = new ReentrantLock();
    private Entry[] table;
    private int mask;

    public DoubleMap(int size) {
        table = new Entry[closedTableSize(size)];
        mask = table.length - 1;
    }

    public V get(K1 k1, K2 k2) {
        Entry[] table = this.table;
        int mask = this.mask;
        int index = smear(k1.hashCode() * 31 + k2.hashCode()) & mask;
        for (Entry entry = table[index]; entry != null; entry = entry.next) {
            if (k1 == entry.k1 && k2 == entry.k2) {
                return (V) entry.v;
            }
        }
        return null;
    }

    public void forEach(TriConsumer consumer) {
        Entry[] table = this.table;
        for (Entry entry : table) {
            while (entry != null) {
                consumer.accept((K1) entry.k1, (K2) entry.k2, (V) entry.v);
                entry = entry.next;
            }
        }
    }

    public boolean containsKey(K1 k1, K2 k2) {
        Entry[] table = this.table;
        int mask = this.mask;
        int index = smear(k1.hashCode() * 31 + k2.hashCode()) & mask;
        for (Entry entry = table[index]; entry != null; entry = entry.next) {
            if (k1 == entry.k1 && k2 == entry.k2) {
                return true;
            }
        }
        return false;
    }

    public void put(K1 k1, K2 k2, V v) {
        lock.lock();
        try {
            Entry[] table = this.table;
            int size = size() + 1;
            int realSize = closedTableSize(size);
            if (realSize <= table.length) {
                realSize = table.length;
                int index = smear(k1.hashCode() * 31 + k2.hashCode()) & (realSize - 1);
                for (Entry oldEntry = table[index]; oldEntry != null; oldEntry = oldEntry.next) {
                    if (oldEntry.k1 == k1 && oldEntry.k2 == k2) {
                        oldEntry.v = v;
                        return;
                    }
                }
                Entry entry = new Entry();
                entry.k1 = k1;
                entry.k2 = k2;
                entry.v = v;
                entry.next = table[index];
                table[index] = entry;
            } else {
                Entry[] newT = new Entry[realSize];
                int index = smear(k1.hashCode() * 31 + k2.hashCode()) & (realSize - 1);
                Entry entry = new Entry();
                newT[index] = entry;
                entry.k1 = k1;
                entry.k2 = k2;
                entry.v = v;
                for (Entry oldEntry : table) {
                    while (oldEntry != null) {
                        if (k1 != oldEntry.k1 || k2 != oldEntry.k2) {
                            index = smear(oldEntry.k1.hashCode() * 31 + oldEntry.k2.hashCode()) & (realSize - 1);
                            Entry newEntry = new Entry();
                            newEntry.k1 = oldEntry.k1;
                            newEntry.k2 = oldEntry.k2;
                            newEntry.v = oldEntry.v;
                            newEntry.next = newT[index];
                            newT[index] = newEntry;
                        }
                        oldEntry = oldEntry.next;
                    }
                }
                this.table = newT;
                this.mask = realSize - 1;
            }
        } finally {
            lock.unlock();
        }
    }

    public boolean remove(K1 k1, K2 k2) {
        lock.lock();
        try {
            Entry[] table = this.table;
            int mask = this.mask;
            int index = smear(k1.hashCode() * 31 + k2.hashCode()) & mask;
            Entry prevEntry = null;
            for (Entry oldEntry = table[index]; oldEntry != null; prevEntry = oldEntry, oldEntry = oldEntry.next) {
                if (oldEntry.k1 == k1 && oldEntry.k2 == k2) {
                    if (prevEntry == null) {
                        table[index] = oldEntry.next;
                    } else {
                        prevEntry.next = oldEntry.next;
                    }
                    return true;
                }
            }
            return false;
        } finally {
            lock.unlock();
        }
    }

    public V getFirst(Predicate p1, Predicate p2) {
        for (Entry entry : table) {
            while (entry != null) {
                if (p1.test((K1) entry.k1) && p2.test((K2) entry.k2)) {
                    return (V) entry.v;
                }
                entry = entry.next;
            }
        }
        return null;
    }

    public int size() {
        Entry[] table = this.table;
        int n = 0;
        if (table != null) {
            for (Entry e : table) {
                for (Entry c = e; c != null; c = c.next) {
                    n++;
                }
            }
        }
        return n;
    }

    public void clear() {
        lock.lock();
        try {
            this.table = new Entry[table.length];
        } finally {
            lock.unlock();
        }
    }

    static int smear(int hashCode) {
        return C2 * Integer.rotateLeft(hashCode * C1, 15);
    }

    static int closedTableSize(int expectedEntries) {
        // Get the recommended table size.
        // Round down to the nearest power of 2.
        expectedEntries = Math.max(expectedEntries, 2);
        int tableSize = Integer.highestOneBit(expectedEntries);
        // Check to make sure that we will not exceed the maximum load factor.
        if (expectedEntries > (int) (MAX_LOAD_FACTOR * tableSize)) {
            tableSize <<= 1;
            return (tableSize > 0) ? tableSize : MAX_TABLE_SIZE;
        }
        return tableSize;
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy