Package com.orientechnologies.common.collection

Source Code of com.orientechnologies.common.collection.OMVRBTree$NavigableSubMap$SubMapEntryIterator

/*
* Copyright 1999-2010 Luca Garulli (l.garulli--at--orientechnologies.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.orientechnologies.common.collection;

import java.io.IOException;
import java.util.AbstractCollection;
import java.util.AbstractMap;
import java.util.AbstractSet;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.ConcurrentModificationException;
import java.util.Iterator;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.SortedMap;
import java.util.SortedSet;

import com.orientechnologies.common.log.OLogManager;
import com.orientechnologies.common.profiler.OProfiler;

/**
* Base abstract class of MVRB-Tree algorithm.
*
* @author Luca Garulli (l.garulli--at--orientechnologies.com)
*
* @param <K>
*          Key type
* @param <V>
*          Value type
*/
@SuppressWarnings({ "unchecked", "serial" })
public abstract class OMVRBTree<K, V> extends AbstractMap<K, V> implements ONavigableMap<K, V>, Cloneable, java.io.Serializable {
  protected OMVRBTreeEventListener<K, V>    listener;
  boolean                                    pageItemFound        = false;
  protected int                              pageItemComparator  = 0;
  protected int                              pageIndex            = -1;
  protected int                              lastPageSize        = 63;    // PERSISTENT FIELDS

  /**
   * The number of entries in the tree
   */
  protected int                              size                = 0;      // PERSISTENT FIELDS
  protected float                            pageLoadFactor      = 0.7f;

  /**
   * The comparator used to maintain order in this tree map, or null if it uses the natural ordering of its keys.
   *
   * @serial
   */
  protected final Comparator<? super K>      comparator;
  protected transient OMVRBTreeEntry<K, V>  root                = null;

  /**
   * The number of structural modifications to the tree.
   */
  transient int                              modCount            = 0;
  protected transient boolean                runtimeCheckEnabled  = false;
  protected transient boolean                debug                = false;

  protected Object                          lastSearchKey;
  protected OMVRBTreeEntry<K, V>            lastSearchNode;
  protected boolean                          lastSearchFound      = false;
  protected int                              lastSearchIndex      = -1;

  public OMVRBTree(final int iSize, final float iLoadFactor) {
    lastPageSize = iSize;
    pageLoadFactor = iLoadFactor;
    comparator = null;
    init();
  }

  public OMVRBTree(final OMVRBTreeEventListener<K, V> iListener) {
    init();
    comparator = null;
    listener = iListener;
  }

  /**
   * Constructs a new, empty tree map, using the natural ordering of its keys. All keys inserted into the map must implement the
   * {@link Comparable} interface. Furthermore, all such keys must be <i>mutually comparable</i>: <tt>k1.compareTo(k2)</tt> must not
   * throw a <tt>ClassCastException</tt> for any keys <tt>k1</tt> and <tt>k2</tt> in the map. If the user attempts to put a key into
   * the map that violates this constraint (for example, the user attempts to put a string key into a map whose keys are integers),
   * the <tt>put(Object key, Object value)</tt> call will throw a <tt>ClassCastException</tt>.
   */
  public OMVRBTree() {
    init();
    comparator = null;
  }

  /**
   * Constructs a new, empty tree map, ordered according to the given comparator. All keys inserted into the map must be <i>mutually
   * comparable</i> by the given comparator: <tt>comparator.compare(k1,
   * k2)</tt> must not throw a <tt>ClassCastException</tt> for any keys <tt>k1</tt> and <tt>k2</tt> in the map. If the user attempts
   * to put a key into the map that violates this constraint, the <tt>put(Object
   * key, Object value)</tt> call will throw a <tt>ClassCastException</tt>.
   *
   * @param comparator
   *          the comparator that will be used to order this map. If <tt>null</tt>, the {@linkplain Comparable natural ordering} of
   *          the keys will be used.
   */
  public OMVRBTree(final Comparator<? super K> comparator) {
    init();
    this.comparator = comparator;
  }

  /**
   * Constructs a new tree map containing the same mappings as the given map, ordered according to the <i>natural ordering</i> of
   * its keys. All keys inserted into the new map must implement the {@link Comparable} interface. Furthermore, all such keys must
   * be <i>mutually comparable</i>: <tt>k1.compareTo(k2)</tt> must not throw a <tt>ClassCastException</tt> for any keys <tt>k1</tt>
   * and <tt>k2</tt> in the map. This method runs in n*log(n) time.
   *
   * @param m
   *          the map whose mappings are to be placed in this map
   * @throws ClassCastException
   *           if the keys in m are not {@link Comparable}, or are not mutually comparable
   * @throws NullPointerException
   *           if the specified map is null
   */
  public OMVRBTree(final Map<? extends K, ? extends V> m) {
    init();
    comparator = null;
    putAll(m);
  }

  /**
   * Constructs a new tree map containing the same mappings and using the same ordering as the specified sorted map. This method
   * runs in linear time.
   *
   * @param m
   *          the sorted map whose mappings are to be placed in this map, and whose comparator is to be used to sort this map
   * @throws NullPointerException
   *           if the specified map is null
   */
  public OMVRBTree(final SortedMap<K, ? extends V> m) {
    init();
    comparator = m.comparator();
    try {
      buildFromSorted(m.size(), m.entrySet().iterator(), null, null);
    } catch (java.io.IOException cannotHappen) {
    } catch (ClassNotFoundException cannotHappen) {
    }
  }

  /**
   * Create a new entry with the first key/value to handle.
   */
  protected abstract OMVRBTreeEntry<K, V> createEntry(final K key, final V value);

  /**
   * Create a new node with the same parent of the node is splitting.
   */
  protected abstract OMVRBTreeEntry<K, V> createEntry(final OMVRBTreeEntry<K, V> parent);

  public int getNodes() {
    int counter = -1;

    OMVRBTreeEntry<K, V> entry = getFirstEntry();
    while (entry != null) {
      entry = successor(entry);
      counter++;
    }

    return counter;
  }

  /**
   * Returns the number of key-value mappings in this map.
   *
   * @return the number of key-value mappings in this map
   */
  @Override
  public int size() {
    return size;
  }

  /**
   * Returns <tt>true</tt> if this map contains a mapping for the specified key.
   *
   * @param key
   *          key whose presence in this map is to be tested
   * @return <tt>true</tt> if this map contains a mapping for the specified key
   * @throws ClassCastException
   *           if the specified key cannot be compared with the keys currently in the map
   * @throws NullPointerException
   *           if the specified key is null and this map uses natural ordering, or its comparator does not permit null keys
   */
  @Override
  public boolean containsKey(final Object key) {
    return getEntry(key) != null;
  }

  /**
   * Returns <tt>true</tt> if this map maps one or more keys to the specified value. More formally, returns <tt>true</tt> if and
   * only if this map contains at least one mapping to a value <tt>v</tt> such that
   * <tt>(value==null ? v==null : value.equals(v))</tt>. This operation will probably require time linear in the map size for most
   * implementations.
   *
   * @param value
   *          value whose presence in this map is to be tested
   * @return <tt>true</tt> if a mapping to <tt>value</tt> exists; <tt>false</tt> otherwise
   * @since 1.2
   */
  @Override
  public boolean containsValue(final Object value) {
    for (OMVRBTreeEntry<K, V> e = getFirstEntry(); e != null; e = next(e))
      if (valEquals(value, e.getValue()))
        return true;
    return false;
  }

  /**
   * Returns the value to which the specified key is mapped, or {@code null} if this map contains no mapping for the key.
   *
   * <p>
   * More formally, if this map contains a mapping from a key {@code k} to a value {@code v} such that {@code key} compares equal to
   * {@code k} according to the map's ordering, then this method returns {@code v}; otherwise it returns {@code null}. (There can be
   * at most one such mapping.)
   *
   * <p>
   * A return value of {@code null} does not <i>necessarily</i> indicate that the map contains no mapping for the key; it's also
   * possible that the map explicitly maps the key to {@code null}. The {@link #containsKey containsKey} operation may be used to
   * distinguish these two cases.
   *
   * @throws ClassCastException
   *           if the specified key cannot be compared with the keys currently in the map
   * @throws NullPointerException
   *           if the specified key is null and this map uses natural ordering, or its comparator does not permit null keys
   */
  @Override
  public V get(final Object key) {
    if (size == 0)
      return null;

    OMVRBTreeEntry<K, V> entry = null;

    final long timer = OProfiler.getInstance().startChrono();

    try {
      // TRY TO GET LATEST SEARCH
      final OMVRBTreeEntry<K, V> node = getLastSearchNodeForSameKey(key);
      if (node != null) {
        // SAME SEARCH OF PREVIOUS ONE: REUSE LAST RESULT?
        if (lastSearchFound)
          // REUSE LAST RESULT, OTHERWISE THE KEY NOT EXISTS
          return node.getValue(lastSearchIndex);
      } else
        // SEARCH THE ITEM
        entry = getEntry(key);

      return entry == null ? null : entry.getValue();

    } finally {
      OProfiler.getInstance().stopChrono("OMVRBTree.get", timer);
    }
  }

  public Comparator<? super K> comparator() {
    return comparator;
  }

  /**
   * @throws NoSuchElementException
   *           {@inheritDoc}
   */
  public K firstKey() {
    return key(getFirstEntry());
  }

  /**
   * @throws NoSuchElementException
   *           {@inheritDoc}
   */
  public K lastKey() {
    return key(getLastEntry());
  }

  /**
   * Copies all of the mappings from the specified map to this map. These mappings replace any mappings that this map had for any of
   * the keys currently in the specified map.
   *
   * @param map
   *          mappings to be stored in this map
   * @throws ClassCastException
   *           if the class of a key or value in the specified map prevents it from being stored in this map
   * @throws NullPointerException
   *           if the specified map is null or the specified map contains a null key and this map does not permit null keys
   */
  @Override
  public void putAll(final Map<? extends K, ? extends V> map) {
    int mapSize = map.size();
    if (size == 0 && mapSize != 0 && map instanceof SortedMap) {
      Comparator<?> c = ((SortedMap<? extends K, ? extends V>) map).comparator();
      if (c == comparator || (c != null && c.equals(comparator))) {
        ++modCount;
        try {
          buildFromSorted(mapSize, map.entrySet().iterator(), null, null);
        } catch (java.io.IOException cannotHappen) {
        } catch (ClassNotFoundException cannotHappen) {
        }
        return;
      }
    }
    super.putAll(map);
  }

  /**
   * Returns this map's entry for the given key, or <tt>null</tt> if the map does not contain an entry for the key.
   *
   * @return this map's entry for the given key, or <tt>null</tt> if the map does not contain an entry for the key
   * @throws ClassCastException
   *           if the specified key cannot be compared with the keys currently in the map
   * @throws NullPointerException
   *           if the specified key is null and this map uses natural ordering, or its comparator does not permit null keys
   */
  protected final OMVRBTreeEntry<K, V> getEntry(final Object key) {
    return getEntry(key, false);
  }

