private ImmutableList<Writer> sortedWriters() {
        ImmutableList.Builder<Writer> sorted = ImmutableList.builder();

        // invertedDependencies is intended to just be a 'view' on dependencies, so when dependencies is modified
        // we should always also modify invertedDependencies (and vice-versa).
        Multimap<Writer, Writer> dependencies = HashMultimap.create(this.dependencies);
        Multimap<Writer, Writer> invertedDependencies = HashMultimap.create();
        Multimaps.invertFrom(dependencies, invertedDependencies);

        Queue<Writer> writerWithoutDependencies =
                new ArrayDeque<>(Sets.filter(writers, property -> dependencies.get(property).isEmpty()));

        Writer property;

        // Retrieve the next property without any dependencies
        while ((property = writerWithoutDependencies.poll()) != null) {
            sorted.add(property);

            // We copy this into a new list because the underlying collection gets modified during iteration
            Collection<Writer> dependents = Lists.newArrayList(invertedDependencies.get(property));

            for (Writer dependent : dependents) {
                // Because the property has been removed, the dependent no longer needs to depend on it
                dependencies.remove(dependent, property);
                invertedDependencies.remove(property, dependent);

                boolean hasNoDependencies = dependencies.get(dependent).isEmpty();

                if (hasNoDependencies) {
                    writerWithoutDependencies.add(dependent);
                }
            }
        }

        if (!dependencies.isEmpty()) {
            // This means there must have been a loop. Pick an arbitrary remaining var to display
            Variable var = dependencies.keys().iterator().next().var();
            throw GraqlQueryException.insertRecursive(printableRepresentation(var));
        }

        return sorted.build();
    }
private ImmutableList < Writer > sortedWriters ( ) { ImmutableList . Builder < Writer > sorted = ImmutableList . builder ( ) ; Multimap < Writer , Writer > dependencies = HashMultimap . create ( this . dependencies ) ; Multimap < Writer , Writer > invertedDependencies = HashMultimap . create ( ) ; Multimaps . invertFrom ( dependencies , invertedDependencies ) ; Queue < Writer > writerWithoutDependencies = new ArrayDeque < > ( Sets . filter ( writers , property -> dependencies . get ( property ) . isEmpty ( ) ) ) ; Writer property ; while ( ( property = writerWithoutDependencies . poll ( ) ) != null ) { sorted . add ( property ) ; Collection < Writer > dependents = Lists . newArrayList ( invertedDependencies . get ( property ) ) ; for ( Writer dependent : dependents ) { dependencies . remove ( dependent , property ) ; invertedDependencies . remove ( property , dependent ) ; boolean hasNoDependencies = dependencies . get ( dependent ) . isEmpty ( ) ; if ( hasNoDependencies ) { writerWithoutDependencies . add ( dependent ) ; } } } if ( ! dependencies . isEmpty ( ) ) { Variable var = dependencies . keys ( ) . iterator ( ) . next ( ) . var ( ) ; throw GraqlQueryException . insertRecursive ( printableRepresentation ( var ) ) ; } return sorted . build ( ) ; }
Produce a valid ordering of the properties by using the given dependency information.
This method uses a topological sort (Kahn's algorithm) in order to find a valid ordering.