/** * Copyright 2015 Santhosh Kumar Tekuri * * The JLibs authors license this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package jlibs.core.graph; import jlibs.core.graph.navigators.FilteredNavigator; import jlibs.core.graph.visitors.StaticVisitor; import jlibs.core.graph.walkers.PreorderWalker; import jlibs.core.io.FileNavigator; import java.io.File; import java.io.FileFilter; import java.util.ArrayDeque; import java.util.Deque; import java.util.LinkedList; import java.util.List; /** * @author Santhosh Kumar T */ public class WalkerUtil{ public static <E> void walk(Walker<E> walker, Visitor<E, Processor<E>> visitor){ while(true){ E elem = walker.next(); if(elem!=null){ Processor<E> processor = visitor.visit(elem); if(processor!=null){ if(!processor.preProcess(elem, walker.getCurrentPath())) walker.skip(); } walker.addBreakpoint(); }else if(walker.isPaused()){ walker.resume(); elem = walker.current(); Processor<E> processor = visitor.visit(elem); if(processor!=null) processor.postProcess(elem, walker.getCurrentPath()); }else return; } } public static <E> void walk(Walker<E> walker, final Processor<E> processor){ walk(walker, new StaticVisitor<E, Processor<E>>(processor)); } public static <E> List<E> topologicalSort(Sequence<E> elements, Navigator<E> navigator){ final List<E> unvisitedElements = SequenceUtil.addAll(new LinkedList<E>(), elements); Navigator<E> filteredNavigator = new FilteredNavigator<E>(navigator, new Filter<E>(){ @Override public boolean select(E elem){ return unvisitedElements.contains(elem); } }); final LinkedList<E> result = new LinkedList<E>(); while(!unvisitedElements.isEmpty()){ WalkerUtil.walk(new PreorderWalker<E>(unvisitedElements.remove(0), filteredNavigator), new Processor<E>(){ @Override public boolean preProcess(E elem, Path path){ unvisitedElements.remove(elem); return true; } @Override public void postProcess(E elem, Path path){ result.add(0, elem); } }); } for(int i=0; i<result.size(); i++){ Sequence<? extends E> seq = navigator.children(result.get(i)); for(E elem; (elem=seq.next())!=null;){ if(result.indexOf(elem)<i) throw new IllegalArgumentException("the given graph contains cycle"); } } return result; } public static <E> void print(Walker<E> walker, final Visitor<E, String> visitor){ walk(walker, new Processor<E>(){ private StringBuilder getIndentation(Path path){ Deque<Path> stack = new ArrayDeque<Path>(); while(path.getParentPath()!=null){ stack.push(path); path = path.getParentPath(); } StringBuilder indentString = new StringBuilder(); while(!stack.isEmpty()){ path = stack.pop(); if(stack.isEmpty()){ indentString.append(path.lastElem ? '`' : '|'); indentString.append("-- "); }else{ indentString.append(path.lastElem ? ' ' : '|'); indentString.append(" "); } } return indentString; } @Override public boolean preProcess(E elem, Path path){ printPending(path); String str = visitor!=null ? visitor.visit(elem) : elem.toString(); System.out.print(getIndentation(path)); int newLine = str.indexOf('\n'); if(newLine!=-1){ pending = str.substring(newLine+1); pendingPath = path; str = str.substring(0, newLine); } System.out.println(str); return true; } String pending; Path pendingPath; private void printPending(Path path){ if(pending!=null){ StringBuilder indentStr = getIndentation(path.getParentPath()==null ? pendingPath : path); if(indentStr.length()>0){ indentStr.replace(indentStr.length()-4, indentStr.length(), path.getParentPath()==null ? " " : "|"); if(path.getParentPath()==pendingPath.getParentPath()) indentStr.append(" "); } int from = 0; int index = 0; while((index=pending.indexOf('\n', from))!=-1){ System.out.print(indentStr); System.out.println(pending.substring(from, index)); from = index+1; } if(from<pending.length()){ System.out.print(indentStr); System.out.println(pending.substring(from)); } pending = null; } } @Override public void postProcess(E elem, Path path){ if(path.getParentPath()==null) printPending(path); } }); } public static void main(String[] args){ // ArraySequence<String> elements = new ArraySequence<String>("undershorts", "socks", "pants", "shoes", "watch", "belt", "shirt", "tie", "jacket"); // System.out.println(topologicalSort(elements, new Navigator<String>(){ // Map<String, Sequence<String>> map = new HashMap<String, Sequence<String>>(); // { // map.put("undershorts", new ArraySequence<String>("pants", "shoes")); // map.put("socks", new ArraySequence<String>("shoes")); // map.put("pants", new ArraySequence<String>("belt", "shoes")); // map.put("belt", new ArraySequence<String>("jacket")); // map.put("shirt", new ArraySequence<String>("tie")); // map.put("tie", new ArraySequence<String>("jacket")); // } // // @Override // public Sequence<String> children(String elem){ // Sequence<String> seq = map.get(elem); // if(seq==null) // return EmptySequence.getInstance(); // else // return seq; // } // })); print(new PreorderWalker<File>(new File("/Volumes/Softwares/Personal/jlibs/core/src"), new FileNavigator(new FileFilter(){ @Override public boolean accept(File file){ return !file.isDirectory() || !file.getName().equals(".svn"); } })), new Visitor<File, String>(){ @Override public String visit(File elem){ return elem.getName(); } }); } }