  final OMVRBTreeEntry<K, V> getEntry(final Object key, final boolean iGetContainer) {
    if (key == null)
      return setLastSearchNode(null, null);

    // 1^ CHANCE - TRY TO SEE IF LAST USED NODE IS GOOD: THIS IS VERY COMMON CASE ON INSERTION WITH AN INCREMENTING KEY
    // OMVRBTreeEntry<K, V> entry = OMVRBTreeThreadLocal.INSTANCE.getLatest();
    // if (entry != null && entry.getSize() > 0) {
    // final Comparable k = (Comparable) key;
    // if (k.compareTo(entry.getFirstKey()) >= 0)
    // if (k.compareTo(entry.getLastKey()) <= 0 || successor(entry) == null) {
    // return entry;
    // }
    // }

    pageItemFound = false;

    if (size == 0) {
      pageIndex = 0;
      return iGetContainer ? root : null;
    }

    OMVRBTreeEntry<K, V> p = getBestEntryPoint(key);

    checkTreeStructure(p);

    if (p == null)
      return setLastSearchNode(key, null);

    OMVRBTreeEntry<K, V> lastNode = p;
    OMVRBTreeEntry<K, V> prevNode = null;
    OMVRBTreeEntry<K, V> tmpNode;
    int beginKey = -1;
    int steps = -1;
    final Comparable<? super K> k = (Comparable<? super K>) key;

    try {
      while (p != null && p.getSize() > 0) {
        steps++;

        lastNode = p;

        if (comparator != null)
          beginKey = comparator.compare((K) key, p.getFirstKey());
        else
          try {
            beginKey = k.compareTo(p.getFirstKey());
          } catch (Exception e) {
          }

        if (beginKey == 0) {
          // EXACT MATCH, YOU'RE VERY LUCKY: RETURN THE FIRST KEY WITHOUT SEARCH INSIDE THE NODE
          pageIndex = 0;
          pageItemFound = true;
          pageItemComparator = 0;
          return setLastSearchNode(key, p);
        }

        if (comparator != null)
          pageItemComparator = comparator.compare((K) key, p.getLastKey());
        else
          pageItemComparator = k.compareTo(p.getLastKey());

        if (beginKey < 0) {
          if (pageItemComparator < 0) {
            // System.out.println("-> Load predecessor of " + p + "...");
            tmpNode = predecessor(p);
            // System.out.println("-> Loaded " + tmpNode);
            if (tmpNode != null && tmpNode != prevNode) {
              // MINOR THAN THE CURRENT: GET THE LEFT NODE
              // p = p.getLeft();
              prevNode = p;
              p = tmpNode;
              continue;
            }
          }
        } else if (beginKey > 0) {
          if (pageItemComparator > 0) {
            // System.out.println("-> Load successor of " + p + "...");
            tmpNode = successor(p);
            // System.out.println("-> Loaded " + tmpNode);
            if (tmpNode != null && tmpNode != prevNode) {
              // MAJOR THAN THE CURRENT: GET THE RIGHT NODE
              // p = p.getRight();
              prevNode = p;
              p = tmpNode;
              continue;
            }
          }
        }

        // SEARCH INSIDE THE NODE
        final V value = lastNode.search(k);

        setLastSearchNode(key, lastNode);

        if (value != null || iGetContainer)
          // FOUND: RETURN CURRENT NODE OR AT LEAST THE CONTAINER NODE
          return lastNode;

        // NOT FOUND
        return null;
      }
    } finally {
      checkTreeStructure(p);

      OProfiler.getInstance().updateStat("[OMVRBTree.getEntry] Steps of search", steps);
    }

    return setLastSearchNode(key, null);
  }

  /**
   * Basic implementation that returns the root node.
   */
  protected OMVRBTreeEntry<K, V> getBestEntryPoint(final Object key) {
    return root;
  }

  public OMVRBTreeEventListener<K, V> getListener() {
    return listener;
  }

  public void setListener(final OMVRBTreeEventListener<K, V> listener) {
    this.listener = listener;
  }

  /**
   * Gets the entry corresponding to the specified key; if no such entry exists, returns the entry for the least key greater than
   * the specified key; if no such entry exists (i.e., the greatest key in the Tree is less than the specified key), returns
   * <tt>null</tt>.
   */
  final OMVRBTreeEntry<K, V> getCeilingEntry(final K key) {
    final OMVRBTreeEntry<K, V> p = getEntry(key, true);

    if (p == null)
      return null;

    if (pageItemFound)
      return p;

    return next(p);
  }

  /**
   * Gets the entry corresponding to the specified key; if no such entry exists, returns the entry for the greatest key less than
   * the specified key; if no such entry exists, returns <tt>null</tt>.
   */
  final OMVRBTreeEntry<K, V> getFloorEntry(final K key) {
    final OMVRBTreeEntry<K, V> p = getEntry(key, true);

    if (p == null)
      return null;

    if (pageItemFound)
      return p;

    return previous(p);
  }

  /**
   * Gets the entry for the least key greater than the specified key; if no such entry exists, returns the entry for the least key
   * greater than the specified key; if no such entry exists returns <tt>null</tt>.
   */
  final OMVRBTreeEntry<K, V> getHigherEntry(final K key) {
    final OMVRBTreeEntry<K, V> p = getEntry(key, true);

    if (p == null)
      return null;

    if (pageItemFound)
      // MATCH, RETURN THE NEXT ONE
      return next(p);
    else if (pageIndex < p.getSize())
      // NOT MATCHED, POSITION IS ALREADY TO THE NEXT ONE
      return p;

    return null;
  }

  /**
   * Returns the entry for the greatest key less than the specified key; if no such entry exists (i.e., the least key in the Tree is
   * greater than the specified key), returns <tt>null</tt>.
   */
  final OMVRBTreeEntry<K, V> getLowerEntry(final K key) {
    final OMVRBTreeEntry<K, V> p = getEntry(key, true);

    if (p == null)
      return null;

    return previous(p);
  }

  /**
   * Associates the specified value with the specified key in this map. If the map previously contained a mapping for the key, the
   * old value is replaced.
   *
   * @param key
   *          key with which the specified value is to be associated
   * @param value
   *          value to be associated with the specified key
   *
   * @return the previous value associated with <tt>key</tt>, or <tt>null</tt> if there was no mapping for <tt>key</tt>. (A
   *         <tt>null</tt> return can also indicate that the map previously associated <tt>null</tt> with <tt>key</tt>.)
   * @throws ClassCastException
   *           if the specified key cannot be compared with the keys currently in the map
   * @throws NullPointerException
   *           if the specified key is null and this map uses natural ordering, or its comparator does not permit null keys
   */
  @Override
  public V put(final K key, final V value) {
    OMVRBTreeEntry<K, V> parentNode = null;

    try {
      if (root == null) {
        root = createEntry(key, value);
        root.setColor(BLACK);

        size = 1;
        modCount++;

        if (listener != null)
          listener.signalTreeChanged(this);

        return null;
      }

      // TRY TO GET LATEST SEARCH
      parentNode = getLastSearchNodeForSameKey(key);
      if (parentNode != null) {
        if (lastSearchFound) {
          // EXACT MATCH: UPDATE THE VALUE
          pageIndex = lastSearchIndex;
          return parentNode.setValue(value);
        }
      }

      // SEARCH THE ITEM
      parentNode = getEntry(key, true);

      if (pageItemFound)
        // EXACT MATCH: UPDATE THE VALUE
        return parentNode.setValue(value);

      setLastSearchNode(null, null);

      if (parentNode == null) {
        parentNode = root;
        pageIndex = 0;
      }

      if (parentNode.getFreeSpace() > 0) {
        // INSERT INTO THE PAGE
        parentNode.insert(pageIndex, key, value);
      } else {
        // CREATE NEW NODE AND COPY HALF OF VALUES FROM THE ORIGIN TO THE NEW ONE IN ORDER TO GET VALUES BALANCED
        final OMVRBTreeEntry<K, V> newNode = createEntry(parentNode);

        if (pageIndex < parentNode.getPageSplitItems())
          // INSERT IN THE ORIGINAL NODE
          parentNode.insert(pageIndex, key, value);
        else
          // INSERT IN THE NEW NODE
          newNode.insert(pageIndex - parentNode.getPageSplitItems(), key, value);

        final OMVRBTreeEntry<K, V> prevNode = parentNode.getRight();

        // REPLACE THE RIGHT ONE WITH THE NEW NODE
        parentNode.setRight(newNode);

        if (prevNode != null) {
          // INSERT THE NODE IN THE TREE IN THE RIGHT MOVING CURRENT RIGHT TO THE RIGHT OF THE NEW NODE
          newNode.setRight(prevNode);
          fixAfterInsertion(prevNode);
        } else
          fixAfterInsertion(newNode);

        checkTreeStructure(parentNode);

        modCount++;
      }

      checkTreeStructure(parentNode);

      size++;

      if (listener != null)
        listener.signalTreeChanged(this);
    } finally {
      checkTreeStructure(parentNode);
    }

    return null;
  }

  /**
   * Removes the mapping for this key from this OMVRBTree if present.
   *
   * @param key
   *          key for which mapping should be removed
   * @return the previous value associated with <tt>key</tt>, or <tt>null</tt> if there was no mapping for <tt>key</tt>. (A
   *         <tt>null</tt> return can also indicate that the map previously associated <tt>null</tt> with <tt>key</tt>.)
   * @throws ClassCastException
   *           if the specified key cannot be compared with the keys currently in the map
   * @throws NullPointerException
   *           if the specified key is null and this map uses natural ordering, or its comparator does not permit null keys
   */
  @Override
  public V remove(final Object key) {
    OMVRBTreeEntry<K, V> p = getEntry(key);
    setLastSearchNode(null, null);
    if (p == null)
      return null;

    V oldValue = p.getValue();
    deleteEntry(p);
    return oldValue;
  }

  /**
   * Removes all of the mappings from this map. The map will be empty after this call returns.
   */
  @Override
  public void clear() {
    modCount++;
    size = 0;
    setLastSearchNode(null, null);
    setRoot(null);
  }

  /**
   * Returns a shallow copy of this <tt>OMVRBTree</tt> instance. (The keys and values themselves are not cloned.)
   *
   * @return a shallow copy of this map
   */
  @Override
  public Object clone() {
    OMVRBTree<K, V> clone = null;
    try {
      clone = (OMVRBTree<K, V>) super.clone();
    } catch (CloneNotSupportedException e) {
      throw new InternalError();
    }

    // Put clone into "virgin" state (except for comparator)
    clone.listener = listener;
    clone.lastPageSize = lastPageSize;
    clone.pageIndex = pageIndex;
    clone.pageItemFound = pageItemFound;
    clone.pageLoadFactor = pageLoadFactor;

    clone.root = null;
    clone.size = 0;
    clone.modCount = 0;
    clone.entrySet = null;
    clone.navigableKeySet = null;
    clone.descendingMap = null;

    // Initialize clone with our mappings
    try {
      clone.buildFromSorted(size, entrySet().iterator(), null, null);
    } catch (java.io.IOException cannotHappen) {
    } catch (ClassNotFoundException cannotHappen) {
    }

    return clone;
  }

