Clover coverage report - PLT Utilities Test Coverage (plt-20120304-r5436)
Coverage timestamp: Sat Mar 3 2012 22:01:56 CST
file stats: LOC: 143   Methods: 23
NCLOC: 68   Classes: 2
 
 Source file Conditionals Statements Methods TOTAL
SnapshotSynchronizedList.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.collect;
 36   
 37    import java.io.Serializable;
 38    import java.util.ArrayList;
 39    import java.util.Collection;
 40    import java.util.Collections;
 41    import java.util.Iterator;
 42    import java.util.List;
 43    import java.util.ListIterator;
 44   
 45    import edu.rice.cs.plt.lambda.CachedThunk;
 46    import edu.rice.cs.plt.lambda.Thunk;
 47   
 48    /**
 49    * A synchronized list like {@link Collections#synchronizedList}, but one that returns a snapshot of
 50    * the list contents on invocations of {@code iterator()}. In contrast to
 51    * {@link java.util.concurrent.CopyOnWriteArrayList}, copies are only made when needed for iteration; other
 52    * operations use locking to support concurrency. The snapshot strategy has the following advantages over
 53    * {@link Collections#synchronizedList}: 1) Thread safety during iteration is guaranteed; 2) the list is
 54    * interchangeable with other types of lists, even in contexts that perform iteration; 3) concurrent access to
 55    * the list is not blocked during iteration; and 4) the list can be directly mutated by the iteration loop
 56    * (on the other hand, removing elements via the iterator is not supported). Note, also, that operations on
 57    * this list cannot be blocked by synchronizing on the list itself. To support these differences, the
 58    * implementation must make a copy whenever {@code iterator()} is invoked after the list has been mutated;
 59    * that copy is cached with the list (optimizing the performance of subsequent calls, but doubling the
 60    * list's memory footprint).
 61    */
 62    public class SnapshotSynchronizedList<E> extends DelegatingList<E> {
 63    private final Object _lock;
 64    private final CachedThunk<List<E>> _copy;
 65   
 66  0 public SnapshotSynchronizedList(List<E> delegate) { this(Collections.synchronizedList(delegate), null); }
 67   
 68    /** The {@code lock} field may be null, indicating that {@code synchronziedDelegate} should be used. */
 69  0 private SnapshotSynchronizedList(List<E> synchronizedDelegate, Object lock) {
 70  0 super(synchronizedDelegate);
 71  0 _lock = (lock == null) ? synchronizedDelegate : lock;
 72  0 _copy = CachedThunk.make(new Thunk<List<E>>() {
 73  0 public List<E> value() {
 74  0 synchronized(_lock) { return new ArrayList<E>(_delegate); }
 75    }
 76    });
 77    }
 78   
 79    /**
 80    * Discard the cached copy of the list, if it exists. This minimizes this list's memory footprint, but
 81    * forces the copy to be recalculated when {@link #iterator} is next invoked. Has no effect if
 82    * {@code iterator()} has not been invoked since the last mutating operation.
 83    */
 84  0 public void discardSnapshot() {
 85    // to facilitate overridden behavior in subList(), this is the *only* code that should call _copy.reset()
 86  0 _copy.reset();
 87    }
 88   
 89    /** Reset the copy thunk if {@code changed} is {@code true}; return {@code changed}. */
 90  0 private boolean reset(boolean changed) {
 91  0 if (changed) { discardSnapshot(); }
 92  0 return changed;
 93    }
 94   
 95  0 @Override public Iterator<E> iterator() { return _copy.value().iterator(); }
 96  0 @Override public ListIterator<E> listIterator() { return _copy.value().listIterator(); }
 97  0 @Override public ListIterator<E> listIterator(int index) { return _copy.value().listIterator(index); }
 98   
 99  0 @Override public boolean add(E o) { return reset(_delegate.add(o)); }
 100  0 @Override public boolean addAll(Collection<? extends E> c) { return reset(_delegate.addAll(c)); }
 101  0 @Override public void clear() { _delegate.clear(); discardSnapshot(); }
 102  0 @Override public boolean remove(Object o) { return reset(_delegate.remove(o)); }
 103  0 @Override public boolean removeAll(Collection<?> c) { return reset(_delegate.removeAll(c)); }
 104  0 @Override public boolean retainAll(Collection<?> c) { return reset(_delegate.retainAll(c)); }
 105   
 106  0 @Override public void add(int index, E element) { _delegate.add(index, element); discardSnapshot(); }
 107  0 @Override public boolean addAll(int index, Collection<? extends E> c) { return reset(_delegate.addAll(index, c)); }
 108   
 109  0 @Override public E set(int index, E element) {
 110  0 E result = _delegate.set(index, element);
 111  0 discardSnapshot();
 112  0 return result;
 113    }
 114   
 115  0 @Override public E remove(int index) {
 116  0 E result = _delegate.remove(index);
 117  0 discardSnapshot();
 118  0 return result;
 119    }
 120   
 121  0 @Override public List<E> subList(final int from, int to) {
 122  0 return new SnapshotSynchronizedList<E>(_delegate.subList(from, to), _lock) {
 123  0 @Override public void discardSnapshot() {
 124    // discard both this cache and that of the outer list(s)
 125  0 SnapshotSynchronizedList.this.discardSnapshot();
 126  0 super.discardSnapshot();
 127    }
 128    };
 129    }
 130   
 131    /** Get a thunk that invokes the constructor with sets produced by the given factory. */
 132  0 public static <T> Thunk<List<T>> factory(Thunk<? extends List<T>> delegateFactory) {
 133  0 return new Factory<T>(delegateFactory);
 134    }
 135   
 136    private static final class Factory<T> implements Thunk<List<T>>, Serializable {
 137    private final Thunk<? extends List<T>> _delegateFactory;
 138  0 private Factory(Thunk<? extends List<T>> delegateFactory) { _delegateFactory = delegateFactory; }
 139  0 public List<T> value() { return new SnapshotSynchronizedList<T>(_delegateFactory.value()); }
 140    }
 141   
 142   
 143    }