class TopMap<K> {

        private final long topN;
        private Map<K, MutableLong> tops;

        public TopMap(long topN) {
            this.topN = topN;
            this.tops = new HashMap<>();
        }

        public int size() {
            return this.tops.size();
        }

        public MutableLong get(K key) {
            return this.tops.get(key);
        }

        public void add(K key, long value) {
            MutableLong mlong = this.tops.get(key);
            if (mlong == null) {
                mlong = new MutableLong(value);
                this.tops.put(key, mlong);
            }
            mlong.add(value);
        }

        public void put(K key, long value) {
            assert this.topN != 0L;
            this.tops.put(key, new MutableLong(value));
            // keep 2x buffer
            if (this.tops.size() > this.topN * 2 &&
                this.topN != HugeTraverser.NO_LIMIT) {
                this.shrinkIfNeeded(this.topN);
            }
        }

        public Set<Map.Entry<K, MutableLong>> entrySet() {
            if (this.tops.size() <= this.topN) {
                this.tops = CollectionUtil.sortByValue(this.tops, false);
            } else {
                this.shrinkIfNeeded(this.topN);
            }
            return this.tops.entrySet();
        }

        private void shrinkIfNeeded(long limit) {<FILL_FUNCTION_BODY>}
    }

            assert limit != 0L;
            if (this.tops.size() >= limit &&
                (limit > 0L || limit == HugeTraverser.NO_LIMIT)) {
                // Just do sort if limit=NO_LIMIT, else do sort and shrink
                this.tops = HugeTraverser.topN(this.tops, true, limit);
            }
        
<no_super_class>