  // ONavigableMap API methods

  /**
   * @since 1.6
   */
  public Map.Entry<K, V> firstEntry() {
    return exportEntry(getFirstEntry());
  }

  /**
   * @since 1.6
   */
  public Map.Entry<K, V> lastEntry() {
    return exportEntry(getLastEntry());
  }

  /**
   * @since 1.6
   */
  public Entry<K, V> pollFirstEntry() {
    OMVRBTreeEntry<K, V> p = getFirstEntry();
    Map.Entry<K, V> result = exportEntry(p);
    if (p != null)
      deleteEntry(p);
    return result;
  }

  /**
   * @since 1.6
   */
  public Entry<K, V> pollLastEntry() {
    OMVRBTreeEntry<K, V> p = getLastEntry();
    Map.Entry<K, V> result = exportEntry(p);
    if (p != null)
      deleteEntry(p);
    return result;
  }

  /**
   * @throws ClassCastException
   *           {@inheritDoc}
   * @throws NullPointerException
   *           if the specified key is null and this map uses natural ordering, or its comparator does not permit null keys
   * @since 1.6
   */
  public Map.Entry<K, V> lowerEntry(final K key) {
    return exportEntry(getLowerEntry(key));
  }

  /**
   * @throws ClassCastException
   *           {@inheritDoc}
   * @throws NullPointerException
   *           if the specified key is null and this map uses natural ordering, or its comparator does not permit null keys
   * @since 1.6
   */
  public K lowerKey(final K key) {
    return keyOrNull(getLowerEntry(key));
  }

  /**
   * @throws ClassCastException
   *           {@inheritDoc}
   * @throws NullPointerException
   *           if the specified key is null and this map uses natural ordering, or its comparator does not permit null keys
   * @since 1.6
   */
  public Map.Entry<K, V> floorEntry(final K key) {
    return exportEntry(getFloorEntry(key));
  }

  /**
   * @throws ClassCastException
   *           {@inheritDoc}
   * @throws NullPointerException
   *           if the specified key is null and this map uses natural ordering, or its comparator does not permit null keys
   * @since 1.6
   */
  public K floorKey(final K key) {
    return keyOrNull(getFloorEntry(key));
  }

  /**
   * @throws ClassCastException
   *           {@inheritDoc}
   * @throws NullPointerException
   *           if the specified key is null and this map uses natural ordering, or its comparator does not permit null keys
   * @since 1.6
   */
  public Map.Entry<K, V> ceilingEntry(final K key) {
    return exportEntry(getCeilingEntry(key));
  }

  /**
   * @throws ClassCastException
   *           {@inheritDoc}
   * @throws NullPointerException
   *           if the specified key is null and this map uses natural ordering, or its comparator does not permit null keys
   * @since 1.6
   */
  public K ceilingKey(final K key) {
    return keyOrNull(getCeilingEntry(key));
  }

  /**
   * @throws ClassCastException
   *           {@inheritDoc}
   * @throws NullPointerException
   *           if the specified key is null and this map uses natural ordering, or its comparator does not permit null keys
   * @since 1.6
   */
  public Map.Entry<K, V> higherEntry(final K key) {
    return exportEntry(getHigherEntry(key));
  }

  /**
   * @throws ClassCastException
   *           {@inheritDoc}
   * @throws NullPointerException
   *           if the specified key is null and this map uses natural ordering, or its comparator does not permit null keys
   * @since 1.6
   */
  public K higherKey(final K key) {
    return keyOrNull(getHigherEntry(key));
  }

  // Views

  /**
   * Fields initialized to contain an instance of the entry set view the first time this view is requested. Views are stateless, so
   * there's no reason to create more than one.
   */
  private transient EntrySet            entrySet        = null;
  private transient KeySet<K>            navigableKeySet  = null;
  private transient ONavigableMap<K, V>  descendingMap    = null;

  /**
   * Returns a {@link Set} view of the keys contained in this map. The set's iterator returns the keys in ascending order. The set
   * is backed by the map, so changes to the map are reflected in the set, and vice-versa. If the map is modified while an iteration
   * over the set is in progress (except through the iterator's own <tt>remove</tt> operation), the results of the iteration are
   * undefined. The set supports element removal, which removes the corresponding mapping from the map, via the
   * <tt>Iterator.remove</tt>, <tt>Set.remove</tt>, <tt>removeAll</tt>, <tt>retainAll</tt>, and <tt>clear</tt> operations. It does
   * not support the <tt>add</tt> or <tt>addAll</tt> operations.
   */
  @Override
  public Set<K> keySet() {
    return navigableKeySet();
  }

  /**
   * @since 1.6
   */
  public ONavigableSet<K> navigableKeySet() {
    KeySet<K> nks = navigableKeySet;
    return (nks != null) ? nks : (navigableKeySet = (KeySet<K>) new KeySet<Object>((ONavigableMap<Object, Object>) this));
  }

  /**
   * @since 1.6
   */
  public ONavigableSet<K> descendingKeySet() {
    return descendingMap().navigableKeySet();
  }

  /**
   * Returns a {@link Collection} view of the values contained in this map. The collection's iterator returns the values in
   * ascending order of the corresponding keys. The collection is backed by the map, so changes to the map are reflected in the
   * collection, and vice-versa. If the map is modified while an iteration over the collection is in progress (except through the
   * iterator's own <tt>remove</tt> operation), the results of the iteration are undefined. The collection supports element removal,
   * which removes the corresponding mapping from the map, via the <tt>Iterator.remove</tt>, <tt>Collection.remove</tt>,
   * <tt>removeAll</tt>, <tt>retainAll</tt> and <tt>clear</tt> operations. It does not support the <tt>add</tt> or <tt>addAll</tt>
   * operations.
   */
  @Override
  public Collection<V> values() {
    final Collection<V> vs = super.values();
    return (vs != null) ? vs : null;
  }

  /**
   * Returns a {@link Set} view of the mappings contained in this map. The set's iterator returns the entries in ascending key
   * order. The set is backed by the map, so changes to the map are reflected in the set, and vice-versa. If the map is modified
   * while an iteration over the set is in progress (except through the iterator's own <tt>remove</tt> operation, or through the
   * <tt>setValue</tt> operation on a map entry returned by the iterator) the results of the iteration are undefined. The set
   * supports element removal, which removes the corresponding mapping from the map, via the <tt>Iterator.remove</tt>,
   * <tt>Set.remove</tt>, <tt>removeAll</tt>, <tt>retainAll</tt> and <tt>clear</tt> operations. It does not support the <tt>add</tt>
   * or <tt>addAll</tt> operations.
   */
  @Override
  public Set<Map.Entry<K, V>> entrySet() {
    EntrySet es = entrySet;
    return (es != null) ? es : (entrySet = new EntrySet());
  }

  /**
   * @since 1.6
   */
  public ONavigableMap<K, V> descendingMap() {
    ONavigableMap<K, V> km = descendingMap;
    return (km != null) ? km : (descendingMap = new DescendingSubMap<K, V>(this, true, null, true, true, null, true));
  }

  /**
   * @throws ClassCastException
   *           {@inheritDoc}
   * @throws NullPointerException
   *           if <tt>fromKey</tt> or <tt>toKey</tt> is null and this map uses natural ordering, or its comparator does not permit
   *           null keys
   * @throws IllegalArgumentException
   *           {@inheritDoc}
   * @since 1.6
   */
  public ONavigableMap<K, V> subMap(K fromKey, boolean fromInclusive, K toKey, boolean toInclusive) {
    return new AscendingSubMap<K, V>(this, false, fromKey, fromInclusive, false, toKey, toInclusive);
  }

  /**
   * @throws ClassCastException
   *           {@inheritDoc}
   * @throws NullPointerException
   *           if <tt>toKey</tt> is null and this map uses natural ordering, or its comparator does not permit null keys
   * @throws IllegalArgumentException
   *           {@inheritDoc}
   * @since 1.6
   */
  public ONavigableMap<K, V> headMap(K toKey, boolean inclusive) {
    return new AscendingSubMap<K, V>(this, true, null, true, false, toKey, inclusive);
  }

  /**
   * @throws ClassCastException
   *           {@inheritDoc}
   * @throws NullPointerException
   *           if <tt>fromKey</tt> is null and this map uses natural ordering, or its comparator does not permit null keys
   * @throws IllegalArgumentException
   *           {@inheritDoc}
   * @since 1.6
   */
  public ONavigableMap<K, V> tailMap(K fromKey, boolean inclusive) {
    return new AscendingSubMap<K, V>(this, false, fromKey, inclusive, true, null, true);
  }

  /**
   * @throws ClassCastException
   *           {@inheritDoc}
   * @throws NullPointerException
   *           if <tt>fromKey</tt> or <tt>toKey</tt> is null and this map uses natural ordering, or its comparator does not permit
   *           null keys
   * @throws IllegalArgumentException
   *           {@inheritDoc}
   */
  public SortedMap<K, V> subMap(K fromKey, K toKey) {
    return subMap(fromKey, true, toKey, false);
  }

  /**
   * @throws ClassCastException
   *           {@inheritDoc}
   * @throws NullPointerException
   *           if <tt>toKey</tt> is null and this map uses natural ordering, or its comparator does not permit null keys
   * @throws IllegalArgumentException
   *           {@inheritDoc}
   */
  public SortedMap<K, V> headMap(K toKey) {
    return headMap(toKey, false);
  }

  /**
   * @throws ClassCastException
   *           {@inheritDoc}
   * @throws NullPointerException
   *           if <tt>fromKey</tt> is null and this map uses natural ordering, or its comparator does not permit null keys
   * @throws IllegalArgumentException
   *           {@inheritDoc}
   */
  public SortedMap<K, V> tailMap(K fromKey) {
    return tailMap(fromKey, true);
  }

  // View class support

  class Values extends AbstractCollection<V> {
    @Override
    public Iterator<V> iterator() {
      return new ValueIterator(getFirstEntry());
    }

    @Override
    public int size() {
      return OMVRBTree.this.size();
    }

    @Override
    public boolean contains(Object o) {
      return OMVRBTree.this.containsValue(o);
    }

    @Override
    public boolean remove(Object o) {
      for (OMVRBTreeEntry<K, V> e = getFirstEntry(); e != null; e = next(e)) {
        if (valEquals(e.getValue(), o)) {
          deleteEntry(e);
          return true;
        }
      }
      return false;
    }

    @Override
    public void clear() {
      OMVRBTree.this.clear();
    }
  }

  class EntrySet extends AbstractSet<Map.Entry<K, V>> {
    @Override
    public Iterator<Map.Entry<K, V>> iterator() {
      return new EntryIterator(getFirstEntry());
    }

    @Override
    public boolean contains(Object o) {
      if (!(o instanceof Map.Entry))
        return false;
      OMVRBTreeEntry<K, V> entry = (OMVRBTreeEntry<K, V>) o;
      V value = entry.getValue();
      V p = get(entry.getKey());
      return p != null && valEquals(p, value);
    }

