| Author | Dave Jarvis <email> |
|---|---|
| Date | 2015-03-27 21:30:35 GMT-0700 |
| Commit | 83e78af3bd7f775ac9faefa89a316156d175d70c |
| Parent | 31c2e4e |
| package com.whitemagicsoftware.rxm; | ||
| -import java.util.LinkedList; | ||
| +import java.util.ArrayList; | ||
| +import java.util.Iterator; | ||
| import static java.lang.System.out; | ||
| /** | ||
| * Provides the ability to determine the index whereat two lists begin | ||
| * to differ in content. Both this list and the list to comapre against | ||
| - * must not contain null strings. | ||
| + * must not contain null objects. | ||
| */ | ||
| -public class DivergentList extends LinkedList<String> { | ||
| +public class DivergentList<E> extends ArrayList<E> { | ||
| /** | ||
| - * Answers the index at which the strings within this list differ from | ||
| - * the strings in the given list. | ||
| + * Determines the index at which the objects within this list differ from | ||
| + * the objects in the given list. | ||
| * | ||
| * @param list The list to compare against. | ||
| * | ||
| - * @return -1 if the lists have no common strings. | ||
| + * @return -1 if the lists have no equal objects. | ||
| */ | ||
| - public int diverges( DivergentList list ) { | ||
| + public int diverges( DivergentList<E> list ) { | ||
| int index = -1; | ||
| + boolean smaller = list.size() < this.size(); | ||
| - if( valid( list ) && valid( this ) ) { | ||
| - while( equals( list, ++index ) ); | ||
| - } | ||
| + Iterator<E> iFew = (smaller ? list : this).iterator(); | ||
| - return index; | ||
| - } | ||
| + for( E e : (smaller ? this : list) ) { | ||
| + index++; | ||
| - /** | ||
| - * Answers whether the element at the given index is the same in both | ||
| - * lists. This is not null-safe. | ||
| - * | ||
| - * @param list The list to compare against this list. | ||
| - * @return true The lists have the same string at the given index. | ||
| - */ | ||
| - private boolean equals( DivergentList list, int index ) { | ||
| - return (index < size()) && (index < list.size()) && | ||
| - get( index ).equals( list.get( index ) ); | ||
| - } | ||
| + if( !(iFew.hasNext() && e.equals( iFew.next() )) ) { | ||
| + break; | ||
| + } | ||
| + } | ||
| - /** | ||
| - * Answers whether the given element path contains at least one | ||
| - * string. | ||
| - * | ||
| - * @param list The list that must have at least one string. | ||
| - * @return true The list has at least one element. | ||
| - */ | ||
| - private boolean valid( DivergentList list ) { | ||
| - return list != null && list.size() > 0; | ||
| + return index; | ||
| } | ||
| /** | ||
| - * Test the functionality. | ||
| + * Testing. | ||
| */ | ||
| public static void main( String args[] ) { | ||
| - DivergentList list1 = new DivergentList(); | ||
| - list1.addLast( "name" ); | ||
| - list1.addLast( "first" ); | ||
| - list1.addLast( "middle" ); | ||
| - list1.addLast( "last" ); | ||
| - list1.addLast( "maiden" ); | ||
| + DivergentList<String> list1 = new DivergentList<String>(); | ||
| + list1.add( "name" ); | ||
| + list1.add( "first" ); | ||
| + list1.add( "middle" ); | ||
| + list1.add( "last" ); | ||
| + list1.add( "maiden" ); | ||
| - DivergentList list2 = new DivergentList(); | ||
| - list2.addLast( "name" ); | ||
| - list2.addLast( "middle" ); | ||
| - list2.addLast( "last" ); | ||
| + DivergentList<String> list2 = new DivergentList<String>(); | ||
| + list2.add( "name" ); | ||
| + list2.add( "middle" ); | ||
| + list2.add( "last" ); | ||
| // Prints 1 | ||
| out.println( list2.diverges( list1 ) ); | ||
| list1.clear(); | ||
| - list1.addLast( "name" ); | ||
| - list1.addLast( "middle" ); | ||
| - list1.addLast( "last" ); | ||
| + list1.add( "name" ); | ||
| + list1.add( "middle" ); | ||
| + list1.add( "last" ); | ||
| list2.clear(); | ||
| - list2.addLast( "name" ); | ||
| - list2.addLast( "middle" ); | ||
| - list2.addLast( "last" ); | ||
| - list2.addLast( "maiden" ); | ||
| - list2.addLast( "honorific" ); | ||
| + list2.add( "name" ); | ||
| + list2.add( "middle" ); | ||
| + list2.add( "last" ); | ||
| + list2.add( "maiden" ); | ||
| + list2.add( "honorific" ); | ||
| // Prints 3 | ||
| out.println( list1.diverges( list2 ) ); | ||
| - list2.addFirst( "name" ); | ||
| + list2.add( 0, "name" ); | ||
| // Prints 1 | ||
| + out.println( list1.diverges( list2 ) ); | ||
| + | ||
| + list1.clear(); | ||
| + list1.add( "name" ); | ||
| + list1.add( "middle" ); | ||
| + list1.add( "last" ); | ||
| + list1.add( "maiden" ); | ||
| + list1.add( "honorific" ); | ||
| + | ||
| + list2.clear(); | ||
| + list2.add( "name" ); | ||
| + list2.add( "middle" ); | ||
| + list2.add( "last" ); | ||
| + list2.add( "maiden" ); | ||
| + list2.add( "honorific" ); | ||
| + | ||
| + // Prints 4 | ||
| out.println( list1.diverges( list2 ) ); | ||
| } | ||
| +package com.whitemagicsoftware.rxm; | ||
| + | ||
| +import java.util.Iterator; | ||
| + | ||
| +/** | ||
| + * Provides look-ahead abilities for an iterator. | ||
| + */ | ||
| +public class PeekingIterator<E> implements Iterator<E> { | ||
| + private final Iterator<? extends E> iterator; | ||
| + | ||
| + private boolean peekNext; | ||
| + private E elementNext; | ||
| + | ||
| + /** | ||
| + * Constructs an iterator with look-ahead abilities for a given iterator. | ||
| + * | ||
| + * @param iterator The iterator to adorn with look-ahead abilities. | ||
| + */ | ||
| + public PeekingIterator( Iterator<? extends E> iterator ) { | ||
| + this.iterator = iterator; | ||
| + } | ||
| + | ||
| + /** | ||
| + * Answers whether there are more elements to iterate. | ||
| + * | ||
| + * @return true There is another element to iterate. | ||
| + */ | ||
| + @Override | ||
| + public boolean hasNext() { | ||
| + return getPeekedNext() || getIterator().hasNext(); | ||
| + } | ||
| + | ||
| + /** | ||
| + * Returns the next element in the list. If peek was called before | ||
| + * this method, then this method will return the peeked value. | ||
| + * | ||
| + * @return The next element. | ||
| + */ | ||
| + @Override | ||
| + public E next() { | ||
| + return getPeekedNext() ? reset() : iteratorNext(); | ||
| + } | ||
| + | ||
| + /** | ||
| + * Resets the peeked next state to false and sets the next peeked element | ||
| + * to null. | ||
| + * | ||
| + * @return The peeked next element. | ||
| + */ | ||
| + private E reset() { | ||
| + E result = getElementNext(); | ||
| + setPeekedNext( false ); | ||
| + setElementNext( null ); | ||
| + | ||
| + return result; | ||
| + } | ||
| + | ||
| + /** | ||
| + * Attempts to remove the currently iterated element. This will throw | ||
| + * an exception when trying to remove an element after peeking. This is | ||
| + * because next() has already been called on the underlying iterator. | ||
| + */ | ||
| + @Override | ||
| + public void remove() { | ||
| + if( getPeekedNext() ) { | ||
| + throw new UnsupportedOperationException( "No removing after peeking." ); | ||
| + } | ||
| + | ||
| + getIterator().remove(); | ||
| + } | ||
| + | ||
| + /** | ||
| + * Returns the next element to iterate. Note that peeking prevents | ||
| + * removal. | ||
| + * | ||
| + * @return The next element in the iterator's list. | ||
| + */ | ||
| + public E peek() { | ||
| + if( !getPeekedNext() ) { | ||
| + setElementNext( iteratorNext() ); | ||
| + setPeekedNext( true ); | ||
| + } | ||
| + | ||
| + return getElementNext(); | ||
| + } | ||
| + | ||
| + private E iteratorNext() { | ||
| + return getIterator().next(); | ||
| + } | ||
| + | ||
| + private E getElementNext() { | ||
| + return this.elementNext; | ||
| + } | ||
| + | ||
| + private void setElementNext( E elementNext ) { | ||
| + this.elementNext = elementNext; | ||
| + } | ||
| + | ||
| + private boolean getPeekedNext() { | ||
| + return this.peekNext; | ||
| + } | ||
| + | ||
| + private void setPeekedNext( boolean peekNext ) { | ||
| + this.peekNext = peekNext; | ||
| + } | ||
| + | ||
| + private Iterator<? extends E> getIterator() { | ||
| + return this.iterator; | ||
| + } | ||
| +} | ||
| + | ||
| import java.util.ArrayList; | ||
| +import java.util.Iterator; | ||
| import java.util.List; | ||
| +import com.whitemagicsoftware.rxm.PeekingIterator; | ||
| import com.whitemagicsoftware.rxm.Tree; | ||
| sb.append( indent ).append( start( tree ) ); | ||
| - for( Tree<Context> branch : tree.getBranches() ) { | ||
| + // Immediately previous column map (if any). | ||
| + ColumnMapContext priorColumnMap = null; | ||
| + List<Tree<Context>> branches = tree.getBranches(); | ||
| + PeekingIterator<Tree<Context>> i = createIterator( branches.iterator() ); | ||
| + | ||
| + while( i.hasNext() ) { | ||
| + Tree<Context> branch = i.next(); | ||
| Context context = branch.getPayload(); | ||
| if( context instanceof AttributeMapContext ) { | ||
| - AttributeMapContext ctx = (AttributeMapContext)context; | ||
| Tree<Context> parent = branch.getParent(); | ||
| + AttributeMapContext ctx = (AttributeMapContext)context; | ||
| ctx.hasPrecedingPayload( hasPrecedingPayload( parent, ctx ) ); | ||
| ctx.hasFollowingPayload( hasFollowingPayload( parent, ctx ) ); | ||
| } | ||
| else if( context instanceof ColumnMapContext ) { | ||
| - // nothing. | ||
| + if( i.hasNext() ) { | ||
| + Tree<Context> next = i.peek(); | ||
| + | ||
| + Context nextContext = next.getPayload(); | ||
| + | ||
| + if( nextContext instanceof ColumnMapContext ) { | ||
| + System.out.println( "NEXT!" + nextContext.toString() ); | ||
| + } | ||
| + } | ||
| + | ||
| + /* | ||
| + if( priorColumnMap != null ) { | ||
| + ((ColumnMapContext)context).setPrevious( priorColumnMap ); | ||
| + } | ||
| + | ||
| + priorColumnMap = context; | ||
| + */ | ||
| } | ||
| protected String stop( Context payload ) { | ||
| return payload.getStop(); | ||
| + } | ||
| + | ||
| + | ||
| + private PeekingIterator<Tree<Context>> createIterator( | ||
| + Iterator<Tree<Context>> iterator ) { | ||
| + return new PeekingIterator<Tree<Context>>( iterator ); | ||
| } | ||
| Delta | 198 lines added, 55 lines removed, 143-line increase |
|---|