/**
   * Compares the specified Object with the receiver. Returns true if and only if the specified
   * Object is also an ArrayList of the same type, both Lists have the same size, and all
   * corresponding pairs of elements in the two Lists are identical. In other words, two Lists are
   * defined to be equal if they contain the same elements in the same order.
   *
   * @param otherObj the Object to be compared for equality with the receiver.
   * @return true if the specified Object is equal to the receiver.
   */
  public boolean equals(Object otherObj) { // delta
    // overridden for performance only.
    if (!(otherObj instanceof ByteArrayList)) return super.equals(otherObj);
    if (this == otherObj) return true;
    if (otherObj == null) return false;
    ByteArrayList other = (ByteArrayList) otherObj;
    if (size() != other.size()) return false;

    byte[] theElements = elements();
    byte[] otherElements = other.elements();
    for (int i = size(); --i >= 0; ) {
      if (theElements[i] != otherElements[i]) return false;
    }
    return true;
  }
  /**
   * Removes from the receiver all elements that are contained in the specified list. Tests for
   * identity.
   *
   * @param other the other list.
   * @return <code>true</code> if the receiver changed as a result of the call.
   */
  public boolean removeAll(AbstractByteList other) {
    // overridden for performance only.
    if (!(other instanceof ByteArrayList)) return super.removeAll(other);

    /*
     * There are two possibilities to do the thing a) use other.indexOf(...)
     * b) sort other, then use other.binarySearch(...)
     *
     * Let's try to figure out which one is faster. Let M=size,
     * N=other.size, then a) takes O(M*N) steps b) takes O(N*logN + M*logN)
     * steps (sorting is O(N*logN) and binarySearch is O(logN))
     *
     * Hence, if N*logN + M*logN < M*N, we use b) otherwise we use a).
     */
    if (other.size() == 0) {
      return false;
    } // nothing to do
    int limit = other.size() - 1;
    int j = 0;
    byte[] theElements = elements;
    int mySize = size();

    double N = (double) other.size();
    double M = (double) mySize;
    if ((N + M) * cern.jet.math.Arithmetic.log2(N) < M * N) {
      // it is faster to sort other before searching in it
      ByteArrayList sortedList = (ByteArrayList) other.clone();
      sortedList.quickSort();

      for (int i = 0; i < mySize; i++) {
        if (sortedList.binarySearchFromTo(theElements[i], 0, limit) < 0)
          theElements[j++] = theElements[i];
      }
    } else {
      // it is faster to search in other without sorting
      for (int i = 0; i < mySize; i++) {
        if (other.indexOfFromTo(theElements[i], 0, limit) < 0) theElements[j++] = theElements[i];
      }
    }

    boolean modified = (j != mySize);
    setSize(j);
    return modified;
  }
 /**
  * Returns a deep copy of the receiver.
  *
  * @return a deep copy of the receiver.
  */
 public Object clone() {
   // overridden for performance only.
   ByteArrayList clone = new ByteArrayList((byte[]) elements.clone());
   clone.setSizeRaw(size);
   return clone;
 }