    @Override
    public boolean remove(Object o) {
      if (!(o instanceof Map.Entry))
        return false;
      OMVRBTreeEntry<K, V> entry = (OMVRBTreeEntry<K, V>) o;
      V value = entry.getValue();
      OMVRBTreeEntry<K, V> p = getEntry(entry.getKey());
      if (p != null && valEquals(p.getValue(), value)) {
        deleteEntry(p);
        return true;
      }
      return false;
    }

    @Override
    public int size() {
      return OMVRBTree.this.size();
    }

    @Override
    public void clear() {
      OMVRBTree.this.clear();
    }
  }

  /*
   * Unlike Values and EntrySet, the KeySet class is static, delegating to a ONavigableMap to allow use by SubMaps, which outweighs
   * the ugliness of needing type-tests for the following Iterator methods that are defined appropriately in main versus submap
   * classes.
   */

  Iterator<K> keyIterator() {
    return new KeyIterator(getFirstEntry());
  }

  Iterator<K> descendingKeyIterator() {
    return new DescendingKeyIterator(getLastEntry());
  }

  @SuppressWarnings("rawtypes")
  static final class KeySet<E> extends AbstractSet<E> implements ONavigableSet<E> {
    private final ONavigableMap<E, Object>  m;

    KeySet(ONavigableMap<E, Object> map) {
      m = map;
    }

    @Override
    public Iterator<E> iterator() {
      if (m instanceof OMVRBTree)
        return ((OMVRBTree<E, Object>) m).keyIterator();
      else
        return (((OMVRBTree.NavigableSubMap) m).keyIterator());
    }

    public Iterator<E> descendingIterator() {
      if (m instanceof OMVRBTree)
        return ((OMVRBTree<E, Object>) m).descendingKeyIterator();
      else
        return (((OMVRBTree.NavigableSubMap) m).descendingKeyIterator());
    }

    @Override
    public int size() {
      return m.size();
    }

    @Override
    public boolean isEmpty() {
      return m.isEmpty();
    }

    @Override
    public boolean contains(Object o) {
      return m.containsKey(o);
    }

    @Override
    public void clear() {
      m.clear();
    }

    public E lower(E e) {
      return m.lowerKey(e);
    }

    public E floor(E e) {
      return m.floorKey(e);
    }

    public E ceiling(E e) {
      return m.ceilingKey(e);
    }

    public E higher(E e) {
      return m.higherKey(e);
    }

    public E first() {
      return m.firstKey();
    }

    public E last() {
      return m.lastKey();
    }

    public Comparator<? super E> comparator() {
      return m.comparator();
    }

    public E pollFirst() {
      Map.Entry<E, Object> e = m.pollFirstEntry();
      return e == null ? null : e.getKey();
    }

    public E pollLast() {
      Map.Entry<E, Object> e = m.pollLastEntry();
      return e == null ? null : e.getKey();
    }

    @Override
    public boolean remove(Object o) {
      int oldSize = size();
      m.remove(o);
      return size() != oldSize;
    }

    public ONavigableSet<E> subSet(E fromElement, boolean fromInclusive, E toElement, boolean toInclusive) {
      return new OMVRBTreeSetMemory<E>(m.subMap(fromElement, fromInclusive, toElement, toInclusive));
    }

    public ONavigableSet<E> headSet(E toElement, boolean inclusive) {
      return new OMVRBTreeSetMemory<E>(m.headMap(toElement, inclusive));
    }

    public ONavigableSet<E> tailSet(E fromElement, boolean inclusive) {
      return new OMVRBTreeSetMemory<E>(m.tailMap(fromElement, inclusive));
    }

    public SortedSet<E> subSet(E fromElement, E toElement) {
      return subSet(fromElement, true, toElement, false);
    }

    public SortedSet<E> headSet(E toElement) {
      return headSet(toElement, false);
    }

    public SortedSet<E> tailSet(E fromElement) {
      return tailSet(fromElement, true);
    }

    public ONavigableSet<E> descendingSet() {
      return new OMVRBTreeSetMemory<E>(m.descendingMap());
    }
  }

  final class EntryIterator extends AbstractEntryIterator<K, V, Map.Entry<K, V>> {
    EntryIterator(OMVRBTreeEntry<K, V> first) {
      super(first);
    }

    public Map.Entry<K, V> next() {
      return nextEntry();
    }
  }

  final class ValueIterator extends AbstractEntryIterator<K, V, V> {
    ValueIterator(OMVRBTreeEntry<K, V> first) {
      super(first);
    }

    public V next() {
      return nextEntry().getValue();
    }
  }

  final class KeyIterator extends AbstractEntryIterator<K, V, K> {
    KeyIterator(OMVRBTreeEntry<K, V> first) {
      super(first);
    }

    public K next() {
      return nextEntry().getKey();
    }
  }

  final class DescendingKeyIterator extends AbstractEntryIterator<K, V, K> {
    DescendingKeyIterator(OMVRBTreeEntry<K, V> first) {
      super(first);
    }

    public K next() {
      return prevEntry().getKey();
    }
  }

  // Little utilities

  /**
   * Compares two keys using the correct comparison method for this OMVRBTree.
   */
  final int compare(Object k1, Object k2) {
    return comparator == null ? ((Comparable<? super K>) k1).compareTo((K) k2) : comparator.compare((K) k1, (K) k2);
  }

  /**
   * Test two values for equality. Differs from o1.equals(o2) only in that it copes with <tt>null</tt> o1 properly.
   */
  final static boolean valEquals(Object o1, Object o2) {
    return (o1 == null ? o2 == null : o1.equals(o2));
  }

  /**
   * Return SimpleImmutableEntry for entry, or null if null
   */
  static <K, V> Map.Entry<K, V> exportEntry(OMVRBTreeEntry<K, V> omvrbTreeEntryPosition) {
    return omvrbTreeEntryPosition == null ? null : new OSimpleImmutableEntry<K, V>(omvrbTreeEntryPosition);
  }

  /**
   * Return SimpleImmutableEntry for entry, or null if null
   */
  static <K, V> Map.Entry<K, V> exportEntry(OMVRBTreeEntryPosition<K, V> omvrbTreeEntryPosition) {
    return omvrbTreeEntryPosition == null ? null : new OSimpleImmutableEntry<K, V>(omvrbTreeEntryPosition.entry);
  }

  /**
   * Return key for entry, or null if null
   */
  static <K, V> K keyOrNull(OMVRBTreeEntry<K, V> e) {
    return e == null ? null : e.getKey();
  }

  /**
   * Return key for entry, or null if null
   */
  static <K, V> K keyOrNull(OMVRBTreeEntryPosition<K, V> e) {
    return e == null ? null : e.getKey();
  }

  /**
   * Returns the key corresponding to the specified Entry.
   *
   * @throws NoSuchElementException
   *           if the Entry is null
   */
  static <K> K key(OMVRBTreeEntry<K, ?> e) {
    if (e == null)
      throw new NoSuchElementException();
    return e.getKey();
  }

  // SubMaps

  /**
   * @serial include
   */
  static abstract class NavigableSubMap<K, V> extends AbstractMap<K, V> implements ONavigableMap<K, V>, java.io.Serializable {
    /**
     * The backing map.
     */
    final OMVRBTree<K, V>  m;

    /**
     * Endpoints are represented as triples (fromStart, lo, loInclusive) and (toEnd, hi, hiInclusive). If fromStart is true, then
     * the low (absolute) bound is the start of the backing map, and the other values are ignored. Otherwise, if loInclusive is
     * true, lo is the inclusive bound, else lo is the exclusive bound. Similarly for the upper bound.
     */
    final K                lo, hi;
    final boolean          fromStart, toEnd;
    final boolean          loInclusive, hiInclusive;

    NavigableSubMap(OMVRBTree<K, V> m, boolean fromStart, K lo, boolean loInclusive, boolean toEnd, K hi, boolean hiInclusive) {
      if (!fromStart && !toEnd) {
        if (m.compare(lo, hi) > 0)
          throw new IllegalArgumentException("fromKey > toKey");
      } else {
        if (!fromStart) // type check
          m.compare(lo, lo);
        if (!toEnd)
          m.compare(hi, hi);
      }

      this.m = m;
      this.fromStart = fromStart;
      this.lo = lo;
      this.loInclusive = loInclusive;
      this.toEnd = toEnd;
      this.hi = hi;
      this.hiInclusive = hiInclusive;
    }

    // internal utilities

    final boolean tooLow(Object key) {
      if (!fromStart) {
        int c = m.compare(key, lo);
        if (c < 0 || (c == 0 && !loInclusive))
          return true;
      }
      return false;
    }

    final boolean tooHigh(Object key) {
      if (!toEnd) {
        int c = m.compare(key, hi);
        if (c > 0 || (c == 0 && !hiInclusive))
          return true;
      }
      return false;
    }

    final boolean inRange(Object key) {
      return !tooLow(key) && !tooHigh(key);
    }

    final boolean inClosedRange(Object key) {
      return (fromStart || m.compare(key, lo) >= 0) && (toEnd || m.compare(hi, key) >= 0);
    }

    final boolean inRange(Object key, boolean inclusive) {
      return inclusive ? inRange(key) : inClosedRange(key);
    }

    /*
     * Absolute versions of relation operations. Subclasses map to these using like-named "sub" versions that invert senses for
     * descending maps
     */

    final OMVRBTreeEntryPosition<K, V> absLowest() {
      OMVRBTreeEntry<K, V> e = (fromStart ? m.getFirstEntry() : (loInclusive ? m.getCeilingEntry(lo) : m.getHigherEntry(lo)));
      return (e == null || tooHigh(e.getKey())) ? null : new OMVRBTreeEntryPosition<K, V>(e);
    }

    final OMVRBTreeEntryPosition<K, V> absHighest() {
      OMVRBTreeEntry<K, V> e = (toEnd ? m.getLastEntry() : (hiInclusive ? m.getFloorEntry(hi) : m.getLowerEntry(hi)));
      return (e == null || tooLow(e.getKey())) ? null : new OMVRBTreeEntryPosition<K, V>(e);
    }

    final OMVRBTreeEntryPosition<K, V> absCeiling(K key) {
      if (tooLow(key))
        return absLowest();
      OMVRBTreeEntry<K, V> e = m.getCeilingEntry(key);
      return (e == null || tooHigh(e.getKey())) ? null : new OMVRBTreeEntryPosition<K, V>(e);
    }

    final OMVRBTreeEntryPosition<K, V> absHigher(K key) {
      if (tooLow(key))
        return absLowest();
      OMVRBTreeEntry<K, V> e = m.getHigherEntry(key);
      return (e == null || tooHigh(e.getKey())) ? null : new OMVRBTreeEntryPosition<K, V>(e);
    }

    final OMVRBTreeEntryPosition<K, V> absFloor(K key) {
      if (tooHigh(key))
        return absHighest();
      OMVRBTreeEntry<K, V> e = m.getFloorEntry(key);
      return (e == null || tooLow(e.getKey())) ? null : new OMVRBTreeEntryPosition<K, V>(e);
    }

