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

soot.jimple.infoflow.collections.util.MySpecialMultiMap Maven / Gradle / Ivy

The newest version!
package soot.jimple.infoflow.collections.util;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.function.Consumer;

/**
 * Special MultiMap that saves the first-added element seperated from the element added afterward
 *
 * @param  key type
 * @param  value type
 */
public class MySpecialMultiMap {
    /**
     * Set that saves the first value separately
     *
     * @param  value type
     */
    protected static class MySet {
        protected final V firstValue;
        protected final Set otherValues;

        MySet(V v) {
            this(v, new HashSet<>());
        }

        private MySet(V v, Set newSet) {
            this.firstValue = v;
            // This can be a thread-unsafe set because there is always a lock on the key
            // when the set is accessed.
            this.otherValues = newSet;
        }

        void add(V value) {
            if (!firstValue.equals(value))
                otherValues.add(value);
        }
    }

    /**
     * Dummy set that prevents any reuse
     *
     * @param  value type
     */
    protected static class NotReusableSet extends MySet {
        NotReusableSet() {
            super(null, Collections.emptySet());
        }

        @Override
        void add(V value) {
            // NO-OP
        }
    }
    protected NotReusableSet notReusableSet = new NotReusableSet<>();

    protected final ConcurrentMap> m;

    public MySpecialMultiMap() {
        this.m = new ConcurrentHashMap<>();
    }


    /**
     * Puts the value into the map and gets the first added value for this key
     *
     * @param key   key
     * @param value value
     * @return the first added value or null if the key had no mapping before
     */
    public V putAndGetFirst(K key, V value) {
        @SuppressWarnings("unchecked")
        V[] returnValue = (V[]) new Object[1];

        m.compute(key, (k, set) -> {
            if (set == null)
                return new MySet<>(value);

            returnValue[0] = set.firstValue;
            set.add(value);
            return set;
        });

        return returnValue[0];
    }

    /**
     * Runs the consumer on all other values and removes the key value mapping
     *
     * @param key      key
     * @param consumer function that runs on all other values
     */
    public void consumeOtherValuesAndRemove(K key, Consumer consumer) {
        m.computeIfPresent(key, (k, set) -> {
            for (V v : set.otherValues)
                consumer.accept(v);
            return notReusableSet;
        });
    }

    /**
     * Runs the consumer on all other values and removes the key value mapping
     *
     * @param key      key
     * @param consumer function that runs on all other values
     */
    public void consumeOtherValues(K key, Consumer consumer) {
        m.computeIfPresent(key, (k, set) -> {
            for (V v : set.otherValues)
                consumer.accept(v);
            return set;
        });
    }

    /**
     * Clears the mapping
     */
    public void clear() {
        this.m.clear();
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy