Clover coverage report - DrJava Test Coverage (drjava-20120304-r5456)
Coverage timestamp: Sun Mar 4 2012 03:13:23 CST
file stats: LOC: 312   Methods: 36
NCLOC: 169   Classes: 3
 
 Source file Conditionals Statements Methods TOTAL
ModelList.java 75% 100% 100% 95.2%
coverage coverage
 1    /*BEGIN_COPYRIGHT_BLOCK
 2    *
 3    * Copyright (c) 2001-2010, JavaPLT group at Rice University (drjava@rice.edu)
 4    * All rights reserved.
 5    *
 6    * Redistribution and use in source and binary forms, with or without
 7    * modification, are permitted provided that the following conditions are met:
 8    * * Redistributions of source code must retain the above copyright
 9    * notice, this list of conditions and the following disclaimer.
 10    * * Redistributions in binary form must reproduce the above copyright
 11    * notice, this list of conditions and the following disclaimer in the
 12    * documentation and/or other materials provided with the distribution.
 13    * * Neither the names of DrJava, the JavaPLT group, Rice University, nor the
 14    * names of its contributors may be used to endorse or promote products
 15    * derived from this software without specific prior written permission.
 16    *
 17    * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 18    * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 19    * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 20    * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 21    * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 22    * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 23    * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 24    * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 25    * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 26    * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 27    * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 28    *
 29    * This software is Open Source Initiative approved Open Source Software.
 30    * Open Source Initative Approved is a trademark of the Open Source Initiative.
 31    *
 32    * This file is part of DrJava. Download the current version of this project
 33    * from http://www.drjava.org/ or http://sourceforge.net/projects/drjava/
 34    *
 35    * END_COPYRIGHT_BLOCK*/
 36   
 37    package edu.rice.cs.drjava.model.definitions.reducedmodel;
 38   
 39    import edu.rice.cs.plt.collect.WeakHashSet;
 40    import java.util.Set;
 41   
 42    /** A doubly-linked list class with header and trailer nodes. Allows multiple iterators to make modifications to the
 43    * same list without failing unlike the iterators for java.util.*List.
 44    * @version $Id: ModelList.java 5175 2010-01-20 08:46:32Z mgricken $
 45    */
 46    class ModelList<T> {
 47    private Node<T> _head;
 48    private Node<T> _tail;
 49    /** length of this list; supports constant time length lookup */
 50    private int _length;
 51    /** a set of objects that can trigger and listen for updates to the list */
 52    private Set<ModelIterator> _listeners;
 53   
 54    /** Constructor. Initializes the head and tail nodes, as well as the listener table and the length variable. */
 55  3191 ModelList() {
 56    // This node is the only node that exists in an empty list.
 57    // If an Iterator points to this node, the iterator is considered to be in "initial position."
 58  3191 _head = new Node<T>();
 59  3191 _tail = new Node<T>();
 60  3191 _head._prev = null;
 61  3191 _head._next = _tail;
 62  3191 _tail._prev = _head;
 63  3191 _tail._next = null;
 64  3191 _length = 0;
 65   
 66    /* We use a WeakHashSet so that listeners do not leak. That is, even if the dispose method is not called, when they
 67    * are no longer strongly referenced, they will be automatically removed from the listener set. */
 68  3191 _listeners = new WeakHashSet<ModelIterator>();
 69    }
 70   
 71  4 public void insertFront(T item) { insert(_head._next, item); }
 72   
 73    /** Insert a node immediately before the specified point. Returns the inserted node. Assumes point is not head. */
 74  14418 private Node<T> insert(Node<T> point, T item) {
 75  14418 assert point != _head;
 76  14418 Node<T> newNode = point.insert(item);
 77  14418 _length++;
 78  14418 return newNode;
 79    }
 80   
 81    /** Remove a node from the list. Assumes point is not head or tail. */
 82  478 private void remove(Node<T> point) {
 83  478 assert point != _head && point != _tail;
 84  478 point.remove();
 85  478 _length--;
 86    }
 87   
 88  62773 private void addListener(ModelIterator that) { _listeners.add(that); }
 89   
 90  32446 private void removeListener(ModelIterator that) { _listeners.remove(that); }
 91   
 92  5 public int listenerCount() { return _listeners.size(); }
 93   
 94    /** Returns true if the list is empty. */
 95  2942167 public boolean isEmpty() { return _head._next == _tail; }
 96   
 97  18 public int length() { return _length; }
 98   
 99    /** Create a new iterator for this list and register it as one of the listeners which are notified when the list is
 100    * updated.
 101    */
 102  19 public ModelIterator getIterator() { return new ModelIterator(); }
 103   
 104    /** The Node class for ModelLists. The _prev and _next pointers are mutable. The _item field is null in _head and _tail. */
 105    private static class Node<T> {
 106    Node<T> _prev;
 107    Node<T> _next;
 108    T _item;
 109   
 110    /** Constructor for _head and _tail nodes. */
 111  6382 Node() { }
 112   
 113    /** Constructor for nodes containing data. */
 114  14418 Node(T item, Node<T> pred, Node<T> succ) {
 115  14418 _item = item;
 116  14418 _prev = pred;
 117  14418 _next = succ;
 118    }
 119   
 120    /** Insert a new node before "this". Returns the new node. Assumes that "this" is not the head node. */
 121  14418 Node<T> insert(T item) {
 122  14418 assert _prev != null;
 123  14418 Node<T> newNode = new Node<T>(item, _prev, this);
 124  14418 _prev._next = newNode;
 125  14418 _prev = newNode;
 126  14418 return newNode;
 127    }
 128   
 129    /** Remove the current node. Assumes that this is neither _head not _tail. */
 130  478 void remove() {
 131  478 assert _prev != null && _next != null;
 132  478 _prev._next = _next;
 133  478 _next._prev = _prev;
 134    }
 135    }
 136   
 137    /** The iterator class for ModelList. Package private instead of private so that it can be extended. The methods of
 138    * this class constitute the only public interface for traversing and modifying ModelList objects (other than
 139    * insertFront). These iterators support concurrent modification from within the same thread. They are NOT thread
 140    * safe.
 141    */
 142    class ModelIterator {
 143    private Node<T> _point; // the current node
 144    private int _pos; // the offset of _point within the list; _head has index 0
 145   
 146    /** Standard constructor that creates an iterator pointing to the list head (_head) and adds it the listeners. */
 147  3183 public ModelIterator() {
 148  3183 _point = _head;
 149  3183 _pos = 0;
 150  3183 addListener(this);
 151    }
 152   
 153    /** Copy constructor that creates a copy of an existing iterator and adds it to the listeners. */
 154  59590 public ModelIterator(ModelIterator iter) {
 155  59590 _point = iter._point;
 156  59590 _pos = iter._pos;
 157  59590 addListener(this);
 158    }
 159   
 160  3 public ModelIterator copy() { return new ModelIterator(this); }
 161   
 162    /** Tests "that" for equality with "this". */
 163  1164 public boolean eq(ModelIterator that) { return _point == that._point; }
 164   
 165    /** Force "this" iterator to take the values of "that". */
 166  490 public void setTo(ModelIterator that) {
 167  490 _point = that._point;
 168  490 _pos = that._pos;
 169    }
 170   
 171    /** Disposes of an iterator by removing it from the listeners. If an iterator becomes unreachable, it is
 172    * automatically reclaimed as part of system garbage collection. The manual use of dispose() reduces the
 173    * cost of notifying the listeners because it reduces the size of the listener set.
 174    */
 175  32446 public void dispose() { removeListener(this); }
 176   
 177    /** Return true if we're pointing at the head.*/
 178  28016605 public boolean atStart() { return _point == _head; }
 179   
 180    /** Return true if we're pointing at the tail. */
 181  25170483 public boolean atEnd() { return _point == _tail; }
 182   
 183    /** Return true if we're pointing at the node after the head. */
 184  2949750 public boolean atFirstItem() { return _point._prev == _head; }
 185   
 186    /** Return true if we're pointing at the node before the tail. */
 187  63588 public boolean atLastItem() { return _point._next == _tail; }
 188   
 189    /** Return the item associated with the current node. */
 190  24427096 public T current() {
 191    // assert ! atStart() && ! atEnd();
 192  24427096 return _point._item;
 193    }
 194   
 195    /** Returns the item associated with the node before the current node. */
 196  2529692 public T prevItem() {
 197  2529692 assert ! atStart() && ! isEmpty() && ! atFirstItem();
 198  2529692 return _point._prev._item;
 199    }
 200   
 201    /** Returns the item associated with the node after the current node. */
 202  2 public T nextItem() {
 203  2 assert ! atStart() && ! isEmpty() && ! atLastItem();
 204  2 return _point._next._item;
 205    }
 206   
 207  11 public int pos() { return _pos; }
 208   
 209    /** Inserts an item before the current item. If current is head, we need to move to the next node
 210    * to perform the insert properly. Otherwise, we'll get a null pointer exception because the function will try
 211    * to insert the new item before the head. Ends pointing to inserted item.
 212    */
 213  14414 public void insert(T item) {
 214    //so as not to insert at head
 215  1472 if (atStart()) next();
 216  14414 _point = ModelList.this.insert(_point, item);
 217  14414 int savPos = _pos;
 218  14414 notifyOfInsert(_pos);
 219   
 220  14414 _pos = savPos; // this._pos is incremented by notify; reverse this change
 221    }
 222   
 223    /** Removes the current item from the list. Ends pointing to the node following the removed node.
 224    * Throws exception if performed atStart() or atEnd().
 225    */
 226  478 public void remove() {
 227  478 Node<T> succ = _point._next;
 228  478 ModelList.this.remove(_point);
 229  478 _point = succ;
 230  478 notifyOfRemove(_pos, succ);
 231    }
 232   
 233    /** Moves to the previous node. Throws exception atStart(). */
 234  11962563 public void prev() {
 235  11962563 assert ! atStart();
 236  11962563 _point = _point._prev;
 237  11962563 _pos--;
 238    }
 239   
 240    /** Moves to the next node. Throws exception atEnd(). */
 241  12035403 public void next() {
 242  12035403 assert ! atEnd();
 243  12035403 _point = _point._next;
 244  12035403 _pos++;
 245    }
 246   
 247    /** Delete all nodes between the current position of this and the current position of the given iterator.
 248    * 1) Two iterators pointing to same node: do nothing
 249    * 2) Iterator 2 is before iterator 1: remove between iterator 2 and iterator 1
 250    * 3) Iterator 1 is before iterator 2: remove between iterator 1 and iterator 2
 251    * Does not remove points iterators point to.
 252    */
 253  680 public void collapse(ModelIterator iter) {
 254  680 int itPos = iter._pos;
 255  680 int diff = Math.abs(_pos - itPos);
 256  389 if (diff <= 1) return; // _pos and iter.pos are either equal or adjacent
 257   
 258  291 int leftPos, rightPos;
 259  291 Node<T> leftPoint, rightPoint;
 260   
 261  291 if (_pos > itPos) {
 262  1 leftPos = itPos;
 263  1 leftPoint = iter._point;
 264  1 rightPos = _pos;
 265  1 rightPoint = _point;
 266    }
 267    else /* _pos < iter._pos */ {
 268  290 leftPos = _pos;
 269  290 leftPoint = _point;
 270  290 rightPos = itPos;
 271  290 rightPoint = iter._point;
 272    }
 273   
 274  291 rightPoint._prev = leftPoint;
 275  291 leftPoint._next = rightPoint;
 276  291 _length -= rightPos - leftPos - 1; //determine new length
 277  291 notifyOfCollapse(leftPos, rightPos, rightPoint);
 278    }
 279   
 280    /** Notifies the iterators in _listeners that a node has been inserted. */
 281  14414 private void notifyOfInsert(int pos) {
 282  14414 for (ModelIterator listener : _listeners) {
 283  33138 int lisPos = listener._pos;
 284  21799 if (lisPos >= pos) listener._pos = lisPos + 1;
 285    }
 286    }
 287   
 288    /** Notifies the iterators in _listeners that a node has been removed. */
 289  478 private void notifyOfRemove(int pos, Node<T> point) {
 290  478 for (ModelIterator listener : _listeners) {
 291  2828 int lisPos = listener._pos;
 292  556 if (lisPos == pos) listener._point = point;
 293  1403 else if (lisPos > pos) listener._pos = lisPos - 1;
 294    }
 295    }
 296   
 297    /** Notifies the iterators in _listeners that a range of nodes has been collapsed. */
 298  291 private void notifyOfCollapse(int leftPos, int rightPos, Node<T> rightPoint) {
 299  291 for (ModelIterator listener : _listeners) {
 300  1946 int lisPos = listener._pos;
 301  824 if (lisPos <= leftPos) continue;
 302  1122 if (lisPos < rightPos) {
 303  343 listener._pos = leftPos + 1;
 304  343 listener._point = rightPoint;
 305    }
 306    else { // lisPos >+ rightPos
 307  779 listener._pos = lisPos - (rightPos - leftPos - 1);
 308    }
 309    }
 310    }
 311    }
 312    }