    final OMVRBTreeEntryPosition<K, V> absLower(K key) {
      if (tooHigh(key))
        return absHighest();
      OMVRBTreeEntry<K, V> e = m.getLowerEntry(key);
      return (e == null || tooLow(e.getKey())) ? null : new OMVRBTreeEntryPosition<K, V>(e);
    }

    /** Returns the absolute high fence for ascending traversal */
    final OMVRBTreeEntryPosition<K, V> absHighFence() {
      return (toEnd ? null : new OMVRBTreeEntryPosition<K, V>(hiInclusive ? m.getHigherEntry(hi) : m.getCeilingEntry(hi)));
    }

    /** Return the absolute low fence for descending traversal */
    final OMVRBTreeEntryPosition<K, V> absLowFence() {
      return (fromStart ? null : new OMVRBTreeEntryPosition<K, V>(loInclusive ? m.getLowerEntry(lo) : m.getFloorEntry(lo)));
    }

    // Abstract methods defined in ascending vs descending classes
    // These relay to the appropriate absolute versions

    abstract OMVRBTreeEntry<K, V> subLowest();

    abstract OMVRBTreeEntry<K, V> subHighest();

    abstract OMVRBTreeEntry<K, V> subCeiling(K key);

    abstract OMVRBTreeEntry<K, V> subHigher(K key);

    abstract OMVRBTreeEntry<K, V> subFloor(K key);

    abstract OMVRBTreeEntry<K, V> subLower(K key);

    /** Returns ascending iterator from the perspective of this submap */
    abstract Iterator<K> keyIterator();

    /** Returns descending iterator from the perspective of this submap */
    abstract Iterator<K> descendingKeyIterator();

    // public methods

    @Override
    public boolean isEmpty() {
      return (fromStart && toEnd) ? m.isEmpty() : entrySet().isEmpty();
    }

    @Override
    public int size() {
      return (fromStart && toEnd) ? m.size() : entrySet().size();
    }

    @Override
    public final boolean containsKey(Object key) {
      return inRange(key) && m.containsKey(key);
    }

    @Override
    public final V put(K key, V value) {
      if (!inRange(key))
        throw new IllegalArgumentException("key out of range");
      return m.put(key, value);
    }

    @Override
    public final V get(Object key) {
      return !inRange(key) ? null : m.get(key);
    }

    @Override
    public final V remove(Object key) {
      return !inRange(key) ? null : m.remove(key);
    }

    public final Map.Entry<K, V> ceilingEntry(K key) {
      return exportEntry(subCeiling(key));
    }

    public final K ceilingKey(K key) {
      return keyOrNull(subCeiling(key));
    }

    public final Map.Entry<K, V> higherEntry(K key) {
      return exportEntry(subHigher(key));
    }

    public final K higherKey(K key) {
      return keyOrNull(subHigher(key));
    }

    public final Map.Entry<K, V> floorEntry(K key) {
      return exportEntry(subFloor(key));
    }

    public final K floorKey(K key) {
      return keyOrNull(subFloor(key));
    }

    public final Map.Entry<K, V> lowerEntry(K key) {
      return exportEntry(subLower(key));
    }

    public final K lowerKey(K key) {
      return keyOrNull(subLower(key));
    }

    public final K firstKey() {
      return key(subLowest());
    }

    public final K lastKey() {
      return key(subHighest());
    }

    public final Map.Entry<K, V> firstEntry() {
      return exportEntry(subLowest());
    }

    public final Map.Entry<K, V> lastEntry() {
      return exportEntry(subHighest());
    }

    public final Map.Entry<K, V> pollFirstEntry() {
      OMVRBTreeEntry<K, V> e = subLowest();
      Map.Entry<K, V> result = exportEntry(e);
      if (e != null)
        m.deleteEntry(e);
      return result;
    }

    public final Map.Entry<K, V> pollLastEntry() {
      OMVRBTreeEntry<K, V> e = subHighest();
      Map.Entry<K, V> result = exportEntry(e);
      if (e != null)
        m.deleteEntry(e);
      return result;
    }

    // Views
    transient ONavigableMap<K, V>  descendingMapView    = null;
    transient EntrySetView        entrySetView        = null;
    transient KeySet<K>            navigableKeySetView  = null;

    @SuppressWarnings("rawtypes")
    public final ONavigableSet<K> navigableKeySet() {
      KeySet<K> nksv = navigableKeySetView;
      return (nksv != null) ? nksv : (navigableKeySetView = new OMVRBTree.KeySet(this));
    }

    @Override
    public final Set<K> keySet() {
      return navigableKeySet();
    }

    public ONavigableSet<K> descendingKeySet() {
      return descendingMap().navigableKeySet();
    }

    public final SortedMap<K, V> subMap(final K fromKey, final K toKey) {
      return subMap(fromKey, true, toKey, false);
    }

    public final SortedMap<K, V> headMap(final K toKey) {
      return headMap(toKey, false);
    }

    public final SortedMap<K, V> tailMap(final K fromKey) {
      return tailMap(fromKey, true);
    }

    // View classes

    abstract class EntrySetView extends AbstractSet<Map.Entry<K, V>> {
      private transient int  size  = -1, sizeModCount;

      @Override
      public int size() {
        if (fromStart && toEnd)
          return m.size();
        if (size == -1 || sizeModCount != m.modCount) {
          sizeModCount = m.modCount;
          size = 0;
          Iterator<?> i = iterator();
          while (i.hasNext()) {
            size++;
            i.next();
          }
        }
        return size;
      }

      @Override
      public boolean isEmpty() {
        OMVRBTreeEntryPosition<K, V> n = absLowest();
        return n == null || tooHigh(n.getKey());
      }

      @Override
      public boolean contains(final Object o) {
        if (!(o instanceof OMVRBTreeEntry))
          return false;
        OMVRBTreeEntry<K, V> entry = (OMVRBTreeEntry<K, V>) o;
        K key = entry.getKey();
        if (!inRange(key))
          return false;
        V nodeValue = m.get(key);
        return nodeValue != null && valEquals(nodeValue, entry.getValue());
      }

      @Override
      public boolean remove(final Object o) {
        if (!(o instanceof OMVRBTreeEntry))
          return false;
        final OMVRBTreeEntry<K, V> entry = (OMVRBTreeEntry<K, V>) o;
        K key = entry.getKey();
        if (!inRange(key))
          return false;
        final OMVRBTreeEntry<K, V> node = m.getEntry(key);
        if (node != null && valEquals(node.getValue(), entry.getValue())) {
          m.deleteEntry(node);
          return true;
        }
        return false;
      }
    }

    /**
     * Iterators for SubMaps
     */
    abstract class SubMapIterator<T> implements Iterator<T> {
      OMVRBTreeEntryPosition<K, V>  lastReturned;
      OMVRBTreeEntryPosition<K, V>  next;
      final K                        fenceKey;
      int                            expectedModCount;

      SubMapIterator(final OMVRBTreeEntryPosition<K, V> first, final OMVRBTreeEntryPosition<K, V> fence) {
        expectedModCount = m.modCount;
        lastReturned = null;
        next = first;
        fenceKey = fence == null ? null : fence.getKey();
      }

      public final boolean hasNext() {
        return next != null && next.getKey() != fenceKey;
      }

      final OMVRBTreeEntryPosition<K, V> nextEntry() {
        final OMVRBTreeEntryPosition<K, V> e;
        if (next != null)
          e = new OMVRBTreeEntryPosition<K, V>(next);
        else
          e = null;
        if (e == null || e.entry == null || e.getKey() == fenceKey)
          throw new NoSuchElementException();
        if (m.modCount != expectedModCount)
          throw new ConcurrentModificationException();
        next.assign(OMVRBTree.next(e));
        lastReturned = e;
        return e;
      }

      final OMVRBTreeEntryPosition<K, V> prevEntry() {
        final OMVRBTreeEntryPosition<K, V> e;
        if (next != null)
          e = new OMVRBTreeEntryPosition<K, V>(next);
        else
          e = null;
        if (e == null || e.entry == null || e.getKey() == fenceKey)
          throw new NoSuchElementException();
        if (m.modCount != expectedModCount)
          throw new ConcurrentModificationException();
        next.assign(OMVRBTree.previous(e));
        lastReturned = e;
        return e;
      }

      final void removeAscending() {
        if (lastReturned == null)
          throw new IllegalStateException();
        if (m.modCount != expectedModCount)
          throw new ConcurrentModificationException();
        // deleted entries are replaced by their successors
        if (lastReturned.entry.getLeft() != null && lastReturned.entry.getRight() != null)
          next = lastReturned;
        m.deleteEntry(lastReturned.entry);
        lastReturned = null;
        expectedModCount = m.modCount;
      }

      final void removeDescending() {
        if (lastReturned == null)
          throw new IllegalStateException();
        if (m.modCount != expectedModCount)
          throw new ConcurrentModificationException();
        m.deleteEntry(lastReturned.entry);
        lastReturned = null;
        expectedModCount = m.modCount;
      }

    }

    final class SubMapEntryIterator extends SubMapIterator<Map.Entry<K, V>> {
      SubMapEntryIterator(final OMVRBTreeEntryPosition<K, V> first, final OMVRBTreeEntryPosition<K, V> fence) {
        super(first, fence);
      }

      public Map.Entry<K, V> next() {
        final Map.Entry<K, V> e = OMVRBTree.exportEntry(next);
        nextEntry();
        return e;
      }

      public void remove() {
        removeAscending();
      }
    }

    final class SubMapKeyIterator extends SubMapIterator<K> {
      SubMapKeyIterator(final OMVRBTreeEntryPosition<K, V> first, final OMVRBTreeEntryPosition<K, V> fence) {
        super(first, fence);
      }

      public K next() {
        return nextEntry().getKey();
      }

      public void remove() {
        removeAscending();
      }
    }

    final class DescendingSubMapEntryIterator extends SubMapIterator<Map.Entry<K, V>> {
      DescendingSubMapEntryIterator(final OMVRBTreeEntryPosition<K, V> last, final OMVRBTreeEntryPosition<K, V> fence) {
        super(last, fence);
      }

      public Map.Entry<K, V> next() {
        final Map.Entry<K, V> e = OMVRBTree.exportEntry(next);
        prevEntry();
        return e;
      }

      public void remove() {
        removeDescending();
      }
    }

    final class DescendingSubMapKeyIterator extends SubMapIterator<K> {
      DescendingSubMapKeyIterator(final OMVRBTreeEntryPosition<K, V> last, final OMVRBTreeEntryPosition<K, V> fence) {
        super(last, fence);
      }

      public K next() {
        return prevEntry().getKey();
      }

      public void remove() {
        removeDescending();
      }
    }
  }

  /**
   * @serial include
   */
  static final class AscendingSubMap<K, V> extends NavigableSubMap<K, V> {
    private static final long  serialVersionUID  = 912986545866124060L;

    AscendingSubMap(final OMVRBTree<K, V> m, final boolean fromStart, final K lo, final boolean loInclusive, final boolean toEnd,
        K hi, final boolean hiInclusive) {
      super(m, fromStart, lo, loInclusive, toEnd, hi, hiInclusive);
    }

