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

us.bpsm.edn.protocols.C3 Maven / Gradle / Ivy

package us.bpsm.edn.protocols;

import java.util.ArrayList;
import java.util.List;

import us.bpsm.edn.EdnException;

/**
 * Implements the C3 superclass
 * linearization algorithm.
 */
class C3 {

    /**
     * Return a linearization for the inheritance hierarchy of the
     * {@code class} {@code c}. The linearization will includes
     * interfaces as well as classes and considers {@link Object} to
     * be the ultimate superclass.
     *
     * @param c represents an actual class, not an
     *        interface. Never null.
     *
     * @return The linearization of c: never null and never empty.
     *
     * @throws EdnException if the inheritance hiearchy of {@code c}
     *         makes it impossible to compuate a consistent hierarchy
     *         for {@code c}.
     */
    static List> methodResolutionOrder(Class c) {
        try {
            List> result = mro(c);
            if (c.getSuperclass() != null) {
                result.add(Object.class);
            }
            return result;
        } catch (InconsistentHierarchy e) {
            StringBuilder b = new StringBuilder()
                .append("Unable to compute a consistent ")
                .append("method resolution order for ")
                .append(c.getName());
            if (c.equals(e.problematicClass)) {
                b.append(".");
            } else {
                b.append(" because ").append(e.problematicClass.getName())
                .append(" has no consistent method resolution order.");
            }
            throw new EdnException(b.toString());
        }
    }

    private static List> mro(Class c) throws InconsistentHierarchy {
        List>> seqsToMerge = new ArrayList>>();
        seqsToMerge.add(asList(c));
        List> supers = supers(c);
        for (Class s : supers) {
            seqsToMerge.add(mro(s));
        }
        seqsToMerge.add(supers);
        try {
            return merge(seqsToMerge);
        } catch (InconsistentHierarchy e) {
            throw new InconsistentHierarchy(c);
        }
    }

    private static List> asList(Class c) {
        List> result = new ArrayList>(1);
        result.add(c);
        return result;
    }

    private static List> supers(Class c) {
        Class sc = c.getSuperclass();
        Class[] interfaces = c.getInterfaces();
        List> result = new ArrayList>();
        if (sc != null && sc != Object.class) {
            result.add(sc);
        }
        for (Class i : interfaces) {
            result.add(i);
        }
        return result;
    }

    private static List> merge(List>> seqsToMerge)
            throws InconsistentHierarchy {
        List> result = new ArrayList>();
        while (!allAreEmpty(seqsToMerge)) {
            Class candidate = findCandidate(seqsToMerge);
            if (candidate == null) {
                throw new InconsistentHierarchy();
            }
            result.add(candidate);
            removeCandidate(seqsToMerge, candidate);
        }
        return result;
    }

    private static boolean allAreEmpty(List>> lists) {
        for (List l : lists) {
            if (!l.isEmpty()) {
                return false;
            }
        }
        return true;
    }

    private static Class findCandidate(List>> seqsToMerge) {
        for (List> seq : seqsToMerge) {
            if (!seq.isEmpty() && !occursInSomeTail(seqsToMerge, seq.get(0))) {
                return seq.get(0);
            }
        }
        return null;
    }

    private static boolean occursInSomeTail(List>> seqsToMerge,
            Object c) {
        for (List seq : seqsToMerge) {
            for (int i = 1; i < seq.size(); i++) {
                if (c.equals(seq.get(i))) {
                    return true;
                }
            }
        }
        return false;
    }

    private static void removeCandidate(List>> seqsToMerge,
            Class candidate) {
        for (List> seq : seqsToMerge) {
            if (!seq.isEmpty() && candidate.equals(seq.get(0))) {
                seq.remove(0);
            }
        }
    }

    static class InconsistentHierarchy extends Exception {
        private static final long serialVersionUID = 1L;
        Class problematicClass;

        InconsistentHierarchy(Class problematicClass) {
            super();
            this.problematicClass = problematicClass;
        }

        InconsistentHierarchy() {
            super();
        }
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy