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

org.bitcoinj.utils.CacheMultiMap Maven / Gradle / Ivy

There is a newer version: 21.0.0
Show newest version
package org.bitcoinj.utils;

import org.bitcoinj.core.*;

import java.io.IOException;
import java.io.OutputStream;
import java.util.*;

/**
 * Map like container that keeps the N most recently added items
 */

public class CacheMultiMap extends Message {

    protected long nMaxSize;

    private long nCurrentSize;

    private LinkedList> listItems;

    private HashMap>> mapIndex;

    public CacheMultiMap() {
        this(0);
    }

    public CacheMultiMap(long nMaxSizeIn) {
        super(Context.get().getParams());
        this.nMaxSize = nMaxSizeIn;
        this.nCurrentSize = 0;
        this.listItems = new LinkedList>();
        this.mapIndex = new HashMap>>();
    }

    public CacheMultiMap(CacheMap other) {
        super(other.getParams());
        this.nMaxSize = other.getMaxSize();
        this.nCurrentSize = other.getSize();
        this.listItems = new LinkedList>(other.getItemList());
        this.mapIndex = new HashMap>>();
        rebuildIndex();
    }
    public CacheMultiMap(NetworkParameters params, byte [] payload, int cursor) {
        super(params, payload, cursor);
    }

    public final void clear() {
        mapIndex.clear();
        listItems.clear();
        nCurrentSize = 0;
    }

    public final void setMaxSize(long nMaxSizeIn) {
        nMaxSize = nMaxSizeIn;
    }

    public final long getMaxSize() {
        return nMaxSize;
    }

    public final long getSize() {
        return nCurrentSize;
    }

    public final boolean insert(K key, V value) {
        if (nCurrentSize == nMaxSize) {
            pruneLast();
        }
        HashMap> map = mapIndex.get(key);
        if (map == null) {
            map = new HashMap>();
            mapIndex.put(key, map);
        }

        if (map.containsValue(value)) {
            // Don't insert duplicates
            return false;
        }

        listItems.addFirst(new CacheItem(key, value));
        CacheItem lit = listItems.getFirst();

        map.put(value, lit);
        ++nCurrentSize;
        return true;
    }

    public final boolean hasKey(K key) {
        return mapIndex.containsKey(key);
    }

    public final V get(K key) {
        HashMap> it = mapIndex.get(key);
        if (it == null) {
            return null;
        }
        final HashMap> mapIt = it;
        final CacheItem item = mapIt.get(key);
        return item.value;
    }

    public final boolean getAll(K key, ArrayList vecValues) {
        assert(vecValues != null);
        HashMap> mit = mapIndex.get(key);
        if (mit == null) {
            return false;
        }

        for (Map.Entry> it :  mit.entrySet()) {
            final CacheItem item = it.getValue();
            vecValues.add(item.value);
        }
        return true;
    }

    public final void getKeys(ArrayList vecKeys) {
        assert(vecKeys != null);
        for (Map.Entry>> it:  mapIndex.entrySet()) {
            vecKeys.add(it.getKey());
        }
    }

    public final void erase(K key) {
        HashMap> mit = mapIndex.get(key);
        if (mit == null) {
            return;
        }

        for (Map.Entry> it : mit.entrySet()) {

            listItems.remove(it.getValue());
            --nCurrentSize;
        }
        mapIndex.remove(mit);
    }

    public final void erase(K key, V value) {
        HashMap> mit = mapIndex.get(key);
        if (mit == null) {
            return;
        }

        CacheItem it = mit.get(value);
        if (it == null) {
            return;
        }

        listItems.remove(it);
        --nCurrentSize;
        mit.remove(key);

        if (mit.size() < 1) {
            mapIndex.remove(mit);
        }
    }

    public final LinkedList> getItemList() {
        return listItems;
    }

    private void pruneLast() {
        if (nCurrentSize < 1) {
            return;
        }

        Iterator> lit = listItems.descendingIterator();
        CacheItem item = lit.next();

        HashMap> mit = mapIndex.get(item.key);

        if (mit != null){
            mit.remove(item.value);

            if (mit.size() < 1) {
                mapIndex.remove(item.key);
            }
        }

        listItems.removeLast();
        --nCurrentSize;
    }

    private void rebuildIndex() {
        mapIndex.clear();
        for(CacheItem lit : listItems)
        {
            HashMap> mit = mapIndex.get(lit.key);
            if (mit == null) {
                mit = new HashMap>();
                mapIndex.put(lit.key, mit);
            }
            mit.put(lit.value, lit);
        }
    }

    @Override
    protected void parse() throws ProtocolException {
        nMaxSize = readInt64();
        nCurrentSize = readInt64();
        long size = readVarInt();
        mapIndex = new LinkedHashMap>>();
        listItems = new LinkedList>();
        for (int i = 0; i < size; ++i) {
            CacheItem item = new CacheItem(params, payload, cursor);
            cursor += item.getMessageSize();
            listItems.add(item);
        }
        length = cursor - offset;
        rebuildIndex();
    }

    @Override
    protected void bitcoinSerializeToStream(OutputStream stream) throws IOException {
        Utils.int64ToByteStreamLE(nMaxSize, stream);
        Utils.int64ToByteStreamLE(nCurrentSize, stream);
        stream.write(new VarInt(listItems.size()).encode());
        for(CacheItem item : listItems) {
            item.bitcoinSerialize(stream);
        }
    }

    public String toString() {
        return "CacheMap("+nCurrentSize+" of {"+nMaxSize+"}}";
    }
}





© 2015 - 2024 Weber Informatics LLC | Privacy Policy