    public Comparator<? super K> comparator() {
      return m.comparator();
    }

    public ONavigableMap<K, V> subMap(final K fromKey, final boolean fromInclusive, final K toKey, final boolean toInclusive) {
      if (!inRange(fromKey, fromInclusive))
        throw new IllegalArgumentException("fromKey out of range");
      if (!inRange(toKey, toInclusive))
        throw new IllegalArgumentException("toKey out of range");
      return new AscendingSubMap<K, V>(m, false, fromKey, fromInclusive, false, toKey, toInclusive);
    }

    public ONavigableMap<K, V> headMap(final K toKey, final boolean inclusive) {
      if (!inRange(toKey, inclusive))
        throw new IllegalArgumentException("toKey out of range");
      return new AscendingSubMap<K, V>(m, fromStart, lo, loInclusive, false, toKey, inclusive);
    }

    public ONavigableMap<K, V> tailMap(final K fromKey, final boolean inclusive) {
      if (!inRange(fromKey, inclusive))
        throw new IllegalArgumentException("fromKey out of range");
      return new AscendingSubMap<K, V>(m, false, fromKey, inclusive, toEnd, hi, hiInclusive);
    }

    public ONavigableMap<K, V> descendingMap() {
      ONavigableMap<K, V> mv = descendingMapView;
      return (mv != null) ? mv : (descendingMapView = new DescendingSubMap<K, V>(m, fromStart, lo, loInclusive, toEnd, hi,
          hiInclusive));
    }

    @Override
    Iterator<K> keyIterator() {
      return new SubMapKeyIterator(absLowest(), absHighFence());
    }

    @Override
    Iterator<K> descendingKeyIterator() {
      return new DescendingSubMapKeyIterator(absHighest(), absLowFence());
    }

    final class AscendingEntrySetView extends EntrySetView {
      @Override
      public Iterator<Map.Entry<K, V>> iterator() {
        return new SubMapEntryIterator(absLowest(), absHighFence());
      }
    }

    @Override
    public Set<Map.Entry<K, V>> entrySet() {
      EntrySetView es = entrySetView;
      return (es != null) ? es : new AscendingEntrySetView();
    }

    @Override
    OMVRBTreeEntry<K, V> subLowest() {
      return absLowest().entry;
    }

    @Override
    OMVRBTreeEntry<K, V> subHighest() {
      return absHighest().entry;
    }

    @Override
    OMVRBTreeEntry<K, V> subCeiling(final K key) {
      return absCeiling(key).entry;
    }

    @Override
    OMVRBTreeEntry<K, V> subHigher(final K key) {
      return absHigher(key).entry;
    }

    @Override
    OMVRBTreeEntry<K, V> subFloor(final K key) {
      return absFloor(key).entry;
    }

    @Override
    OMVRBTreeEntry<K, V> subLower(final K key) {
      return absLower(key).entry;
    }
  }

  /**
   * @serial include
   */
  static final class DescendingSubMap<K, V> extends NavigableSubMap<K, V> {
    private static final long            serialVersionUID  = 912986545866120460L;

    private final Comparator<? super K>  reverseComparator  = Collections.reverseOrder(m.comparator);

    DescendingSubMap(final OMVRBTree<K, V> m, final boolean fromStart, final K lo, final boolean loInclusive, final boolean toEnd,
        final K hi, final boolean hiInclusive) {
      super(m, fromStart, lo, loInclusive, toEnd, hi, hiInclusive);
    }

    public Comparator<? super K> comparator() {
      return reverseComparator;
    }

    public ONavigableMap<K, V> subMap(final K fromKey, final boolean fromInclusive, final K toKey, final boolean toInclusive) {
      if (!inRange(fromKey, fromInclusive))
        throw new IllegalArgumentException("fromKey out of range");
      if (!inRange(toKey, toInclusive))
        throw new IllegalArgumentException("toKey out of range");
      return new DescendingSubMap<K, V>(m, false, toKey, toInclusive, false, fromKey, fromInclusive);
    }

    public ONavigableMap<K, V> headMap(final K toKey, final boolean inclusive) {
      if (!inRange(toKey, inclusive))
        throw new IllegalArgumentException("toKey out of range");
      return new DescendingSubMap<K, V>(m, false, toKey, inclusive, toEnd, hi, hiInclusive);
    }

    public ONavigableMap<K, V> tailMap(final K fromKey, final boolean inclusive) {
      if (!inRange(fromKey, inclusive))
        throw new IllegalArgumentException("fromKey out of range");
      return new DescendingSubMap<K, V>(m, fromStart, lo, loInclusive, false, fromKey, inclusive);
    }

    public ONavigableMap<K, V> descendingMap() {
      ONavigableMap<K, V> mv = descendingMapView;
      return (mv != null) ? mv : (descendingMapView = new AscendingSubMap<K, V>(m, fromStart, lo, loInclusive, toEnd, hi,
          hiInclusive));
    }

    @Override
    Iterator<K> keyIterator() {
      return new DescendingSubMapKeyIterator(absHighest(), absLowFence());
    }

    @Override
    Iterator<K> descendingKeyIterator() {
      return new SubMapKeyIterator(absLowest(), absHighFence());
    }

    final class DescendingEntrySetView extends EntrySetView {
      @Override
      public Iterator<Map.Entry<K, V>> iterator() {
        return new DescendingSubMapEntryIterator(absHighest(), absLowFence());
      }
    }

    @Override
    public Set<Map.Entry<K, V>> entrySet() {
      EntrySetView es = entrySetView;
      return (es != null) ? es : new DescendingEntrySetView();
    }

    @Override
    OMVRBTreeEntry<K, V> subLowest() {
      return absHighest().entry;
    }

    @Override
    OMVRBTreeEntry<K, V> subHighest() {
      return absLowest().entry;
    }

    @Override
    OMVRBTreeEntry<K, V> subCeiling(final K key) {
      return absFloor(key).entry;
    }

    @Override
    OMVRBTreeEntry<K, V> subHigher(final K key) {
      return absLower(key).entry;
    }

    @Override
    OMVRBTreeEntry<K, V> subFloor(final K key) {
      return absCeiling(key).entry;
    }

    @Override
    OMVRBTreeEntry<K, V> subLower(final K key) {
      return absHigher(key).entry;
    }
  }

  // Red-black mechanics

  static final boolean  RED    = false;
  static final boolean  BLACK  = true;

  /**
   * Node in the Tree. Doubles as a means to pass key-value pairs back to user (see Map.Entry).
   */

  /**
   * Returns the first Entry in the OMVRBTree (according to the OMVRBTree's key-sort function). Returns null if the OMVRBTree is
   * empty.
   */
  protected OMVRBTreeEntry<K, V> getFirstEntry() {
    OMVRBTreeEntry<K, V> p = root;
    if (p != null) {
      if (p.getSize() > 0)
        pageIndex = 0;

      while (p.getLeft() != null)
        p = p.getLeft();
    }
    return p;
  }

  /**
   * Returns the last Entry in the OMVRBTree (according to the OMVRBTree's key-sort function). Returns null if the OMVRBTree is
   * empty.
   */
  protected final OMVRBTreeEntry<K, V> getLastEntry() {
    OMVRBTreeEntry<K, V> p = root;
    if (p != null)
      while (p.getRight() != null)
        p = p.getRight();

    if (p != null)
      pageIndex = p.getSize() - 1;

    return p;
  }

  public static <K, V> OMVRBTreeEntry<K, V> successor(final OMVRBTreeEntryPosition<K, V> t) {
    t.entry.getTree().setPageIndex(t.position);
    return successor(t.entry);
  }

  /**
   * Returns the successor of the specified Entry, or null if no such.
   */
  public static <K, V> OMVRBTreeEntry<K, V> successor(final OMVRBTreeEntry<K, V> t) {
    if (t == null)
      return null;

    OMVRBTreeEntry<K, V> p = null;

    if (t.getRight() != null) {
      p = t.getRight();
      while (p.getLeft() != null)
        p = p.getLeft();
    } else {
      p = t.getParent();
      OMVRBTreeEntry<K, V> ch = t;
      while (p != null && ch == p.getRight()) {
        ch = p;
        p = p.getParent();
      }
    }

    return p;
  }

  public static <K, V> OMVRBTreeEntry<K, V> next(final OMVRBTreeEntryPosition<K, V> t) {
    t.entry.getTree().setPageIndex(t.position);
    return next(t.entry);
  }

  /**
   * Returns the next item of the tree.
   */
  public static <K, V> OMVRBTreeEntry<K, V> next(final OMVRBTreeEntry<K, V> t) {
    if (t == null)
      return null;

    final OMVRBTreeEntry<K, V> succ;
    if (t.tree.pageIndex < t.getSize() - 1) {
      // ITERATE INSIDE THE NODE
      succ = t;
      t.tree.pageIndex++;
    } else {
      // GET THE NEXT NODE
      t.tree.pageIndex = 0;
      succ = OMVRBTree.successor(t);
    }

    return succ;
  }

  public static <K, V> OMVRBTreeEntry<K, V> predecessor(final OMVRBTreeEntryPosition<K, V> t) {
    t.entry.getTree().setPageIndex(t.position);
    return predecessor(t.entry);
  }

  /**
   * Returns the predecessor of the specified Entry, or null if no such.
   */
  public static <K, V> OMVRBTreeEntry<K, V> predecessor(final OMVRBTreeEntry<K, V> t) {
    if (t == null)
      return null;
    else if (t.getLeft() != null) {
      OMVRBTreeEntry<K, V> p = t.getLeft();
      while (p.getRight() != null)
        p = p.getRight();
      return p;
    } else {
      OMVRBTreeEntry<K, V> p = t.getParent();
      Entry<K, V> ch = t;
      while (p != null && ch == p.getLeft()) {
        ch = p;
        p = p.getParent();
      }
      return p;
    }
  }

  public static <K, V> OMVRBTreeEntry<K, V> previous(final OMVRBTreeEntryPosition<K, V> t) {
    t.entry.getTree().setPageIndex(t.position);
    return previous(t.entry);
  }

  /**
   * Returns the previous item of the tree.
   */
  public static <K, V> OMVRBTreeEntry<K, V> previous(final OMVRBTreeEntry<K, V> t) {
    if (t == null)
      return null;

    final int index = t.getTree().getPageIndex();

    final OMVRBTreeEntry<K, V> prev;
    if (index <= 0) {
      prev = predecessor(t);
      if (prev != null)
        t.tree.pageIndex = prev.size - 1;
      else
        t.tree.pageIndex = 0;
    } else {
      prev = t;
      t.tree.pageIndex = index - 1;
    }

    return prev;
  }

  /**
   * Balancing operations.
   *
   * Implementations of rebalancings during insertion and deletion are slightly different than the CLR version. Rather than using
   * dummy nilnodes, we use a set of accessors that deal properly with null. They are used to avoid messiness surrounding nullness
   * checks in the main algorithms.
   */

  private static <K, V> boolean colorOf(final OMVRBTreeEntry<K, V> p) {
    return (p == null ? BLACK : p.getColor());
  }

