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

eu.lucaventuri.collections.ClassifiedMap Maven / Gradle / Ivy

There is a newer version: 3.0.1
Show newest version
package eu.lucaventuri.collections;

import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Predicate;

/**
 * This object contains a map grouped by class and a list; so it can be accessed in both ways.
 * This object in intended to be used to filter messages based on their class and on some other attribute
 */
public class ClassifiedMap {
    private final NodeLinkedList list = new NodeLinkedList<>();
    private final ConcurrentHashMap>> mapByClass = new ConcurrentHashMap<>();

    public boolean addToTail(Object obj) {
        assert obj != null;
        verify();

        if (obj == null)
            return false;

        NodeLinkedList.Node node = list.addToTail(obj);

        mapByClass.computeIfAbsent(obj.getClass(), k -> new NodeLinkedList<>()).addToTail(node);

        verify();

        return true;
    }

    public boolean addToTailConverted(Object obj, Class convertedClass) {
        assert obj != null;
        verify();

        if (obj == null)
            return false;

        NodeLinkedList.Node node = list.addToTail(obj);

        mapByClass.computeIfAbsent(convertedClass, k -> new NodeLinkedList<>()).addToTail(node);

        verify();

        return true;
    }

    public  T peekHead() {
        verify();

        return (T) list.peekHead();
    }

    public  T removeHead() {
        verify();

        NodeLinkedList.Node n = list.removeHeadNode();

        if (n == null)
            return null;

        NodeLinkedList> classList = mapByClass.get(n.value.getClass());

        if (classList != null)
            classList.removeFirstByValue(n);

        verify();

        return (T) n.value;
    }

    private void verify() {
        assert (mapByClass.isEmpty() && list.ieEmpty()) || (!mapByClass.isEmpty() && !list.ieEmpty());
    }

    void deepVerify() {
        assert (mapByClass.size() == list.asListFromHead().size());
    }

    public  T scanAndChoose(Class cls, Predicate filter) {
        verify();
        T value = scanList(filter, mapByClass.get(cls));

        if (value!=null)
            return value;

        for (Class clz : mapByClass.keySet()) {
            if (cls!=clz && cls.isAssignableFrom(clz)) {
                value = scanList(filter, mapByClass.get(clz));

                if (value!=null)
                    return value;
            }
        }

        return null;
    }

    private  T scanList(Predicate filter, NodeLinkedList> listByClass) {
        if (listByClass==null)
            return null;

        for (NodeLinkedList.Node n : listByClass) {
            if (filter.test((T) n.value)) {
                listByClass.removeFirstByValue(n);
                list.remove(n);
                return (T) n.value;
            }
        }

        return null;
    }

    public boolean isEmpty() {
        verify();

        return list.ieEmpty();
    }

    public  K scanAndChooseAndConvert(Class cls, Predicate filter, Function converter) {
        verify();

        K value = scanAndCovertList(cls, filter, converter, mapByClass.get(cls));

        if (value != null)
            return value;

        for (Class clz : mapByClass.keySet()) {
            if (cls.isAssignableFrom(clz)) {
                value = scanAndCovertList(clz, filter, converter, mapByClass.get(clz));

                if (value != null)
                    return value;
            }
        }

        return null;
    }

    private  K scanAndCovertList(Class cls, Predicate filter, Function converter, NodeLinkedList> listByClass) {
        if (listByClass==null)
            return null;

        for (NodeLinkedList.Node n : listByClass) {
            K valueConverted = converter.apply((T) n.value);

            if (valueConverted != null && filter.test((E)valueConverted)) {
                listByClass.removeFirstByValue(n);
                list.remove(n);
                return valueConverted;
            }
        }

        return null;
    }
}