blob: 0c22f459f1ea6aa05004caa02e60e33cbe71e9ee [file] [log] [blame]
/*
* Copyright 2017 HugeGraph Authors
*
* 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 com.baidu.hugegraph.util;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
import com.google.common.base.Functions;
import com.google.common.collect.Ordering;
/**
* Reference: https://stackoverflow.com/questions/109383/sort-a-mapkey-value-by-values
*/
public class OrderLimitMap<K extends Comparable<K>, V extends Comparable<V>>
extends TreeMap<K, V> {
private static final long serialVersionUID = 756490437953358633L;
private final int capacity;
private final Map<K, V> valueMap;
private static <V extends Comparable<V>> Ordering<? super V> incr() {
return Ordering.from((V o1, V o2) -> o1.compareTo(o2));
}
private static <V extends Comparable<V>> Ordering<? super V> decr() {
return Ordering.from((V o1, V o2) -> -o1.compareTo(o2));
}
public OrderLimitMap(int capacity) {
this(capacity, false);
}
public OrderLimitMap(int capacity, boolean incr) {
this(capacity, incr ? incr() : decr(), new HashMap<>());
}
private OrderLimitMap(int capacity, Ordering<? super V> ordering,
HashMap<K, V> valueMap) {
/*
* onResultOf: for getting the value for the key from value map
* compound: keep insertion order
*/
super(ordering.onResultOf(Functions.forMap(valueMap))
.compound(Ordering.natural()));
E.checkArgument(capacity > 0, "The capacity must be > 0");
this.capacity = capacity;
this.valueMap = valueMap;
}
@Override
public V put(K k, V v) {
if (this.valueMap.containsKey(k)) {
super.remove(k);
} else if (this.valueMap.size() >= this.capacity) {
K key = super.lastKey();
super.remove(key);
this.valueMap.remove(key);
}
this.valueMap.put(k, v);
return super.put(k, v);
}
@Override
public V get(Object key) {
return this.valueMap.get(key);
}
@Override
public V getOrDefault(Object key, V defaultValue) {
return this.valueMap.getOrDefault(key, defaultValue);
}
@Override
public boolean containsKey(Object key) {
return this.valueMap.containsKey(key);
}
public Map<K, V> topN(int n) {
E.checkArgument(n > 0, "'N' Must be positive, but got '%s'", n);
Map<K, V> top = InsertionOrderUtil.newMap();
int i = 0;
for (Map.Entry<K, V> entry : this.entrySet()) {
top.put(entry.getKey(), entry.getValue());
if (++i >= n) {
break;
}
}
return top;
}
}