  private static <K, V> OMVRBTreeEntry<K, V> parentOf(final OMVRBTreeEntry<K, V> p) {
    return (p == null ? null : p.getParent());
  }

  private static <K, V> void setColor(final OMVRBTreeEntry<K, V> p, final boolean c) {
    if (p != null)
      p.setColor(c);
  }

  private static <K, V> OMVRBTreeEntry<K, V> leftOf(final OMVRBTreeEntry<K, V> p) {
    return (p == null) ? null : p.getLeft();
  }

  private static <K, V> OMVRBTreeEntry<K, V> rightOf(final OMVRBTreeEntry<K, V> p) {
    return (p == null) ? null : p.getRight();
  }

  /** From CLR */
  protected void rotateLeft(final OMVRBTreeEntry<K, V> p) {
    if (p != null) {
      OMVRBTreeEntry<K, V> r = p.getRight();
      p.setRight(r.getLeft());
      if (r.getLeft() != null)
        r.getLeft().setParent(p);
      r.setParent(p.getParent());
      if (p.getParent() == null)
        setRoot(r);
      else if (p.getParent().getLeft() == p)
        p.getParent().setLeft(r);
      else
        p.getParent().setRight(r);
      p.setParent(r);
      r.setLeft(p);
    }
  }

  protected void setRoot(final OMVRBTreeEntry<K, V> iRoot) {
    root = iRoot;
  }

  /** From CLR */
  protected void rotateRight(final OMVRBTreeEntry<K, V> p) {
    if (p != null) {
      OMVRBTreeEntry<K, V> l = p.getLeft();
      p.setLeft(l.getRight());
      if (l.getRight() != null)
        l.getRight().setParent(p);
      l.setParent(p.getParent());
      if (p.getParent() == null)
        setRoot(l);
      else if (p.getParent().getRight() == p)
        p.getParent().setRight(l);
      else
        p.getParent().setLeft(l);
      l.setRight(p);
      p.setParent(l);
    }
  }

  /** From CLR */
  /*
   * private void fixAfterInsertion(OMVRBTreeEntry<K, V> x) { x.setColor(RED);
   *
   * // if (x != null && x != root && x.getParent() != null && x.getParent().getColor() == RED) { //
   * //System.out.println("BEFORE FIX on node: " + x); // printInMemoryStructure(x);
   *
   * OMVRBTreeEntry<K, V> parent; OMVRBTreeEntry<K, V> grandParent;
   *
   * while (x != null && x != root && x.getParent() != null && x.getParent().getColor() == RED) { parent = parentOf(x); grandParent
   * = parentOf(parent);
   *
   * if (parent == leftOf(grandParent)) { // MY PARENT IS THE LEFT OF THE GRANDFATHER. GET MY UNCLE final OMVRBTreeEntry<K, V> uncle
   * = rightOf(grandParent); if (colorOf(uncle) == RED) { // SET MY PARENT AND UNCLE TO BLACK setColor(parent, BLACK);
   * setColor(uncle, BLACK); // SET GRANDPARENT'S COLOR TO RED setColor(grandParent, RED); // CONTINUE RECURSIVELY WITH MY
   * GRANDFATHER x = grandParent; } else { if (x == rightOf(parent)) { // I'M THE RIGHT x = parent; parent = parentOf(x);
   * grandParent = parentOf(parent); rotateLeft(x); } setColor(parent, BLACK); setColor(grandParent, RED); rotateRight(grandParent);
   * } } else { // MY PARENT IS THE RIGHT OF THE GRANDFATHER. GET MY UNCLE final OMVRBTreeEntry<K, V> uncle = leftOf(grandParent);
   * if (colorOf(uncle) == RED) { setColor(parent, BLACK); setColor(uncle, BLACK); setColor(grandParent, RED); x = grandParent; }
   * else { if (x == leftOf(parent)) { x = parentOf(x); parent = parentOf(x); grandParent = parentOf(parent); rotateRight(x); }
   * setColor(parent, BLACK); setColor(grandParent, RED); rotateLeft(grandParent); } } }
   *
   * // //System.out.println("AFTER FIX"); // printInMemoryStructure(x); // }
   *
   * root.setColor(BLACK); }
   */

  private OMVRBTreeEntry<K, V> grandparent(final OMVRBTreeEntry<K, V> n) {
    return parentOf(parentOf(n));
  }

  private OMVRBTreeEntry<K, V> uncle(final OMVRBTreeEntry<K, V> n) {
    if (parentOf(n) == leftOf(grandparent(n)))
      return rightOf(grandparent(n));
    else
      return leftOf(grandparent(n));
  }

  private void fixAfterInsertion(final OMVRBTreeEntry<K, V> n) {
    if (parentOf(n) == null)
      setColor(n, BLACK);
    else
      insert_case2(n);
  }

  private void insert_case2(final OMVRBTreeEntry<K, V> n) {
    if (colorOf(parentOf(n)) == BLACK)
      return; /* Tree is still valid */
    else
      insert_case3(n);
  }

  private void insert_case3(final OMVRBTreeEntry<K, V> n) {
    if (uncle(n) != null && colorOf(uncle(n)) == RED) {
      setColor(parentOf(n), BLACK);
      setColor(uncle(n), BLACK);
      setColor(grandparent(n), RED);
      fixAfterInsertion(grandparent(n));
    } else
      insert_case4(n);
  }

  private void insert_case4(OMVRBTreeEntry<K, V> n) {
    if (n == rightOf(parentOf(n)) && parentOf(n) == leftOf(grandparent(n))) {
      rotateLeft(parentOf(n));
      n = leftOf(n);
    } else if (n == leftOf(parentOf(n)) && parentOf(n) == rightOf(grandparent(n))) {
      rotateRight(parentOf(n));
      n = rightOf(n);
    }
    insert_case5(n);
  }

  private void insert_case5(final OMVRBTreeEntry<K, V> n) {
    setColor(parentOf(n), BLACK);
    setColor(grandparent(n), RED);
    if (n == leftOf(parentOf(n)) && parentOf(n) == leftOf(grandparent(n))) {
      rotateRight(grandparent(n));
    } else {
      /* Here, n == parentOf(n)->right && parentOf(n) == grandparent(n)->right */
      rotateLeft(grandparent(n));
    }
  }

  /**
   * Delete node p, and then re-balance the tree.
   *
   * @param p
   *          node to delete
   */
  void deleteEntry(OMVRBTreeEntry<K, V> p) {
    size--;

    if (listener != null)
      listener.signalTreeChanged(this);

    if (pageIndex > -1) {
      // DELETE INSIDE THE NODE
      p.remove();

      if (p.getSize() > 0)
        return;
    }

    // DELETE THE ENTIRE NODE, RE-BUILDING THE STRUCTURE
    removeNode(p);
  }

  /**
   * Remove a node from the tree.
   *
   * @param p
   *          Node to remove
   */
  protected void removeNode(OMVRBTreeEntry<K, V> p) {
    modCount++;
    // If strictly internal, copy successor's element to p and then make p
    // point to successor.
    if (p.getLeft() != null && p.getRight() != null) {
      OMVRBTreeEntry<K, V> s = next(p);
      p.copyFrom(s);
      p = s;
    } // p has 2 children

    // Start fixup at replacement node, if it exists.
    final OMVRBTreeEntry<K, V> replacement = (p.getLeft() != null ? p.getLeft() : p.getRight());

    if (replacement != null) {
      // Link replacement to parent
      replacement.setParent(p.getParent());
      if (p.getParent() == null)
        setRoot(replacement);
      else if (p == p.getParent().getLeft())
        p.getParent().setLeft(replacement);
      else
        p.getParent().setRight(replacement);

      // Null out links so they are OK to use by fixAfterDeletion.
      p.setLeft(null);
      p.setRight(null);
      p.setParent(null);

      // Fix replacement
      if (p.getColor() == BLACK)
        fixAfterDeletion(replacement);
    } else if (p.getParent() == null) { // return if we are the only node.
      clear();
    } else { // No children. Use self as phantom replacement and unlink.
      if (p.getColor() == BLACK)
        fixAfterDeletion(p);

      if (p.getParent() != null) {
        if (p == p.getParent().getLeft())
          p.getParent().setLeft(null);
        else if (p == p.getParent().getRight())
          p.getParent().setRight(null);
        p.setParent(null);
      }
    }
  }

  /** From CLR */
  private void fixAfterDeletion(OMVRBTreeEntry<K, V> x) {
    while (x != root && colorOf(x) == BLACK) {
      if (x == leftOf(parentOf(x))) {
        OMVRBTreeEntry<K, V> sib = rightOf(parentOf(x));

        if (colorOf(sib) == RED) {
          setColor(sib, BLACK);
          setColor(parentOf(x), RED);
          rotateLeft(parentOf(x));
          sib = rightOf(parentOf(x));
        }

        if (colorOf(leftOf(sib)) == BLACK && colorOf(rightOf(sib)) == BLACK) {
          setColor(sib, RED);
          x = parentOf(x);
        } else {
          if (colorOf(rightOf(sib)) == BLACK) {
            setColor(leftOf(sib), BLACK);
            setColor(sib, RED);
            rotateRight(sib);
            sib = rightOf(parentOf(x));
          }
          setColor(sib, colorOf(parentOf(x)));
          setColor(parentOf(x), BLACK);
          setColor(rightOf(sib), BLACK);
          rotateLeft(parentOf(x));
          x = root;
        }
      } else { // symmetric
        OMVRBTreeEntry<K, V> sib = leftOf(parentOf(x));

        if (colorOf(sib) == RED) {
          setColor(sib, BLACK);
          setColor(parentOf(x), RED);
          rotateRight(parentOf(x));
          sib = leftOf(parentOf(x));
        }

        if (colorOf(rightOf(sib)) == BLACK && colorOf(leftOf(sib)) == BLACK) {
          setColor(sib, RED);
          x = parentOf(x);
        } else {
          if (colorOf(leftOf(sib)) == BLACK) {
            setColor(rightOf(sib), BLACK);
            setColor(sib, RED);
            rotateLeft(sib);
            sib = leftOf(parentOf(x));
          }
          setColor(sib, colorOf(parentOf(x)));
          setColor(parentOf(x), BLACK);
          setColor(leftOf(sib), BLACK);
          rotateRight(parentOf(x));
          x = root;
        }
      }
    }

    setColor(x, BLACK);
  }

  /**
   * Save the state of the <tt>OMVRBTree</tt> instance to a stream (i.e., serialize it).
   *
   * @serialData The <i>size</i> of the OMVRBTree (the number of key-value mappings) is emitted (int), followed by the key (Object)
   *             and value (Object) for each key-value mapping represented by the OMVRBTree. The key-value mappings are emitted in
   *             key-order (as determined by the OMVRBTree's Comparator, or by the keys' natural ordering if the OMVRBTree has no
   *             Comparator).
   */
  private void writeObject(final java.io.ObjectOutputStream s) throws java.io.IOException {
    // Write out the Comparator and any hidden stuff
    s.defaultWriteObject();

    // Write out size (number of Mappings)
    s.writeInt(size);

    // Write out keys and values (alternating)
    for (Iterator<Map.Entry<K, V>> i = entrySet().iterator(); i.hasNext();) {
      Entry<K, V> e = i.next();
      s.writeObject(e.getKey());
      s.writeObject(e.getValue());
    }
  }

