Coverage Report - org.jdom2.ContentList
 
Classes in this File Line Coverage Branch Coverage Complexity
ContentList
100%
178/178
98%
87/88
3.4
ContentList$1
N/A
N/A
3.4
ContentList$CLIterator
100%
22/22
100%
10/10
3.4
ContentList$CLListIterator
100%
60/60
100%
28/28
3.4
ContentList$FilterList
99%
131/132
96%
79/82
3.4
ContentList$FilterListIterator
100%
65/65
100%
34/34
3.4
 
 1  
 /*--
 2  
 
 3  
  Copyright (C) 2000-2012 Jason Hunter & Brett McLaughlin.
 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
 8  
  are met:
 9  
 
 10  
  1. Redistributions of source code must retain the above copyright
 11  
     notice, this list of conditions, and the following disclaimer.
 12  
 
 13  
  2. Redistributions in binary form must reproduce the above copyright
 14  
     notice, this list of conditions, and the disclaimer that follows
 15  
     these conditions in the documentation and/or other materials
 16  
     provided with the distribution.
 17  
 
 18  
  3. The name "JDOM" must not be used to endorse or promote products
 19  
     derived from this software without prior written permission.  For
 20  
     written permission, please contact <request_AT_jdom_DOT_org>.
 21  
 
 22  
  4. Products derived from this software may not be called "JDOM", nor
 23  
     may "JDOM" appear in their name, without prior written permission
 24  
     from the JDOM Project Management <request_AT_jdom_DOT_org).
 25  
 
 26  
  In addition, we request (but do not require) that you include in the
 27  
  end-user documentation provided with the redistribution and/or in the
 28  
  software itself an acknowledgement equivalent to the following:
 29  
      "This product includes software developed by the
 30  
       JDOM Project (http://www.jdom.org/)."
 31  
  Alternatively, the acknowledgment may be graphical using the logos
 32  
  available at http://www.jdom.org/images/logos.
 33  
 
 34  
  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 35  
  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 36  
  OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 37  
  DISCLAIMED.  IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
 38  
  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 39  
  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 40  
  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 41  
  USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 42  
  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 43  
  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 44  
  OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 45  
  SUCH DAMAGE.
 46  
 
 47  
  This software consists of voluntary contributions made by many
 48  
  individuals on behalf of the JDOM Project and was originally
 49  
  created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
 50  
  Brett McLaughlin <brett_AT_jdom_DOT_org>.  For more information
 51  
  on the JDOM Project, please see <http://www.jdom.org/>.
 52  
 
 53  
  */
 54  
 
 55  
 package org.jdom2;
 56  
 
 57  
 import java.util.*;
 58  
 
 59  
 import org.jdom2.filter.*;
 60  
 import org.jdom2.internal.ArrayCopy;
 61  
 
 62  
 /**
 63  
  * A non-public list implementation holding only legal JDOM content, including
 64  
  * content for Document or Element nodes. Users see this class as a simple List
 65  
  * implementation.
 66  
  *
 67  
  * @see DocType
 68  
  * @see CDATA
 69  
  * @see Comment
 70  
  * @see Element
 71  
  * @see EntityRef
 72  
  * @see ProcessingInstruction
 73  
  * @see Text
 74  
  * @author Alex Rosen
 75  
  * @author Philippe Riand
 76  
  * @author Bradley S. Huffman
 77  
  * @author Rolf Lear
 78  
  */
 79  2764571
 final class ContentList extends AbstractList<Content>
 80  
                 implements RandomAccess {
 81  
 
 82  
         private static final int INITIAL_ARRAY_SIZE = 4;
 83  
 
 84  
         /** Our backing list */
 85  13973
         private Content elementData[] = null;
 86  
         
 87  
         /** The amount of valid content in elementData */
 88  
         private int size;
 89  
         
 90  
         /**
 91  
          * Completely remove references to AbstractList.modCount because in
 92  
          * ContentList it is confusing. As a consequence we also need to implement
 93  
          * a custom ListIterator for ContentList so that we don't use any of the
 94  
          * AbstractList iterators which use modCount.... so we have our own 
 95  
          * ConcurrentModification checking.
 96  
          * 
 97  
          */
 98  13973
         private transient int sizeModCount = Integer.MIN_VALUE;
 99  
 
 100  
         /**
 101  
          * modCount is used for concurrent modification, but dataModCount is used
 102  
          * for refreshing filters.
 103  
          */
 104  13973
         private transient int dataModiCount = Integer.MIN_VALUE;
 105  
 
 106  
         /** Document or Element this list belongs to */
 107  
         private final Parent parent;
 108  
 
 109  
         /**
 110  
          * Force either a Document or Element parent
 111  
          * 
 112  
          * @param parent
 113  
          *        the Element this ContentList belongs to.
 114  
          */
 115  13973
         ContentList(final Parent parent) {
 116  13973
                 this.parent = parent;
 117  13973
         }
 118  
         
 119  
         /**
 120  
          * Package internal method to support building from sources that are 100%
 121  
          * trusted.
 122  
          * 
 123  
          * @param c
 124  
          *        content to add without any checks
 125  
          */
 126  
         final void uncheckedAddContent(final Content c) {
 127  8
                 c.parent = parent;
 128  8
                 ensureCapacity(size + 1);
 129  8
                 elementData[size++] = c;
 130  8
                 incModCount();
 131  8
         }
 132  
 
 133  
         /**
 134  
          * In the FilterList and FilterList iterators it becomes confusing as to
 135  
          * which modCount is being used. This formalizes the process, and using
 136  
          * (set/get/inc)ModCount() is the only thing you should see in the remainder
 137  
          * of this code.
 138  
          * 
 139  
          * @param sizemod
 140  
          *        the value to set for the size-mod count.
 141  
          * @param datamod
 142  
          *        the value to set for the data-mod count.
 143  
          */
 144  
         private final void setModCount(final int sizemod, final int datamod) {
 145  184
                 sizeModCount = sizemod;
 146  184
                 dataModiCount = datamod;
 147  184
         }
 148  
 
 149  
         /**
 150  
          * In the FilterList and FilterList iterators it becomes confusing as to
 151  
          * which modCount is being used. This formalizes the process, and using
 152  
          * (set/get/inc)ModCount() is the only thing you should see in the remainder
 153  
          * of this code.
 154  
          * 
 155  
          * @return mod the value.
 156  
          */
 157  
         private final int getModCount() {
 158  625397
                 return sizeModCount;
 159  
         }
 160  
 
 161  
         /**
 162  
          * In the FilterList and FilterList iterators it becomes confusing as to
 163  
          * which modCount is being used. This formalizes the process, and using
 164  
          * (set/get/inc)ModCount() is the only thing you should see in the remainder
 165  
          * of this code.
 166  
          */
 167  
         private final void incModCount() {
 168  
                 // indicate there's a change to data
 169  68214
                 dataModiCount++;
 170  
                 // indicate there's a change to the size
 171  68214
                 sizeModCount++;
 172  68214
         }
 173  
         
 174  
         private final void incDataModOnly() {
 175  1770
                 dataModiCount++;
 176  1770
         }
 177  
 
 178  
         /**
 179  
          * Get the modcount of data changes.
 180  
          * @return the current data mode count.
 181  
          */
 182  
         private final int getDataModCount() {
 183  335622
                 return dataModiCount;
 184  
         }
 185  
 
 186  
         private final void checkIndex(final int index, final boolean excludes) {
 187  181943
                 final int max = excludes ? size - 1 : size;
 188  
 
 189  181943
                 if (index < 0 || index > max) {
 190  20
                         throw new IndexOutOfBoundsException("Index: " + index +
 191  
                                         " Size: " + size);
 192  
                 }
 193  
 
 194  181923
         }
 195  
 
 196  
         private final void checkPreConditions(final Content child, final int index,
 197  
                         final boolean replace) {
 198  50463
                 if (child == null) {
 199  57
                         throw new NullPointerException("Cannot add null object");
 200  
                 }
 201  
 
 202  50406
                 checkIndex(index, replace);
 203  
 
 204  50398
                 if (child.getParent() != null) {
 205  
                         // the content to be added already has a parent.
 206  68
                         final Parent p = child.getParent();
 207  68
                         if (p instanceof Document) {
 208  1
                                 throw new IllegalAddException((Element) child,
 209  
                                                 "The Content already has an existing parent document");
 210  
                         }
 211  67
                         throw new IllegalAddException(
 212  
                                         "The Content already has an existing parent \"" +
 213  
                                                         ((Element) p).getQualifiedName() + "\"");
 214  
                 }
 215  
 
 216  50330
                 if (child == parent) {
 217  1
                         throw new IllegalAddException(
 218  
                                         "The Element cannot be added to itself");
 219  
                 }
 220  
 
 221  
                 // Detect if we have <a><b><c/></b></a> and c.add(a)
 222  50329
                 if ((parent instanceof Element && child instanceof Element) &&
 223  
                                 ((Element) child).isAncestor((Element) parent)) {
 224  48
                         throw new IllegalAddException(
 225  
                                         "The Element cannot be added as a descendent of itself");
 226  
                 }
 227  
 
 228  50281
         }
 229  
 
 230  
         /**
 231  
          * Check and add the <code>Content</code> to this list at the given index.
 232  
          * Inserts the specified object at the specified position in this list.
 233  
          * Shifts the object currently at that position (if any) and any subsequent
 234  
          * objects to the right (adds one to their indices).
 235  
          * 
 236  
          * @param index
 237  
          *        index where to add <code>Element</code>
 238  
          * @param child
 239  
          *        <code>Content</code> to add
 240  
          */
 241  
         @Override
 242  
         public void add(final int index, final Content child) {
 243  
                 // Confirm basic sanity of child.
 244  48631
                 checkPreConditions(child, index, false);
 245  
                 // Check to see whether this parent believes it can contain this content
 246  48495
                 parent.canContainContent(child, index, false);
 247  
 
 248  48433
                 child.setParent(parent);
 249  
 
 250  48433
                 ensureCapacity(size + 1);
 251  48433
                 if (index == size) {
 252  35037
                         elementData[size++] = child;
 253  
                 } else {
 254  13396
                         System.arraycopy(elementData, index, elementData, index + 1, size - index);
 255  13396
                         elementData[index] = child;
 256  13396
                         size++;
 257  
                 }
 258  
                 // Successful add's increment the AbstractList's modCount
 259  48433
                 incModCount();
 260  48433
         }
 261  
 
 262  
         /**
 263  
          * Add the specified collection to the end of this list.
 264  
          * 
 265  
          * @param collection
 266  
          *        The collection to add to the list.
 267  
          * @return <code>true</code> if the list was modified as a result of the
 268  
          *         add.
 269  
          */
 270  
         @Override
 271  
         public boolean addAll(final Collection<? extends Content> collection) {
 272  34
                 return addAll(size, collection);
 273  
         }
 274  
 
 275  
         /**
 276  
          * Inserts the specified collection at the specified position in this list.
 277  
          * Shifts the object currently at that position (if any) and any subsequent
 278  
          * objects to the right (adds one to their indices).
 279  
          * 
 280  
          * @param index
 281  
          *        The offset to start adding the data in the collection
 282  
          * @param collection
 283  
          *        The collection to insert into the list.
 284  
          * @return <code>true</code> if the list was modified as a result of the
 285  
          *         add. throws IndexOutOfBoundsException if index < 0 || index >
 286  
          *         size()
 287  
          */
 288  
         @Override
 289  
         public boolean addAll(final int index, 
 290  
                         final Collection<? extends Content> collection) {
 291  165
                 if ((collection == null)) {
 292  2
                         throw new NullPointerException(
 293  
                                         "Can not add a null collection to the ContentList");
 294  
                 }
 295  
 
 296  163
                 checkIndex(index, false);
 297  
 
 298  161
                 if (collection.isEmpty()) {
 299  
                         // some collections are expensive to get the size of.
 300  
                         // use isEmpty().
 301  4
                         return false;
 302  
                 }
 303  157
                 final int addcnt = collection.size();
 304  157
                 if (addcnt == 1) {
 305  
                         // quick check for single-add.
 306  108
                         add(index, collection.iterator().next());
 307  40
                         return true;
 308  
                 }
 309  
 
 310  49
                 ensureCapacity(size() + addcnt);
 311  
 
 312  49
                 final int tmpmodcount = getModCount();
 313  49
                 final int tmpdmc = getDataModCount();
 314  49
                 boolean ok = false;
 315  
 
 316  49
                 int count = 0;
 317  
 
 318  
                 try {
 319  49
                         for (Content c : collection) {
 320  169
                                 add(index + count, c);
 321  146
                                 count++;
 322  146
                         }
 323  25
                         ok = true;
 324  
                 } finally {
 325  49
                         if (!ok) {
 326  
                                 // something failed... remove all added content
 327  62
                                 while (--count >= 0) {
 328  38
                                         remove(index + count);
 329  
                                 }
 330  
                                 // restore the mod-counts.
 331  24
                                 setModCount(tmpmodcount, tmpdmc);
 332  
                         }
 333  
                 }
 334  
 
 335  25
                 return true;
 336  
         }
 337  
 
 338  
         /**
 339  
          * Clear the current list.
 340  
          */
 341  
         @Override
 342  
         public void clear() {
 343  142
                 if (elementData != null) {
 344  235
                         for (int i = 0; i < size; i++) {
 345  153
                                 Content obj = elementData[i];
 346  153
                                 removeParent(obj);
 347  
                         }
 348  82
                         elementData = null;
 349  82
                         size = 0;
 350  
                 }
 351  142
                 incModCount();
 352  142
         }
 353  
 
 354  
         /**
 355  
          * Clear the current list and set it to the contents of the
 356  
          * <code>Collection</code>. object.
 357  
          * 
 358  
          * @param collection
 359  
          *        The collection to use.
 360  
          */
 361  
         void clearAndSet(final Collection<? extends Content> collection) {
 362  30
                 if (collection == null || collection.isEmpty()) {
 363  4
                         clear();
 364  4
                         return;
 365  
                 }
 366  
 
 367  
                 // keep a backup in case we need to roll-back...
 368  26
                 final Content[] old = elementData;
 369  26
                 final int oldSize = size;
 370  26
                 final int oldModCount = getModCount();
 371  26
                 final int oldDataModCount = getDataModCount();
 372  
 
 373  
                 // clear the current system
 374  
                 // we need to detach before we add so that we don't run in to a problem
 375  
                 // where a content in the to-add list is one that we are 'clearing'
 376  
                 // first.
 377  58
                 while (size > 0) {
 378  32
                         old[--size].setParent(null);
 379  
                 }
 380  26
                 size = 0;
 381  26
                 elementData = null;
 382  
 
 383  26
                 boolean ok = false;
 384  
                 try {
 385  26
                         addAll(0, collection);
 386  22
                         ok = true;
 387  
                 } finally {
 388  26
                         if (!ok) {
 389  
                                 // we have an exception pending....
 390  
                                 // restore the old system.
 391  
                                 // we do not need to worry about the added content
 392  
                                 // because the failed addAll will clear it up.
 393  
                                 // re-attach the old stuff
 394  4
                                 elementData = old;
 395  26
                                 while (size < oldSize) {
 396  22
                                         elementData[size++].setParent(parent);
 397  
                                 }
 398  4
                                 setModCount(oldModCount, oldDataModCount);
 399  
                         }
 400  
                 }
 401  
 
 402  22
         }
 403  
 
 404  
         /**
 405  
          * Increases the capacity of this <code>ContentList</code> instance, if
 406  
          * necessary, to ensure that it can hold at least the number of items
 407  
          * specified by the minimum capacity argument.
 408  
          * 
 409  
          * @param minCapacity
 410  
          *        the desired minimum capacity.
 411  
          */
 412  
         void ensureCapacity(final int minCapacity) {
 413  48679
                 if (elementData == null) {
 414  7842
                         elementData = new Content[Math.max(minCapacity, INITIAL_ARRAY_SIZE)];
 415  7842
                         return;
 416  40837
                 } else if (minCapacity < elementData.length) {
 417  37252
                         return;
 418  
                 }
 419  
                 // use algorithm Wilf suggests which is essentially the same
 420  
                 // as algorithm as ArrayList.ensureCapacity....
 421  
                 // typically the minCapacity is only slightly larger than
 422  
                 // the current capacity.... so grow from the current capacity
 423  
                 // with a double-check.
 424  3585
                 final int newcap = ((size * 3) / 2) + 1;
 425  3585
                 elementData = ArrayCopy.copyOf(elementData, 
 426  
                                 (newcap < minCapacity ? minCapacity : newcap));
 427  3585
         }
 428  
 
 429  
         /**
 430  
          * Return the object at the specified offset.
 431  
          * 
 432  
          * @param index
 433  
          *        The offset of the object.
 434  
          * @return The Object which was returned.
 435  
          */
 436  
         @Override
 437  
         public Content get(final int index) {
 438  109730
                 checkIndex(index, true);
 439  109726
                 return elementData[index];
 440  
         }
 441  
 
 442  
         /**
 443  
          * Return a view of this list based on the given filter.
 444  
          * 
 445  
          * @param <E>
 446  
          *        The Generic type of the content as set by the Filter.
 447  
          * @param filter
 448  
          *        <code>Filter</code> for this view.
 449  
          * @return a list representing the rules of the <code>Filter</code>.
 450  
          */
 451  
         <E extends Content> List<E> getView(final Filter<E> filter) {
 452  7741
                 return new FilterList<E>(filter);
 453  
         }
 454  
 
 455  
         /**
 456  
          * Return the index of the first Element in the list. If the parent is a
 457  
          * <code>Document</code> then the element is the root element. If the list
 458  
          * contains no Elements, it returns -1.
 459  
          * 
 460  
          * @return index of first element, or -1 if one doesn't exist
 461  
          */
 462  
         int indexOfFirstElement() {
 463  6851
                 if (elementData != null) {
 464  11297
                         for (int i = 0; i < size; i++) {
 465  10618
                                 if (elementData[i] instanceof Element) {
 466  4099
                                         return i;
 467  
                                 }
 468  
                         }
 469  
                 }
 470  2752
                 return -1;
 471  
         }
 472  
 
 473  
         /**
 474  
          * Return the index of the DocType element in the list. If the list contains
 475  
          * no DocType, it returns -1.
 476  
          * 
 477  
          * @return index of the DocType, or -1 if it doesn't exist
 478  
          */
 479  
         int indexOfDocType() {
 480  2148
                 if (elementData != null) {
 481  1998
                         for (int i = 0; i < size; i++) {
 482  1394
                                 if (elementData[i] instanceof DocType) {
 483  376
                                         return i;
 484  
                                 }
 485  
                         }
 486  
                 }
 487  1772
                 return -1;
 488  
         }
 489  
 
 490  
         /**
 491  
          * Remove the object at the specified offset.
 492  
          * 
 493  
          * @param index
 494  
          *        The offset of the object.
 495  
          * @return The Object which was removed.
 496  
          */
 497  
         @Override
 498  
         public Content remove(final int index) {
 499  19635
                 checkIndex(index, true);
 500  
 
 501  19631
                 final Content old = elementData[index];
 502  19631
                 removeParent(old);
 503  19631
                 System.arraycopy(elementData, index + 1, elementData, index, size - index - 1);
 504  19631
                 elementData[--size] = null; // Let gc do its work
 505  19631
                 incModCount();
 506  19631
                 return old;
 507  
         }
 508  
 
 509  
         /** Remove the parent of a Object */
 510  
         private static void removeParent(final Content c) {
 511  21554
                 c.setParent(null);
 512  21554
         }
 513  
 
 514  
         /**
 515  
          * Set the object at the specified location to the supplied object.
 516  
          * 
 517  
          * @param index
 518  
          *        The location to set the value to.
 519  
          * @param child
 520  
          *        The location to set the value to.
 521  
          * @return The object which was replaced. throws IndexOutOfBoundsException
 522  
          *         if index < 0 || index >= size()
 523  
          */
 524  
         @Override
 525  
         public Content set(final int index, final Content child) {
 526  
                 // Confirm basic sanity of child.
 527  1832
                 checkPreConditions(child, index, true);
 528  
 
 529  
                 // Ensure the detail checks out OK too.
 530  1786
                 parent.canContainContent(child, index, true);
 531  
 
 532  
                 /*
 533  
                  * Do a special case of set() where we don't do a remove() then add()
 534  
                  * because that affects the modCount. We want to do a true set(). See
 535  
                  * issue #15
 536  
                  */
 537  
 
 538  1770
                 final Content old = elementData[index];
 539  1770
                 removeParent(old);
 540  1770
                 child.setParent(parent);
 541  1770
                 elementData[index] = child;
 542  
                 // for set method we increment dataModCount, but not modCount
 543  
                 // set does not change the structure of the List (size())
 544  1770
                 incDataModOnly();
 545  1770
                 return old;
 546  
         }
 547  
 
 548  
         /**
 549  
          * Return the number of items in this list
 550  
          * 
 551  
          * @return The number of items in this list.
 552  
          */
 553  
         @Override
 554  
         public int size() {
 555  64455
                 return size;
 556  
         }
 557  
 
 558  
         @Override
 559  
         public Iterator<Content> iterator() {
 560  30461
                 return new CLIterator();
 561  
         }
 562  
         
 563  
         @Override
 564  
         public ListIterator<Content> listIterator() {
 565  407
                 return new CLListIterator(0);
 566  
         }
 567  
 
 568  
         @Override
 569  
         public ListIterator<Content> listIterator(final int start) {
 570  1602
                 return new CLListIterator(start);
 571  
         }
 572  
 
 573  
         /**
 574  
          * Return this list as a <code>String</code>
 575  
          * 
 576  
          * @return The String representation of this list.
 577  
          */
 578  
         @Override
 579  
         public String toString() {
 580  73
                 return super.toString();
 581  
         }
 582  
         
 583  
         private void sortInPlace(final int[] indexes) {
 584  
                 // the indexes are a discrete set of values that have no duplicates,
 585  
                 // and describe the relative order of each of them.
 586  
                 // as a result, we can do some tricks....
 587  15
                 final int[] unsorted = ArrayCopy.copyOf(indexes, indexes.length);
 588  15
                 Arrays.sort(unsorted);
 589  15
                 final Content[] usc = new Content[unsorted.length];
 590  76
                 for (int i = 0; i < usc.length; i++) {
 591  61
                         usc[i] = elementData[indexes[i]];
 592  
                 }
 593  
                 // usc contains the content in their pre-sorted order....
 594  76
                 for (int i = 0; i < indexes.length; i ++) {
 595  61
                         elementData[unsorted[i]] = usc[i];
 596  
                 }
 597  15
         }
 598  
 
 599  
         /**
 600  
          * Unlike the Arrays.binarySearch, this method never expects an
 601  
          * "already exists" condition, we only ever add, thus there will never
 602  
          * be a negative insertion-point.
 603  
          * @param indexes THe pointers to search within
 604  
          * @param len The number of pointers to search within
 605  
          * @param val The pointer we are checking for.
 606  
          * @param comp The Comparator to compare with
 607  
          * @return the insertion point.
 608  
          */
 609  
         private final int binarySearch(final int[] indexes, final int len,
 610  
                         final int val, final Comparator<? super Content> comp) {
 611  20
                 int left = 0, mid = 0, right = len - 1, cmp = 0;
 612  20
                 final Content base = elementData[val];
 613  35
                 while (left <= right) {
 614  21
                         mid = (left + right) >>> 1;
 615  21
                         cmp = comp.compare(base, elementData[indexes[mid]]);
 616  21
                         if (cmp == 0) {
 617  9
                                 while (cmp == 0 && mid < right && comp.compare(
 618  
                                                 base, elementData[indexes[mid + 1]]) == 0) {
 619  3
                                         mid++;
 620  
                                 }
 621  6
                                 return mid + 1;
 622  15
                         } else if (cmp < 0) {
 623  8
                                 right = mid - 1;
 624  
                         } else {
 625  7
                                 left = mid + 1;
 626  
                         }
 627  
                 }
 628  14
                 return left;
 629  
         }
 630  
         
 631  
     /**
 632  
      * Sorts this list using the supplied Comparator to compare elements.
 633  
      * 
 634  
      * @param comp - the Comparator used to compare list elements. A null value indicates that the elements' natural ordering should be used
 635  
      * @Since 2.0.6
 636  
      */
 637  
         // @Override - only in Java8
 638  
         public final void sort(final Comparator<? super Content> comp) {
 639  
 
 640  6
             if (comp == null) {
 641  
             // sort by the 'natural order', which, there is none.
 642  
             // options, throw exception, or let the current-order represent the natural order.
 643  
             // do nothing is the better alternative.
 644  1
             return;
 645  
         }
 646  
 
 647  5
                 final int sz = size;
 648  5
                 int[] indexes = new int[sz];
 649  25
                 for (int i = 0 ; i < sz; i++) {
 650  20
                         final int ip = binarySearch(indexes, i, i, comp);
 651  20
                         if (ip < i) {
 652  9
                                 System.arraycopy(indexes, ip, indexes, ip+1, i - ip);
 653  
                         }
 654  20
                         indexes[ip] = i;
 655  
                 }
 656  5
                 sortInPlace(indexes);
 657  5
         }
 658  
         
 659  
         /* * * * * * * * * * * * * ContentListIterator * * * * * * * * * * * * * * * */
 660  
         /* * * * * * * * * * * * * ContentListIterator * * * * * * * * * * * * * * * */
 661  
         /**
 662  
          * A fast implementation of Iterator.
 663  
          * <p>
 664  
          * It is fast because it is tailored to the ContentList, and not the
 665  
          * flexible implementation used by AbstractList. It needs to be fast because
 666  
          * iterator() is used extensively in the for-each type loop.
 667  
          * 
 668  
          * @author Rolf Lear
 669  
          */
 670  397875
         private final class CLIterator implements Iterator<Content> {
 671  30461
                 private int expect = -1;
 672  30461
                 private int cursor = 0;
 673  30461
                 private boolean canremove = false;
 674  
 
 675  30461
                 private CLIterator() {
 676  30461
                         expect = getModCount();
 677  30461
                 }
 678  
 
 679  
                 @Override
 680  
                 public boolean hasNext() {
 681  413966
                         return cursor < size;
 682  
                 }
 683  
 
 684  
                 @Override
 685  
                 public Content next() {
 686  367414
                         if (getModCount() != expect) {
 687  2
                                 throw new ConcurrentModificationException("ContentList was " +
 688  
                                                 "modified outside of this Iterator");
 689  
                         }
 690  367412
                         if (cursor >= size) {
 691  1092
                                 throw new NoSuchElementException("Iterated beyond the end of " +
 692  
                                                 "the ContentList.");
 693  
                         }
 694  366320
                         canremove = true;
 695  366320
                         return elementData[cursor++];
 696  
                 }
 697  
 
 698  
                 @Override
 699  
                 public void remove() {
 700  716
                         if (getModCount() != expect) {
 701  1
                                 throw new ConcurrentModificationException("ContentList was " +
 702  
                                                 "modified outside of this Iterator");
 703  
                         }
 704  715
                         if (!canremove) {
 705  384
                                 throw new IllegalStateException("Can only remove() content " +
 706  
                                                 "after a call to next()");
 707  
                         }
 708  331
                         canremove = false;
 709  331
                         ContentList.this.remove(--cursor);
 710  331
                         expect = getModCount();
 711  331
                 }
 712  
 
 713  
         }
 714  
 
 715  
         /* * * * * * * * * * * * * ContentListIterator * * * * * * * * * * * * * * * */
 716  
         /* * * * * * * * * * * * * ContentListIterator * * * * * * * * * * * * * * * */
 717  
         /**
 718  
          * A fast implementation of Iterator.
 719  
          * <p>
 720  
          * It is fast because it is tailored to the ContentList, and not the
 721  
          * flexible implementation used by AbstractList. It needs to be fast because
 722  
          * iterator() is used extensively in the for-each type loop.
 723  
          * 
 724  
          * @author Rolf Lear
 725  
          */
 726  16435
         private final class CLListIterator implements ListIterator<Content> {
 727  
                 /** Whether this iterator is in forward or reverse. */
 728  2009
                 private boolean forward = false;
 729  
                 /** Whether a call to remove() is valid */
 730  2009
                 private boolean canremove = false;
 731  
                 /** Whether a call to set() is valid */
 732  2009
                 private boolean canset = false;
 733  
 
 734  
                 /** Expected modCount in our backing list */
 735  2009
                 private int expectedmod = -1;
 736  
 
 737  2009
                 private int cursor = -1;
 738  
 
 739  
                 /**
 740  
                  * Default constructor
 741  
                  * 
 742  
                  * @param flist
 743  
                  *        The FilterList over which we will iterate.
 744  
                  * @param start
 745  
                  *        where in the FilterList to start iteration.
 746  
                  */
 747  2009
                 CLListIterator(final int start) {
 748  2009
                         expectedmod = getModCount();
 749  
                         // always start list iterators in backward mode ....
 750  
                         // it makes sense... really.
 751  2009
                         forward = false;
 752  
 
 753  2009
                         checkIndex(start, false);
 754  
 
 755  2007
                         cursor = start;
 756  2007
                 }
 757  
 
 758  
                 private void checkConcurrent() {
 759  21786
                         if (expectedmod != getModCount()) {
 760  5
                                 throw new ConcurrentModificationException("The ContentList " +
 761  
                                                 "supporting this iterator has been modified by" +
 762  
                                                 "something other than this Iterator.");
 763  
                         }
 764  21781
                 }
 765  
 
 766  
                 /**
 767  
                  * Returns <code>true</code> if this list iterator has a next element.
 768  
                  */
 769  
                 @Override
 770  
                 public boolean hasNext() {
 771  6242
                         return (forward ? cursor + 1 : cursor) < size;
 772  
                 }
 773  
 
 774  
                 /**
 775  
                  * Returns <code>true</code> if this list iterator has more elements
 776  
                  * when traversing the list in the reverse direction.
 777  
                  */
 778  
                 @Override
 779  
                 public boolean hasPrevious() {
 780  5897
                         return (forward ? cursor : cursor - 1) >= 0;
 781  
                 }
 782  
 
 783  
                 /**
 784  
                  * Returns the index of the element that would be returned by a
 785  
                  * subsequent call to <code>next</code>.
 786  
                  */
 787  
                 @Override
 788  
                 public int nextIndex() {
 789  15624
                         return forward ? cursor + 1 : cursor;
 790  
                 }
 791  
 
 792  
                 /**
 793  
                  * Returns the index of the element that would be returned by a
 794  
                  * subsequent call to <code>previous</code>. (Returns -1 if the list
 795  
                  * iterator is at the beginning of the list.)
 796  
                  */
 797  
                 @Override
 798  
                 public int previousIndex() {
 799  14060
                         return forward ? cursor : cursor - 1;
 800  
                 }
 801  
 
 802  
                 /**
 803  
                  * Returns the next element in the list.
 804  
                  */
 805  
                 @Override
 806  
                 public Content next() {
 807  5716
                         checkConcurrent();
 808  5715
                         final int next = forward ? cursor + 1 : cursor;
 809  
 
 810  5715
                         if (next >= size) {
 811  606
                                 throw new NoSuchElementException("next() is beyond the end of the Iterator");
 812  
                         }
 813  
 
 814  5109
                         cursor = next;
 815  5109
                         forward = true;
 816  5109
                         canremove = true;
 817  5109
                         canset = true;
 818  5109
                         return elementData[cursor];
 819  
                 }
 820  
 
 821  
                 /**
 822  
                  * Returns the previous element in the list.
 823  
                  */
 824  
                 @Override
 825  
                 public Content previous() {
 826  7214
                         checkConcurrent();
 827  7213
                         final int prev = forward ? cursor : cursor - 1;
 828  
 
 829  7213
                         if (prev < 0) {
 830  606
                                 throw new NoSuchElementException("previous() is beyond the beginning of the Iterator");
 831  
                         }
 832  
 
 833  6607
                         cursor = prev;
 834  6607
                         forward = false;
 835  6607
                         canremove = true;
 836  6607
                         canset = true;
 837  6607
                         return elementData[cursor];
 838  
                 }
 839  
 
 840  
                 /**
 841  
                  * Inserts the specified element into the list .
 842  
                  */
 843  
                 @Override
 844  
                 public void add(final Content obj) {
 845  3000
                         checkConcurrent();
 846  
                         // always add before what would normally be returned by next();
 847  2999
                         final int next = forward ? cursor + 1 : cursor;
 848  
 
 849  2999
                         ContentList.this.add(next, obj);
 850  
 
 851  2985
                         expectedmod = getModCount();
 852  
 
 853  2985
                         canremove = canset = false;
 854  
 
 855  
                         // a call to next() should be unaffected, so, whatever was going to
 856  
                         // be next will still be next, remember, what was going to be next
 857  
                         // has been shifted 'right' by our insert.
 858  
                         // we ensure this by setting the cursor to next(), and making it
 859  
                         // forward
 860  2985
                         cursor = next;
 861  2985
                         forward = true;
 862  2985
                 }
 863  
 
 864  
                 /**
 865  
                  * Removes from the list the last element that was returned by the last
 866  
                  * call to <code>next</code> or <code>previous</code>.
 867  
                  */
 868  
                 @Override
 869  
                 public void remove() {
 870  5379
                         checkConcurrent();
 871  5378
                         if (!canremove)
 872  2394
                                 throw new IllegalStateException("Can not remove an "
 873  
                                                 + "element unless either next() or previous() has been called "
 874  
                                                 + "since the last remove()");
 875  
                         // we are removing the last entry returned by either next() or
 876  
                         // previous().
 877  
                         // the idea is to remove it, and pretend that we used to be at the
 878  
                         // entry that happened *after* the removed entry.
 879  
                         // so, get what would be the next entry (set at tmpcursor).
 880  
                         // so call nextIndex to set tmpcursor to what would come after.
 881  2984
                         ContentList.this.remove(cursor);
 882  2984
                         forward = false;
 883  2984
                         expectedmod = getModCount();
 884  
 
 885  2984
                         canremove = false;
 886  2984
                         canset = false;
 887  2984
                 }
 888  
 
 889  
                 /**
 890  
                  * Replaces the last element returned by <code>next</code> or
 891  
                  * <code>previous</code> with the specified element.
 892  
                  */
 893  
                 @Override
 894  
                 public void set(final Content obj) {
 895  477
                         checkConcurrent();
 896  476
                         if (!canset) {
 897  128
                                 throw new IllegalStateException("Can not set an element "
 898  
                                                 + "unless either next() or previous() has been called since the "
 899  
                                                 + "last remove() or set()");
 900  
                         }
 901  
 
 902  348
                         ContentList.this.set(cursor, obj);
 903  334
                         expectedmod = getModCount();
 904  
 
 905  334
                 }
 906  
 
 907  
         }
 908  
 
 909  
         /* * * * * * * * * * * * * FilterList * * * * * * * * * * * * * * * */
 910  
         /* * * * * * * * * * * * * FilterList * * * * * * * * * * * * * * * */
 911  
 
 912  
         /**
 913  
          * <code>FilterList</code> represents legal JDOM content, including content
 914  
          * for <code>Document</code>s or <code>Element</code>s.
 915  
          * <p>
 916  
          * FilterList represents a dynamic view of the backing ContentList, changes
 917  
          * to the backing list are reflected in the FilterList, and visa-versa.
 918  
          * 
 919  
          * @param <F>
 920  
          *        The Generic type of content accepted by the underlying Filter.
 921  
          */
 922  
 
 923  156270
         class FilterList<F extends Content> extends AbstractList<F> {
 924  
 
 925  
                 // The filter to apply
 926  
                 final Filter<F> filter;
 927  
                 // correlate the position in the filtered list to the index in the
 928  
                 // backing ContentList.
 929  7741
                 int[] backingpos = new int[size + INITIAL_ARRAY_SIZE];
 930  7741
                 int backingsize = 0;
 931  
                 // track data modifications in the backing ContentList.
 932  7741
                 int xdata = -1;
 933  
 
 934  
                 /**
 935  
                  * Create a new instance of the FilterList with the specified Filter.
 936  
                  * 
 937  
                  * @param filter
 938  
                  *        The underlying Filter to use for filtering the content.
 939  
                  */
 940  7741
                 FilterList(final Filter<F> filter) {
 941  7741
                         this.filter = filter;
 942  7741
                 }
 943  
                 
 944  
                 /**
 945  
                  * Returns true if there is no content in this FilterList.
 946  
                  * @return true if there is no content in this FilterList
 947  
                  */
 948  
                 @Override
 949  
                 public boolean isEmpty() {
 950  
                         // More efficient implementation than default size() == 0
 951  
                         // we use resync() to accomplish the task. If there is an
 952  
                         // element 0 in this FilterList, then it is not empty!
 953  
                         // we may already have resync'd 0, which will be a fast return then,
 954  
                         // or, if we have not resync'd 0, then we only have to filter up to
 955  
                         // the first matching element to get a result (or the whole list
 956  
                         // if isEmpty() is true).
 957  578
                         return resync(0) == size;
 958  
                 }
 959  
 
 960  
                 /**
 961  
                  * Synchronise our view to the backing list. Only synchronise the first
 962  
                  * <code>index</code> view elements. For want of a better word, we'll
 963  
                  * call this a 'Lazy' implementation.
 964  
                  * 
 965  
                  * @param index
 966  
                  *        how much we want to sync. Set to -1 to synchronise everything.
 967  
                  * @return the index in the backing array of the <i>index'th</i> match.
 968  
                  *         or the backing data size if there is no match for the index.
 969  
                  */
 970  
                 private final int resync(final int index) {
 971  293484
                         if (xdata != getDataModCount()) {
 972  
                                 // The underlying list was modified somehow...
 973  
                                 // we need to invalidate our research...
 974  7847
                                 xdata = getDataModCount();
 975  7847
                                 backingsize = 0;
 976  7847
                                 if (size >= backingpos.length) {
 977  1
                                         backingpos = new int[size + 1];
 978  
                                 }
 979  
                         }
 980  
 
 981  293484
                         if (index >= 0 && index < backingsize) {
 982  
                                 // we have already indexed far enough...
 983  
                                 // return the backing index.
 984  213413
                                 return backingpos[index];
 985  
                         }
 986  
 
 987  
                         // the index in the backing list of the next value to check.
 988  80071
                         int bpi = 0;
 989  80071
                         if (backingsize > 0) {
 990  62996
                                 bpi = backingpos[backingsize - 1] + 1;
 991  
                         }
 992  
 
 993  137076
                         while (bpi < size) {
 994  103165
                                 final F gotit = filter.filter(elementData[bpi]);
 995  103165
                                 if (gotit != null) {
 996  47103
                                         backingpos[backingsize] = bpi;
 997  47103
                                         if (backingsize++ == index) {
 998  46160
                                                 return bpi;
 999  
                                         }
 1000  
                                 }
 1001  57005
                                 bpi++;
 1002  57005
                         }
 1003  33911
                         return size;
 1004  
                 }
 1005  
 
 1006  
                 /**
 1007  
                  * Inserts the specified object at the specified position in this list.
 1008  
                  * Shifts the object currently at that position (if any) and any
 1009  
                  * subsequent objects to the right (adds one to their indices).
 1010  
                  * 
 1011  
                  * @param index
 1012  
                  *        The location to set the value to.
 1013  
                  * @param obj
 1014  
                  *        The object to insert into the list. throws
 1015  
                  *        IndexOutOfBoundsException if index < 0 || index > size()
 1016  
                  */
 1017  
                 @Override
 1018  
                 public void add(final int index, final Content obj) {
 1019  16495
                         if (index < 0) {
 1020  4
                                 throw new IndexOutOfBoundsException("Index: " + index + " Size: " + size());
 1021  
                         }
 1022  16491
                         int adj = resync(index);
 1023  16491
                         if (adj == size && index > size()) {
 1024  4
                                 throw new IndexOutOfBoundsException("Index: " + index + " Size: " + size());
 1025  
                         }
 1026  16487
                         if (filter.matches(obj)) {
 1027  16390
                                 ContentList.this.add(adj, obj);
 1028  
 
 1029  
                                 // we can optimise the laziness now by doing a partial reset on
 1030  
                                 // the backing list... invalidate everything *after* the added
 1031  
                                 // content
 1032  16355
                                 if (backingpos.length <= size) {
 1033  341
                                         backingpos = ArrayCopy.copyOf(backingpos, backingpos.length + 1);
 1034  
                                 }
 1035  16355
                                 backingpos[index] = adj;
 1036  16355
                                 backingsize = index + 1;
 1037  16355
                                 xdata = getDataModCount();
 1038  
 
 1039  
                         } else {
 1040  97
                                 throw new IllegalAddException("Filter won't allow the " +
 1041  
                                                 obj.getClass().getName() +
 1042  
                                                 " '" + obj + "' to be added to the list");
 1043  
                         }
 1044  16355
                 }
 1045  
 
 1046  
                 @Override
 1047  
                 public boolean addAll(final int index, 
 1048  
                                 final Collection<? extends F> collection) {
 1049  201
                         if (collection == null) {
 1050  3
                                 throw new NullPointerException("Cannot add a null collection");
 1051  
                         }
 1052  
 
 1053  198
                         if (index < 0) {
 1054  3
                                 throw new IndexOutOfBoundsException("Index: " + index + " Size: " + size());
 1055  
                         }
 1056  
 
 1057  195
                         final int adj = resync(index);
 1058  195
                         if (adj == size && index > size()) {
 1059  3
                                 throw new IndexOutOfBoundsException("Index: " + index + " Size: " + size());
 1060  
                         }
 1061  
 
 1062  192
                         final int addcnt = collection.size();
 1063  192
                         if (addcnt == 0) {
 1064  3
                                 return false;
 1065  
                         }
 1066  
 
 1067  189
                         ContentList.this.ensureCapacity(ContentList.this.size() + addcnt);
 1068  
 
 1069  189
                         final int tmpmodcount = getModCount();
 1070  189
                         final int tmpdmc = getDataModCount();
 1071  189
                         boolean ok = false;
 1072  
 
 1073  189
                         int count = 0;
 1074  
 
 1075  
                         try {
 1076  189
                                 for (Content c : collection) {
 1077  305
                                         if (c == null) {
 1078  63
                                                 throw new NullPointerException(
 1079  
                                                                 "Cannot add null content");
 1080  
                                         }
 1081  242
                                         if (filter.matches(c)) {
 1082  198
                                                 ContentList.this.add(adj + count, c);
 1083  
                                                 // we can optimise the laziness now by doing a partial
 1084  
                                                 // reset on
 1085  
                                                 // the backing list... invalidate everything *after* the
 1086  
                                                 // added
 1087  
                                                 // content
 1088  149
                                                 if (backingpos.length <= size) {
 1089  5
                                                         backingpos = ArrayCopy.copyOf(backingpos, backingpos.length + addcnt);
 1090  
                                                 }
 1091  149
                                                 backingpos[index + count] = adj + count;
 1092  149
                                                 backingsize = index + count + 1;
 1093  149
                                                 xdata = getDataModCount();
 1094  
 
 1095  149
                                                 count++;
 1096  
                                         } else {
 1097  44
                                                 throw new IllegalAddException("Filter won't allow the " +
 1098  
                                                                 c.getClass().getName() +
 1099  
                                                                 " '" + c + "' to be added to the list");
 1100  
 
 1101  
                                         }
 1102  149
                                 }
 1103  33
                                 ok = true;
 1104  
                         } finally {
 1105  189
                                 if (!ok) {
 1106  
                                         // something failed... remove all added content
 1107  232
                                         while (--count >= 0) {
 1108  76
                                                 ContentList.this.remove(adj + count);
 1109  
                                         }
 1110  
                                         // restore the mod-counts.
 1111  156
                                         setModCount(tmpmodcount, tmpdmc);
 1112  
                                         // reset the cache... will need to redo some work on another
 1113  
                                         // call maybe....
 1114  156
                                         backingsize = index;
 1115  156
                                         xdata = tmpmodcount;
 1116  
                                 }
 1117  
                         }
 1118  
 
 1119  33
                         return true;
 1120  
                 }
 1121  
 
 1122  
                 /**
 1123  
                  * Return the object at the specified offset.
 1124  
                  * 
 1125  
                  * @param index
 1126  
                  *        The offset of the object.
 1127  
                  * @return The Object which was returned.
 1128  
                  */
 1129  
                 @Override
 1130  
                 public F get(final int index) {
 1131  94641
                         if (index < 0) {
 1132  4
                                 throw new IndexOutOfBoundsException("Index: " + index + " Size: " + size());
 1133  
                         }
 1134  94637
                         final int adj = resync(index);
 1135  94637
                         if (adj == size) {
 1136  4
                                 throw new IndexOutOfBoundsException("Index: " + index + " Size: " + size());
 1137  
                         }
 1138  94633
                         return filter.filter(ContentList.this.get(adj));
 1139  
                 }
 1140  
 
 1141  
                 @Override
 1142  
                 public Iterator<F> iterator() {
 1143  10738
                         return new FilterListIterator<F>(this, 0);
 1144  
                 }
 1145  
 
 1146  
                 @Override
 1147  
                 public ListIterator<F> listIterator() {
 1148  1286
                         return new FilterListIterator<F>(this, 0);
 1149  
                 }
 1150  
 
 1151  
                 @Override
 1152  
                 public ListIterator<F> listIterator(final int index) {
 1153  6279
                         return new FilterListIterator<F>(this, index);
 1154  
                 }
 1155  
 
 1156  
                 /**
 1157  
                  * Remove the object at the specified offset.
 1158  
                  * 
 1159  
                  * @param index
 1160  
                  *        The offset of the object.
 1161  
                  * @return The Object which was removed.
 1162  
                  */
 1163  
                 @Override
 1164  
                 public F remove(final int index) {
 1165  16110
                         if (index < 0) {
 1166  4
                                 throw new IndexOutOfBoundsException("Index: " + index + " Size: " + size());
 1167  
                         }
 1168  16106
                         final int adj = resync(index);
 1169  16106
                         if (adj == size) {
 1170  4
                                 throw new IndexOutOfBoundsException("Index: " + index + " Size: " + size());
 1171  
                         }
 1172  16102
                         final Content oldc = ContentList.this.remove(adj);
 1173  
                         // optimise the backing cache.
 1174  16102
                         backingsize = index;
 1175  16102
                         xdata = getDataModCount();
 1176  
                         // use Filter to ensure the cast is right.
 1177  16102
                         return filter.filter(oldc);
 1178  
                 }
 1179  
 
 1180  
                 /**
 1181  
                  * Set the object at the specified location to the supplied object.
 1182  
                  * 
 1183  
                  * @param index
 1184  
                  *        The location to set the value to.
 1185  
                  * @param obj
 1186  
                  *        The location to set the value to.
 1187  
                  * @return The object which was replaced. throws
 1188  
                  *         IndexOutOfBoundsException if index < 0 || index >= size()
 1189  
                  */
 1190  
                 @Override
 1191  
                 public F set(final int index, final F obj) {
 1192  1532
                         if (index < 0) {
 1193  4
                                 throw new IndexOutOfBoundsException("Index: " + index + " Size: " + size());
 1194  
                         }
 1195  1528
                         final int adj = resync(index);
 1196  1528
                         if (adj == size) {
 1197  4
                                 throw new IndexOutOfBoundsException("Index: " + index + " Size: " + size());
 1198  
                         }
 1199  1524
                         final F ins = filter.filter(obj);
 1200  1524
                         if (ins != null) {
 1201  1449
                                 final F oldc = filter.filter(ContentList.this.set(adj, ins));
 1202  
                                 // optimize the backing....
 1203  1421
                                 xdata = getDataModCount();
 1204  1421
                                 return oldc;
 1205  
                         }
 1206  75
                         throw new IllegalAddException("Filter won't allow index " +
 1207  
                                         index + " to be set to " +
 1208  
                                         (obj.getClass()).getName());
 1209  
                 }
 1210  
 
 1211  
                 /**
 1212  
                  * Return the number of items in this list
 1213  
                  * 
 1214  
                  * @return The number of items in this list.
 1215  
                  */
 1216  
                 @Override
 1217  
                 public int size() {
 1218  11712
                         resync(-1);
 1219  11712
                         return backingsize;
 1220  
                 }
 1221  
 
 1222  
                 /**
 1223  
                  * Unlike the Arrays.binarySearch, this method never expects an
 1224  
                  * "already exists" condition, we only ever add, thus there will never
 1225  
                  * be a negative insertion-point.
 1226  
                  * @param indexes THe pointers to search within
 1227  
                  * @param len The number of pointers to search within
 1228  
                  * @param val The pointer we are checking for.
 1229  
                  * @param comp The Comparator to compare with
 1230  
                  * @return the insertion point.
 1231  
                  */
 1232  
                 @SuppressWarnings("unchecked")
 1233  
                 private final int fbinarySearch(final int[] indexes, final int len,
 1234  
                                 final int val, final Comparator<? super F> comp) {
 1235  41
                         int left = 0, mid = 0, right = len - 1, cmp = 0;
 1236  41
                         final F base = (F)elementData[backingpos[val]];
 1237  84
                         while (left <= right) {
 1238  50
                                 mid = (left + right) >>> 1;
 1239  50
                                 cmp = comp.compare(base, (F)elementData[indexes[mid]]);
 1240  50
                                 if (cmp == 0) {
 1241  11
                                         while (cmp == 0 && mid < right && comp.compare(
 1242  
                                                         base, (F)elementData[indexes[mid + 1]]) == 0) {
 1243  4
                                                 mid++;
 1244  
                                         }
 1245  7
                                         return mid + 1;
 1246  43
                                 } else if (cmp < 0) {
 1247  24
                                         right = mid - 1;
 1248  
                                 } else {
 1249  19
                                         left = mid + 1;
 1250  
                                 }
 1251  
                         }
 1252  34
                         return left;
 1253  
                 }
 1254  
                 
 1255  
 
 1256  
                 /**
 1257  
                  * Sorts this list using the supplied Comparator to compare elements.
 1258  
                  * 
 1259  
                  * @param comp - the Comparator used to compare list elements. A null value indicates that the elements' natural ordering should be used
 1260  
          * @Since 2.0.6
 1261  
                  */
 1262  
                 //Not till Java8 @Override
 1263  
                 public final void sort(final Comparator<? super F> comp) {
 1264  
                         // this size() forces a full scan/update of the list.
 1265  10
                     if (comp == null) {
 1266  
                         // sort by the 'natural order', which, there is none.
 1267  
                         // options, throw exception, or let the current-order represent the natural order.
 1268  
                         // do nothing is the better alternative.
 1269  0
                         return;
 1270  
                     }
 1271  10
                         final int sz = size();
 1272  10
                         final int[] indexes = new int[sz];
 1273  51
                         for (int i = 0 ; i < sz; i++) {
 1274  41
                                 final int ip = fbinarySearch(indexes, i, i, comp);
 1275  41
                                 if (ip < i) {
 1276  20
                                         System.arraycopy(indexes, ip, indexes, ip+1, i - ip);
 1277  
                                 }
 1278  41
                                 indexes[ip] = backingpos[i];
 1279  
                         }
 1280  10
                         sortInPlace(indexes);
 1281  10
                 }
 1282  
                 
 1283  
         }
 1284  
 
 1285  
         /* * * * * * * * * * * * * FilterListIterator * * * * * * * * * * * */
 1286  
         /* * * * * * * * * * * * * FilterListIterator * * * * * * * * * * * */
 1287  
 
 1288  116221
         final class FilterListIterator<F extends Content> implements ListIterator<F> {
 1289  
 
 1290  
                 /** The Filter that applies */
 1291  
                 private final FilterList<F> filterlist;
 1292  
 
 1293  
                 /** Whether this iterator is in forward or reverse. */
 1294  18303
                 private boolean forward = false;
 1295  
                 /** Whether a call to remove() is valid */
 1296  18303
                 private boolean canremove = false;
 1297  
                 /** Whether a call to set() is valid */
 1298  18303
                 private boolean canset = false;
 1299  
 
 1300  
                 /** Expected modCount in our backing list */
 1301  18303
                 private int expectedmod = -1;
 1302  
 
 1303  18303
                 private int cursor = -1;
 1304  
 
 1305  
                 /**
 1306  
                  * Default constructor
 1307  
                  * 
 1308  
                  * @param flist
 1309  
                  *        The FilterList over which we will iterate.
 1310  
                  * @param start
 1311  
                  *        where in the FilterList to start iteration.
 1312  
                  */
 1313  18303
                 FilterListIterator(final FilterList<F> flist, final int start) {
 1314  18303
                         filterlist = flist;
 1315  18303
                         expectedmod = getModCount();
 1316  
                         // always start list iterators in backward mode ....
 1317  
                         // it makes sense... really.
 1318  18303
                         forward = false;
 1319  
 
 1320  18303
                         if (start < 0) {
 1321  1
                                 throw new IndexOutOfBoundsException("Index: " + start + " Size: " + filterlist.size());
 1322  
                         }
 1323  
 
 1324  18302
                         final int adj = filterlist.resync(start);
 1325  
 
 1326  18302
                         if (adj == size && start > filterlist.size()) {
 1327  
                                 // the start point is after the end of the list.
 1328  
                                 // it is only allowed to be the same as size(), no larger.
 1329  1
                                 throw new IndexOutOfBoundsException("Index: " + start + " Size: " + filterlist.size());
 1330  
                         }
 1331  
 
 1332  18301
                         cursor = start;
 1333  18301
                 }
 1334  
 
 1335  
                 private void checkConcurrent() {
 1336  145868
                         if (expectedmod != getModCount()) {
 1337  21
                                 throw new ConcurrentModificationException("The ContentList " +
 1338  
                                                 "supporting the FilterList this iterator is " +
 1339  
                                                 "processing has been modified by something other " +
 1340  
                                                 "than this Iterator.");
 1341  
                         }
 1342  145847
                 }
 1343  
 
 1344  
                 /**
 1345  
                  * Returns <code>true</code> if this list iterator has a next element.
 1346  
                  */
 1347  
                 @Override
 1348  
                 public boolean hasNext() {
 1349  69570
                         return filterlist.resync(forward ? cursor + 1 : cursor) < size;
 1350  
                 }
 1351  
 
 1352  
                 /**
 1353  
                  * Returns <code>true</code> if this list iterator has more elements
 1354  
                  * when traversing the list in the reverse direction.
 1355  
                  */
 1356  
                 @Override
 1357  
                 public boolean hasPrevious() {
 1358  28021
                         return (forward ? cursor : cursor - 1) >= 0;
 1359  
                 }
 1360  
 
 1361  
                 /**
 1362  
                  * Returns the index of the element that would be returned by a
 1363  
                  * subsequent call to <code>next</code>.
 1364  
                  */
 1365  
                 @Override
 1366  
                 public int nextIndex() {
 1367  78375
                         return forward ? cursor + 1 : cursor;
 1368  
                 }
 1369  
 
 1370  
                 /**
 1371  
                  * Returns the index of the element that would be returned by a
 1372  
                  * subsequent call to <code>previous</code>. (Returns -1 if the list
 1373  
                  * iterator is at the beginning of the list.)
 1374  
                  */
 1375  
                 @Override
 1376  
                 public int previousIndex() {
 1377  70105
                         return forward ? cursor : cursor - 1;
 1378  
                 }
 1379  
 
 1380  
                 /**
 1381  
                  * Returns the next element in the list.
 1382  
                  */
 1383  
                 @Override
 1384  
                 public F next() {
 1385  64371
                         checkConcurrent();
 1386  64365
                         final int next = forward ? cursor + 1 : cursor;
 1387  
 
 1388  64365
                         if (filterlist.resync(next) >= size) {
 1389  4419
                                 throw new NoSuchElementException("next() is beyond the end of the Iterator");
 1390  
                         }
 1391  
 
 1392  59946
                         cursor = next;
 1393  59946
                         forward = true;
 1394  59946
                         canremove = true;
 1395  59946
                         canset = true;
 1396  59946
                         return filterlist.get(cursor);
 1397  
                 }
 1398  
 
 1399  
                 /**
 1400  
                  * Returns the previous element in the list.
 1401  
                  */
 1402  
                 @Override
 1403  
                 public F previous() {
 1404  35138
                         checkConcurrent();
 1405  35135
                         final int prev = forward ? cursor : cursor - 1;
 1406  
 
 1407  35135
                         if (prev < 0) {
 1408  2380
                                 throw new NoSuchElementException("previous() is beyond the beginning of the Iterator");
 1409  
                         }
 1410  
 
 1411  32755
                         cursor = prev;
 1412  32755
                         forward = false;
 1413  32755
                         canremove = true;
 1414  32755
                         canset = true;
 1415  32755
                         return filterlist.get(cursor);
 1416  
                 }
 1417  
 
 1418  
                 /**
 1419  
                  * Inserts the specified element into the list .
 1420  
                  */
 1421  
                 @Override
 1422  
                 public void add(final Content obj) {
 1423  14789
                         checkConcurrent();
 1424  
                         // always add before what would normally be returned by next();
 1425  14786
                         final int next = forward ? cursor + 1 : cursor;
 1426  
 
 1427  14786
                         filterlist.add(next, obj);
 1428  
 
 1429  14735
                         expectedmod = getModCount();
 1430  
 
 1431  14735
                         canremove = canset = false;
 1432  
 
 1433  
                         // a call to next() should be unaffected, so, whatever was going to
 1434  
                         // be next will still be next, remember, what was going to be next
 1435  
                         // has been shifted 'right' by our insert.
 1436  
                         // we ensure this by setting the cursor to next(), and making it
 1437  
                         // forward
 1438  14735
                         cursor = next;
 1439  14735
                         forward = true;
 1440  14735
                 }
 1441  
 
 1442  
                 /**
 1443  
                  * Removes from the list the last element that was returned by the last
 1444  
                  * call to <code>next</code> or <code>previous</code>.
 1445  
                  */
 1446  
                 @Override
 1447  
                 public void remove() {
 1448  29647
                         checkConcurrent();
 1449  29641
                         if (!canremove)
 1450  13851
                                 throw new IllegalStateException("Can not remove an "
 1451  
                                                 + "element unless either next() or previous() has been called "
 1452  
                                                 + "since the last remove()");
 1453  
                         // we are removing the last entry returned by either next() or
 1454  
                         // previous().
 1455  
                         // the idea is to remove it, and pretend that we used to be at the
 1456  
                         // entry that happened *after* the removed entry.
 1457  
                         // so, get what would be the next entry (set at tmpcursor).
 1458  
                         // so call nextIndex to set tmpcursor to what would come after.
 1459  15790
                         filterlist.remove(cursor);
 1460  15790
                         forward = false;
 1461  15790
                         expectedmod = getModCount();
 1462  
 
 1463  15790
                         canremove = false;
 1464  15790
                         canset = false;
 1465  15790
                 }
 1466  
 
 1467  
                 /**
 1468  
                  * Replaces the last element returned by <code>next</code> or
 1469  
                  * <code>previous</code> with the specified element.
 1470  
                  */
 1471  
                 @Override
 1472  
                 public void set(final F obj) {
 1473  1923
                         checkConcurrent();
 1474  1920
                         if (!canset) {
 1475  452
                                 throw new IllegalStateException("Can not set an element "
 1476  
                                                 + "unless either next() or previous() has been called since the "
 1477  
                                                 + "last remove() or set()");
 1478  
                         }
 1479  
 
 1480  1468
                         filterlist.set(cursor, obj);
 1481  1417
                         expectedmod = getModCount();
 1482  
 
 1483  1417
                 }
 1484  
 
 1485  
         }
 1486  
 
 1487  
 }