org.bitcoinj.utils.CacheMultiMap Maven / Gradle / Ivy
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+"}}";
}
}