  /**
   * Reconstitute the <tt>OMVRBTree</tt> instance from a stream (i.e., deserialize it).
   */
  private void readObject(final java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException {
    // Read in the Comparator and any hidden stuff
    s.defaultReadObject();

    // Read in size
    int size = s.readInt();

    buildFromSorted(size, null, s, null);
  }

  /** Intended to be called only from OTreeSet.readObject */
  void readOTreeSet(int size, java.io.ObjectInputStream s, V defaultVal) throws java.io.IOException, ClassNotFoundException {
    buildFromSorted(size, null, s, defaultVal);
  }

  /** Intended to be called only from OTreeSet.addAll */
  void addAllForOTreeSet(SortedSet<? extends K> set, V defaultVal) {
    try {
      buildFromSorted(set.size(), set.iterator(), null, defaultVal);
    } catch (java.io.IOException cannotHappen) {
    } catch (ClassNotFoundException cannotHappen) {
    }
  }

  /**
   * Linear time tree building algorithm from sorted data. Can accept keys and/or values from iterator or stream. This leads to too
   * many parameters, but seems better than alternatives. The four formats that this method accepts are:
   *
   * 1) An iterator of Map.Entries. (it != null, defaultVal == null). 2) An iterator of keys. (it != null, defaultVal != null). 3) A
   * stream of alternating serialized keys and values. (it == null, defaultVal == null). 4) A stream of serialized keys. (it ==
   * null, defaultVal != null).
   *
   * It is assumed that the comparator of the OMVRBTree is already set prior to calling this method.
   *
   * @param size
   *          the number of keys (or key-value pairs) to be read from the iterator or stream
   * @param it
   *          If non-null, new entries are created from entries or keys read from this iterator.
   * @param str
   *          If non-null, new entries are created from keys and possibly values read from this stream in serialized form. Exactly
   *          one of it and str should be non-null.
   * @param defaultVal
   *          if non-null, this default value is used for each value in the map. If null, each value is read from iterator or
   *          stream, as described above.
   * @throws IOException
   *           propagated from stream reads. This cannot occur if str is null.
   * @throws ClassNotFoundException
   *           propagated from readObject. This cannot occur if str is null.
   */
  private void buildFromSorted(final int size, final Iterator<?> it, final java.io.ObjectInputStream str, final V defaultVal)
      throws java.io.IOException, ClassNotFoundException {
    this.size = size;
    root = buildFromSorted(0, 0, size - 1, computeRedLevel(size), it, str, defaultVal);
  }

  /**
   * Recursive "helper method" that does the real work of the previous method. Identically named parameters have identical
   * definitions. Additional parameters are documented below. It is assumed that the comparator and size fields of the OMVRBTree are
   * already set prior to calling this method. (It ignores both fields.)
   *
   * @param level
   *          the current level of tree. Initial call should be 0.
   * @param lo
   *          the first element index of this subtree. Initial should be 0.
   * @param hi
   *          the last element index of this subtree. Initial should be size-1.
   * @param redLevel
   *          the level at which nodes should be red. Must be equal to computeRedLevel for tree of this size.
   */
  private final OMVRBTreeEntry<K, V> buildFromSorted(final int level, final int lo, final int hi, final int redLevel,
      final Iterator<?> it, final java.io.ObjectInputStream str, final V defaultVal) throws java.io.IOException,
      ClassNotFoundException {
    /*
     * Strategy: The root is the middlemost element. To get to it, we have to first recursively construct the entire left subtree,
     * so as to grab all of its elements. We can then proceed with right subtree.
     *
     * The lo and hi arguments are the minimum and maximum indices to pull out of the iterator or stream for current subtree. They
     * are not actually indexed, we just proceed sequentially, ensuring that items are extracted in corresponding order.
     */

    if (hi < lo)
      return null;

    final int mid = (lo + hi) / 2;

    OMVRBTreeEntry<K, V> left = null;
    if (lo < mid)
      left = buildFromSorted(level + 1, lo, mid - 1, redLevel, it, str, defaultVal);

    // extract key and/or value from iterator or stream
    K key;
    V value;
    if (it != null) {
      if (defaultVal == null) {
        OMVRBTreeEntry<K, V> entry = (OMVRBTreeEntry<K, V>) it.next();
        key = entry.getKey();
        value = entry.getValue();
      } else {
        key = (K) it.next();
        value = defaultVal;
      }
    } else { // use stream
      key = (K) str.readObject();
      value = (defaultVal != null ? defaultVal : (V) str.readObject());
    }

    final OMVRBTreeEntry<K, V> middle = createEntry(key, value);

    // color nodes in non-full bottom most level red
    if (level == redLevel)
      middle.setColor(RED);

    if (left != null) {
      middle.setLeft(left);
      left.setParent(middle);
    }

    if (mid < hi) {
      OMVRBTreeEntry<K, V> right = buildFromSorted(level + 1, mid + 1, hi, redLevel, it, str, defaultVal);
      middle.setRight(right);
      right.setParent(middle);
    }

    return middle;
  }

  /**
   * Find the level down to which to assign all nodes BLACK. This is the last `full' level of the complete binary tree produced by
   * buildTree. The remaining nodes are colored RED. (This makes a `nice' set of color assignments wrt future insertions.) This
   * level number is computed by finding the number of splits needed to reach the zeroeth node. (The answer is ~lg(N), but in any
   * case must be computed by same quick O(lg(N)) loop.)
   */
  private static int computeRedLevel(final int sz) {
    int level = 0;
    for (int m = sz - 1; m >= 0; m = m / 2 - 1)
      level++;
    return level;
  }

  public int getPageSize() {
    return lastPageSize;
  }

  public int getPageIndex() {
    return pageIndex;
  }

  public void setPageIndex(final int iPageIndex) {
    pageIndex = iPageIndex;
  }

  private void init() {
  }

  public OMVRBTreeEntry<K, V> getRoot() {
    return root;
  }

  protected void printInMemoryStructure(final OMVRBTreeEntry<K, V> iRootNode) {
    printInMemoryNode("root", iRootNode, 0);
  }

  private void printInMemoryNode(final String iLabel, OMVRBTreeEntry<K, V> iNode, int iLevel) {
    if (iNode == null)
      return;

    for (int i = 0; i < iLevel; ++i)
      System.out.print(' ');

    System.out.println(iLabel + ": " + iNode.toString() + " (" + (iNode.getColor() ? "B" : "R") + ")");

    ++iLevel;

    printInMemoryNode(iLevel + ".left", iNode.getLeftInMemory(), iLevel);
    printInMemoryNode(iLevel + ".right", iNode.getRightInMemory(), iLevel);
  }

  @SuppressWarnings("rawtypes")
  public void checkTreeStructure(final OMVRBTreeEntry<K, V> iRootNode) {
    if (!runtimeCheckEnabled || iRootNode == null)
      return;

    int currPageIndex = pageIndex;

    OMVRBTreeEntry<K, V> prevNode = null;
    int i = 0;
    for (OMVRBTreeEntry<K, V> e = iRootNode.getFirstInMemory(); e != null; e = e.getNextInMemory()) {
      if (e.getSize() == 0)
        OLogManager.instance().error(this, "[OMVRBTree.checkTreeStructure] Node %s has 0 items\n", e);

      if (prevNode != null) {
        if (prevNode.getTree() == null)
          OLogManager.instance().error(this, "[OMVRBTree.checkTreeStructure] Freed record %d found in memory\n", i);

        if (((Comparable) e.getFirstKey()).compareTo((e.getLastKey())) > 0) {
          OLogManager.instance().error(this, "[OMVRBTree.checkTreeStructure] begin key is > than last key\n", e.getFirstKey(),
              e.getLastKey());
          printInMemoryStructure(iRootNode);
        }

        if (((Comparable) e.getFirstKey()).compareTo((prevNode.getLastKey())) < 0) {
          OLogManager.instance().error(this,
              "[OMVRBTree.checkTreeStructure] Node %s starts with a key minor than the last key of the previous node %s\n", e,
              prevNode);
          printInMemoryStructure(e.getParentInMemory() != null ? e.getParentInMemory() : e);
        }
      }

      if (e.getLeftInMemory() != null && e.getLeftInMemory() == e) {
        OLogManager.instance().error(this, "[OMVRBTree.checkTreeStructure] Node %s has left that points to itself!\n", e);
        printInMemoryStructure(iRootNode);
      }

      if (e.getRightInMemory() != null && e.getRightInMemory() == e) {
        OLogManager.instance().error(this, "[OMVRBTree.checkTreeStructure] Node %s has right that points to itself!\n", e);
        printInMemoryStructure(iRootNode);
      }

      if (e.getLeftInMemory() != null && e.getLeftInMemory() == e.getRightInMemory()) {
        OLogManager.instance().error(this, "[OMVRBTree.checkTreeStructure] Node %s has left and right equals!\n", e);
        printInMemoryStructure(iRootNode);
      }

      if (e.getParentInMemory() != null && e.getParentInMemory().getRightInMemory() != e
          && e.getParentInMemory().getLeftInMemory() != e) {
        OLogManager.instance().error(this,
            "[OMVRBTree.checkTreeStructure] Node %s is the children of node %s but the cross-reference is missed!\n", e,
            e.getParentInMemory());
        printInMemoryStructure(iRootNode);
      }

      prevNode = e;
      ++i;
    }

    pageIndex = currPageIndex;
  }

  public boolean isRuntimeCheckEnabled() {
    return runtimeCheckEnabled;
  }

  public void setChecks(boolean checks) {
    this.runtimeCheckEnabled = checks;
  }

  public void setRuntimeCheckEnabled(boolean runtimeCheckEnabled) {
    this.runtimeCheckEnabled = runtimeCheckEnabled;
  }

  public boolean isDebug() {
    return debug;
  }

  public void setDebug(boolean debug) {
    this.debug = debug;
  }

  protected OMVRBTreeEntry<K, V> getLastSearchNodeForSameKey(final Object key) {
    if (key != null && lastSearchKey != null)
      if (comparator != null)
        return comparator.compare((K) key, (K) lastSearchKey) == 0 ? lastSearchNode : null;
      else
        try {
          return ((Comparable<? super K>) key).compareTo((K) lastSearchKey) == 0 ? lastSearchNode : null;
        } catch (Exception e) {
          // IGNORE IT
        }

    return null;
  }

  protected OMVRBTreeEntry<K, V> setLastSearchNode(final Object iKey, final OMVRBTreeEntry<K, V> iNode) {
    lastSearchKey = iKey;
    lastSearchNode = iNode;
    lastSearchFound = iNode != null ? iNode.tree.pageItemFound : false;
    lastSearchIndex = iNode != null ? iNode.tree.pageIndex : -1;
    return iNode;
  }
}
TOP

Related Classes of com.orientechnologies.common.collection.OMVRBTree$NavigableSubMap$SubMapEntryIterator

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.