Clover coverage report - PLT Utilities Test Coverage (plt-20120304-r5436)
Coverage timestamp: Sat Mar 3 2012 22:01:56 CST
file stats: LOC: 390   Methods: 26
NCLOC: 189   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
RecursionStack4.java 0% 0% 0% 0%
coverage
 1    /*BEGIN_COPYRIGHT_BLOCK*
 2   
 3    PLT Utilities BSD License
 4   
 5    Copyright (c) 2007-2010 JavaPLT group at Rice University
 6    All rights reserved.
 7   
 8    Developed by: Java Programming Languages Team
 9    Rice University
 10    http://www.cs.rice.edu/~javaplt/
 11   
 12    Redistribution and use in source and binary forms, with or without modification, are permitted
 13    provided that the following conditions are met:
 14   
 15    - Redistributions of source code must retain the above copyright notice, this list of conditions
 16    and the following disclaimer.
 17    - Redistributions in binary form must reproduce the above copyright notice, this list of
 18    conditions and the following disclaimer in the documentation and/or other materials provided
 19    with the distribution.
 20    - Neither the name of the JavaPLT group, Rice University, nor the names of the library's
 21    contributors may be used to endorse or promote products derived from this software without
 22    specific prior written permission.
 23   
 24    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
 25    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 26    FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND
 27    CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 28    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 29    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
 30    IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 31    OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 32   
 33    *END_COPYRIGHT_BLOCK*/
 34   
 35    package edu.rice.cs.plt.recur;
 36   
 37    import java.util.LinkedList;
 38    import edu.rice.cs.plt.collect.Multiset;
 39    import edu.rice.cs.plt.collect.HashMultiset;
 40    import edu.rice.cs.plt.tuple.Quad;
 41    import edu.rice.cs.plt.tuple.IdentityQuad;
 42    import edu.rice.cs.plt.lambda.Runnable4;
 43    import edu.rice.cs.plt.lambda.Thunk;
 44    import edu.rice.cs.plt.lambda.Lambda4;
 45   
 46    /**
 47    * <p>A stack used to store the arguments of a recursive invocation in order to prevent
 48    * infinite recursion. By checking that the given arguments have not been used previously
 49    * before recurring, a client can prevent infinite recursion in some circumstances (such as
 50    * when traversing an infinite, immutable data structure).</p>
 51    *
 52    * <p>The client may either choose to explicity check for containment, {@link #push} the
 53    * arguments, recur, and then {@link #pop}, or invoke one of a variety of lambda-based
 54    * methods that perform these bookkeeping tasks automatically. In the latter case, when an
 55    * exception occurs between a {@code push} and a matching {@code pop}, the {@code pop} is
 56    * guaranteed to execute before the exception propagates upward. Thus, clients who do not
 57    * directly invoke {@link #push} and {@link #pop} may assume that the stack is always in a
 58    * consistent state.</p>
 59    *
 60    * @see PrecomputedRecursionStack4
 61    * @see RecursionStack
 62    * @see RecursionStack2
 63    * @see RecursionStack3
 64    */
 65    public class RecursionStack4<T1, T2, T3, T4> {
 66   
 67    private final Lambda4<? super T1, ? super T2, ? super T3, ? super T4,
 68    ? extends Quad<T1, T2, T3, T4>> _quadFactory;
 69    private final Multiset<Quad<T1, T2, T3, T4>> _previous;
 70    private final LinkedList<Quad<T1, T2, T3, T4>> _stack;
 71   
 72    /** Create an empty recursion stack with an {@link IdentityQuad} factory */
 73  0 public RecursionStack4() { this(IdentityQuad.<T1, T2, T3, T4>factory()); }
 74   
 75    /**
 76    * Create an empty recursion stack with the given {@code Quad} factory
 77    * @param quadFactory A lambda used to produce a quad for values placed on the
 78    * stack. This provides clients with control over the method used
 79    * to determine if a value has been seen previously.
 80    */
 81  0 public RecursionStack4(Lambda4<? super T1, ? super T2, ? super T3, ? super T4,
 82    ? extends Quad<T1, T2, T3, T4>> quadFactory) {
 83  0 _quadFactory = quadFactory;
 84  0 _previous = new HashMultiset<Quad<T1, T2, T3, T4>>();
 85  0 _stack = new LinkedList<Quad<T1, T2, T3, T4>>();
 86    }
 87   
 88    /**
 89    * @return {@code true} iff a set of values identical (according to {@code ==}) to the
 90    * given arguments is currently on the stack
 91    */
 92  0 public boolean contains(T1 arg1, T2 arg2, T3 arg3, T4 arg4) {
 93  0 return _previous.contains(_quadFactory.value(arg1, arg2, arg3, arg4));
 94    }
 95   
 96    /**
 97    * @return {@code true} iff at least {@code threshold} sets of values identical
 98    * (according to {@code ==}) to the given arguments are currently on the stack
 99    */
 100  0 public boolean contains(T1 arg1, T2 arg2, T3 arg3, T4 arg4, int threshold) {
 101  0 return _previous.count(_quadFactory.value(arg1, arg2, arg3, arg4)) >= threshold;
 102    }
 103   
 104    /** Add the given arguments to the top of the stack */
 105  0 public void push(T1 arg1, T2 arg2, T3 arg3, T4 arg4) {
 106  0 Quad<T1, T2, T3, T4> wrapped = _quadFactory.value(arg1, arg2, arg3, arg4);
 107  0 _stack.addLast(wrapped);
 108  0 _previous.add(wrapped);
 109    }
 110   
 111    /**
 112    * Remove the given arguments from the top of the stack
 113    * @throws IllegalArgumentException If the given arguments are not at the top of the stack
 114    */
 115  0 public void pop(T1 arg1, T2 arg2, T3 arg3, T4 arg4) {
 116  0 Quad<T1, T2, T3, T4> wrapped = _quadFactory.value(arg1, arg2, arg3, arg4);
 117  0 if (_stack.isEmpty() || !_stack.getLast().equals(wrapped)) {
 118  0 throw new IllegalArgumentException("given args are not on top of the stack");
 119    }
 120  0 _stack.removeLast();
 121  0 _previous.remove(wrapped);
 122    }
 123   
 124    /** @return The current size (depth) of the stack */
 125  0 public int size() { return _stack.size(); }
 126   
 127    /** @return {@code true} iff the stack is currently empty */
 128  0 public boolean isEmpty() { return _stack.isEmpty(); }
 129   
 130    /**
 131    * Run the given runnable, unless the given arguments are already on the stack; push the
 132    * arguments onto the stack during runnable execution
 133    */
 134  0 public void run(Runnable r, T1 arg1, T2 arg2, T3 arg3, T4 arg4) {
 135  0 if (!contains(arg1, arg2, arg3, arg4)) {
 136  0 push(arg1, arg2, arg3, arg4);
 137  0 try { r.run(); }
 138  0 finally { pop(arg1, arg2, arg3, arg4); }
 139    }
 140    }
 141   
 142    /**
 143    * Run the given runnable, unless {@code threshold} instances of the given arguments are
 144    * already on the stack; push the arguments onto the stack during runnable execution
 145    */
 146  0 public void run(Runnable r, T1 arg1, T2 arg2, T3 arg3, T4 arg4, int threshold) {
 147  0 if (!contains(arg1, arg2, arg3, arg4, threshold)) {
 148  0 push(arg1, arg2, arg3, arg4);
 149  0 try { r.run(); }
 150  0 finally { pop(arg1, arg2, arg3, arg4); }
 151    }
 152    }
 153   
 154    /**
 155    * If the given arguments are not on the stack, run {@code r}; otherwise, run
 156    * {@code infiniteCase}. In either case, push the arguments onto the stack during
 157    * runnable execution.
 158    */
 159  0 public void run(Runnable r, Runnable infiniteCase, T1 arg1, T2 arg2, T3 arg3, T4 arg4) {
 160  0 Runnable toRun = (contains(arg1, arg2, arg3, arg4) ? infiniteCase : r);
 161  0 push(arg1, arg2, arg3, arg4);
 162  0 try { toRun.run(); }
 163  0 finally { pop(arg1, arg2, arg3, arg4); }
 164    }
 165   
 166    /**
 167    * If less than {@code threshold} instances of the given arguments are on the stack, run
 168    * {@code r}; otherwise, run {@code infiniteCase}. In either case, push the
 169    * arguments onto the stack during runnable execution.
 170    */
 171  0 public void run(Runnable r, Runnable infiniteCase, T1 arg1, T2 arg2, T3 arg3, T4 arg4, int threshold) {
 172  0 Runnable toRun = (contains(arg1, arg2, arg3, arg4, threshold) ? infiniteCase : r);
 173  0 push(arg1, arg2, arg3, arg4);
 174  0 try { toRun.run(); }
 175  0 finally { pop(arg1, arg2, arg3, arg4); }
 176    }
 177   
 178    /**
 179    * Run the given runnable with the given arguments, unless the arguments are already on the
 180    * stack; push the arguments onto the stack during runnable execution
 181    */
 182  0 public <V1 extends T1, V2 extends T2, V3 extends T3, V4 extends T4>
 183    void run(Runnable4<? super V1, ? super V2, ? super V3, ? super V4> r, V1 arg1, V2 arg2,
 184    V3 arg3, V4 arg4) {
 185  0 if (!contains(arg1, arg2, arg3, arg4)) {
 186  0 push(arg1, arg2, arg3, arg4);
 187  0 try { r.run(arg1, arg2, arg3, arg4); }
 188  0 finally { pop(arg1, arg2, arg3, arg4); }
 189    }
 190    }
 191   
 192    /**
 193    * Run the given runnable with the given arguments, unless {@code threshold} instances
 194    * of the arguments are already on the stack; push the arguments onto the stack during
 195    * runnable execution
 196    */
 197  0 public <V1 extends T1, V2 extends T2, V3 extends T3, V4 extends T4>
 198    void run(Runnable4<? super V1, ? super V2, ? super V3, ? super V4> r, V1 arg1, V2 arg2,
 199    V3 arg3, V4 arg4, int threshold) {
 200  0 if (!contains(arg1, arg2, arg3, arg4, threshold)) {
 201  0 push(arg1, arg2, arg3, arg4);
 202  0 try { r.run(arg1, arg2, arg3, arg4); }
 203  0 finally { pop(arg1, arg2, arg3, arg4); }
 204    }
 205    }
 206   
 207    /**
 208    * If the given arguments are not on the stack, run {@code r} with argument the arguments;
 209    * otherwise, run {@code infiniteCase}. In either case, push the arguments onto the
 210    * stack during runnable execution.
 211    */
 212  0 public <V1 extends T1, V2 extends T2, V3 extends T3, V4 extends T4>
 213    void run(Runnable4<? super V1, ? super V2, ? super V3, ? super V4> r,
 214    Runnable4<? super V1, ? super V2, ? super V3, ? super V4> infiniteCase,
 215    V1 arg1, V2 arg2, V3 arg3, V4 arg4) {
 216    // The javac type checker is broken here
 217  0 @SuppressWarnings("unchecked") Runnable4<? super V1, ? super V2, ? super V3, ? super V4> toRun =
 218    (Runnable4<? super V1, ? super V2, ? super V3, ? super V4>)
 219  0 (contains(arg1, arg2, arg3, arg4) ? infiniteCase : r);
 220  0 push(arg1, arg2, arg3, arg4);
 221  0 try { toRun.run(arg1, arg2, arg3, arg4); }
 222  0 finally { pop(arg1, arg2, arg3, arg4); }
 223    }
 224   
 225    /**
 226    * If less than {@code threshold} instances of the given arguments are on the stack,
 227    * run {@code r} with the arguments; otherwise, run {@code infiniteCase}. In either case,
 228    * push the arguments onto the stack during runnable execution.
 229    */
 230  0 public <V1 extends T1, V2 extends T2, V3 extends T3, V4 extends T4>
 231    void run(Runnable4<? super V1, ? super V2, ? super V3, ? super V4> r,
 232    Runnable4<? super V1, ? super V2, ? super V3, ? super V4> infiniteCase,
 233    V1 arg1, V2 arg2, V3 arg3, V4 arg4, int threshold) {
 234    // The javac type checker is broken here
 235  0 @SuppressWarnings("unchecked") Runnable4<? super V1, ? super V2, ? super V3, ? super V4> toRun =
 236    (Runnable4<? super V1, ? super V2, ? super V3, ? super V4>)
 237  0 (contains(arg1, arg2, arg3, arg4, threshold) ? infiniteCase : r);
 238  0 push(arg1, arg2, arg3, arg4);
 239  0 try { toRun.run(arg1, arg2, arg3, arg4); }
 240  0 finally { pop(arg1, arg2, arg3, arg4); }
 241    }
 242   
 243    /**
 244    * Evaluate the given thunk, unless the given arguments are already on the stack; push
 245    * the arguments onto the stack during thunk evaluation
 246    *
 247    * @return The value of {@code thunk}, or {@code infiniteCase}
 248    */
 249  0 public <R> R apply(Thunk<? extends R> thunk, R infiniteCase, T1 arg1, T2 arg2, T3 arg3, T4 arg4) {
 250  0 if (!contains(arg1, arg2, arg3, arg4)) {
 251  0 push(arg1, arg2, arg3, arg4);
 252  0 try { return thunk.value(); }
 253  0 finally { pop(arg1, arg2, arg3, arg4); }
 254    }
 255  0 else { return infiniteCase; }
 256    }
 257   
 258    /**
 259    * Evaluate the given thunk, unless {@code threshold} instances of the given arguments are
 260    * already on the stack; push the arguments onto the stack during thunk evaluation
 261    *
 262    * @return The value of {@code thunk}, or {@code infiniteCase}
 263    */
 264  0 public <R> R apply(Thunk<? extends R> thunk, R infiniteCase, T1 arg1, T2 arg2, T3 arg3, T4 arg4,
 265    int threshold) {
 266  0 if (!contains(arg1, arg2, arg3, arg4, threshold)) {
 267  0 push(arg1, arg2, arg3, arg4);
 268  0 try { return thunk.value(); }
 269  0 finally { pop(arg1, arg2, arg3, arg4); }
 270    }
 271  0 else { return infiniteCase; }
 272    }
 273   
 274    /**
 275    * If the given arguments are not on the stack, evaluate {@code thunk}; otherwise, evaluate
 276    * {@code infiniteCase}. In either case, push the arguments onto the stack during
 277    * thunk evaluation.
 278    *
 279    * @return The value of {@code thunk}, or the value of {@code infiniteCase}
 280    */
 281  0 public <R> R apply(Thunk<? extends R> thunk, Thunk<? extends R> infiniteCase, T1 arg1,
 282    T2 arg2, T3 arg3, T4 arg4) {
 283  0 Thunk<? extends R> toApply = (contains(arg1, arg2, arg3, arg4) ? infiniteCase : thunk);
 284  0 push(arg1, arg2, arg3, arg4);
 285  0 try { return toApply.value(); }
 286  0 finally { pop(arg1, arg2, arg3, arg4); }
 287    }
 288   
 289    /**
 290    * If less than {@code threshold} instances of the given arguments are on the stack,
 291    * evaluate {@code thunk}; otherwise, evaluate {@code infiniteCase}. In either case, push
 292    * the arguments onto the stack during thunk evaluation.
 293    *
 294    * @return The value of {@code thunk}, or the value of {@code infiniteCase}
 295    */
 296  0 public <R> R apply(Thunk<? extends R> thunk, Thunk<? extends R> infiniteCase, T1 arg1,
 297    T2 arg2, T3 arg3, T4 arg4, int threshold) {
 298  0 Thunk<? extends R> toApply = (contains(arg1, arg2, arg3, arg4, threshold) ? infiniteCase : thunk);
 299  0 push(arg1, arg2, arg3, arg4);
 300  0 try { return toApply.value(); }
 301  0 finally { pop(arg1, arg2, arg3, arg4); }
 302    }
 303   
 304    /**
 305    * Evaluate the given lambda with the given arguments, unless the arguments are already on
 306    * the stack; push the arguments onto the stack during lambda evaluation
 307    *
 308    * @return The value of {@code lambda}, or {@code infiniteCase}
 309    */
 310  0 public <V1 extends T1, V2 extends T2, V3 extends T3, V4 extends T4, R>
 311    R apply(Lambda4<? super V1, ? super V2, ? super V3, ? super V4, ? extends R> lambda,
 312    R infiniteCase, V1 arg1, V2 arg2, V3 arg3, V4 arg4) {
 313  0 if (!contains(arg1, arg2, arg3, arg4)) {
 314  0 push(arg1, arg2, arg3, arg4);
 315  0 try { return lambda.value(arg1, arg2, arg3, arg4); }
 316  0 finally { pop(arg1, arg2, arg3, arg4); }
 317    }
 318  0 else { return infiniteCase; }
 319    }
 320   
 321    /**
 322    * Evaluate the given lambda with the given arguments, unless {@code threshold} instances
 323    * of the arguments are already on the stack; push the arguments onto the stack
 324    * during lambda evaluation
 325    *
 326    * @return The value of {@code lambda}, or {@code infiniteCase}
 327    */
 328  0 public <V1 extends T1, V2 extends T2, V3 extends T3, V4 extends T4, R>
 329    R apply(Lambda4<? super V1, ? super V2, ? super V3, ? super V4, ? extends R> lambda,
 330    R infiniteCase, V1 arg1, V2 arg2, V3 arg3, V4 arg4, int threshold) {
 331  0 if (!contains(arg1, arg2, arg3, arg4, threshold)) {
 332  0 push(arg1, arg2, arg3, arg4);
 333  0 try { return lambda.value(arg1, arg2, arg3, arg4); }
 334  0 finally { pop(arg1, arg2, arg3, arg4); }
 335    }
 336  0 else { return infiniteCase; }
 337    }
 338   
 339    /**
 340    * If the given arguments are not on the stack, evaluate {@code lambda} with the arguments;
 341    * otherwise, evaluate {@code infiniteCase}. In either case, push the arguments onto the
 342    * stack during lambda evaluation.
 343    *
 344    * @return The value of {@code lambda}, or the value of {@code infiniteCase}
 345    */
 346  0 public <V1 extends T1, V2 extends T2, V3 extends T3, V4 extends T4, R>
 347    R apply(Lambda4<? super V1, ? super V2, ? super V3, ? super V4, ? extends R> lambda,
 348    Lambda4<? super V1, ? super V2, ? super V3, ? super V4, ? extends R> infiniteCase,
 349    V1 arg1, V2 arg2, V3 arg3, V4 arg4) {
 350    // The javac type checker is broken here
 351  0 @SuppressWarnings("unchecked") Lambda4<? super V1, ? super V2, ? super V3, ? super V4, ? extends R> toApply =
 352    (Lambda4<? super V1, ? super V2, ? super V3, ? super V4, ? extends R>)
 353  0 (contains(arg1, arg2, arg3, arg4) ? infiniteCase : lambda);
 354  0 push(arg1, arg2, arg3, arg4);
 355  0 try { return toApply.value(arg1, arg2, arg3, arg4); }
 356  0 finally { pop(arg1, arg2, arg3, arg4); }
 357    }
 358   
 359    /**
 360    * If less than {@code threshold} instances of the given arguments are on the stack,
 361    * evaluate {@code lambda} with the arguments; otherwise, evaluate {@code infiniteCase}.
 362    * In either case, push the arguments onto the stack during lambda evaluation.
 363    *
 364    * @return The value of {@code lambda}, or the value of {@code infiniteCase}
 365    */
 366  0 public <V1 extends T1, V2 extends T2, V3 extends T3, V4 extends T4, R>
 367    R apply(Lambda4<? super V1, ? super V2, ? super V3, ? super V4, ? extends R> lambda,
 368    Lambda4<? super V1, ? super V2, ? super V3, ? super V4, ? extends R> infiniteCase,
 369    V1 arg1, V2 arg2, V3 arg3, V4 arg4, int threshold) {
 370    // The javac type checker is broken here
 371  0 @SuppressWarnings("unchecked") Lambda4<? super V1, ? super V2, ? super V3, ? super V4, ? extends R> toApply =
 372    (Lambda4<? super V1, ? super V2, ? super V3, ? super V4, ? extends R>)
 373  0 (contains(arg1, arg2, arg3, arg4, threshold) ? infiniteCase : lambda);
 374  0 push(arg1, arg2, arg3, arg4);
 375  0 try { return toApply.value(arg1, arg2, arg3, arg4); }
 376  0 finally { pop(arg1, arg2, arg3, arg4); }
 377    }
 378   
 379    /** Call the constructor (allows the type arguments to be inferred) */
 380  0 public static <T1, T2, T3, T4> RecursionStack4<T1, T2, T3, T4> make() {
 381  0 return new RecursionStack4<T1, T2, T3, T4>();
 382    }
 383   
 384    /** Call the constructor (allows the type arguments to be inferred) */
 385  0 public static <T1, T2, T3, T4> RecursionStack4<T1, T2, T3, T4>
 386    make(Lambda4<? super T1, ? super T2, ? super T3, ? super T4, ? extends Quad<T1, T2, T3, T4>> quadFactory) {
 387  0 return new RecursionStack4<T1, T2, T3, T4>(quadFactory);
 388    }
 389   
 390    }