All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.orientechnologies.orient.core.index.mvrbtree.OMVRBTree Maven / Gradle / Ivy

/*
 *
 *  *  Copyright 2014 Orient Technologies LTD (info(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.
 *  *
 *  * For more information: http://www.orientechnologies.com
 *
 */
package com.orientechnologies.orient.core.index.mvrbtree;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.*;

import com.orientechnologies.common.collection.OLazyIterator;
import com.orientechnologies.common.collection.ONavigableMap;
import com.orientechnologies.common.collection.ONavigableSet;
import com.orientechnologies.common.collection.OSimpleImmutableEntry;
import com.orientechnologies.common.comparator.ODefaultComparator;
import com.orientechnologies.common.log.OLogManager;
import com.orientechnologies.orient.core.index.OAlwaysGreaterKey;
import com.orientechnologies.orient.core.index.OAlwaysLessKey;
import com.orientechnologies.orient.core.index.OCompositeKey;

/**
 * Base abstract class of MVRB-Tree algorithm.
 * 
 * @author Luca Garulli (l.garulli--at--orientechnologies.com)
 * 
 * @param 
 *          Key type
 * @param 
 *          Value type
 */
@SuppressWarnings({ "unchecked", "serial" })
public abstract class OMVRBTree extends AbstractMap implements ONavigableMap, Cloneable, java.io.Serializable {
  public static final boolean              RED                 = false;
  public static final boolean              BLACK               = true;
  private static final OAlwaysLessKey      ALWAYS_LESS_KEY     = new OAlwaysLessKey();
  private static final OAlwaysGreaterKey   ALWAYS_GREATER_KEY  = new OAlwaysGreaterKey();
  /**
   * 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    comparator;
  protected boolean                        pageItemFound       = false;
  protected int                            pageItemComparator  = 0;
  protected int                            pageIndex           = -1;
  protected float                          pageLoadFactor      = 0.7f;
  protected transient OMVRBTreeEntry root                = null;
  protected transient boolean              runtimeCheckEnabled = false;
  protected transient boolean              debug               = false;
  protected Object                         lastSearchKey;
  protected OMVRBTreeEntry           lastSearchNode;
  protected boolean                        lastSearchFound     = false;
  protected int                            lastSearchIndex     = -1;
  protected int                            keySize             = 1;
  /**
   * The number of structural modifications to the tree.
   */
  transient int                            modCount            = 0;
  /**
   * 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              navigableKeySet     = null;
  private transient ONavigableMap    descendingMap       = null;

  /**
   * Indicates search behavior in case of {@link com.orientechnologies.orient.core.index.OCompositeKey} keys that have less amount
   * of internal keys are used, whether lowest or highest partially matched key should be used. Such keys is allowed to use only in
   * 
   * @link OMVRBTree#subMap(K, boolean, K, boolean)}, {@link OMVRBTree#tailMap(Object, boolean)} and
   *       {@link OMVRBTree#headMap(Object, boolean)} .
   */
  public static enum PartialSearchMode {
    /**
     * Any partially matched key will be used as search result.
     */
    NONE,
    /**
     * The biggest partially matched key will be used as search result.
     */
    HIGHEST_BOUNDARY,

    /**
     * The smallest partially matched key will be used as search result.
     */
    LOWEST_BOUNDARY
  }

  @SuppressWarnings("rawtypes")
  static final class KeySet extends AbstractSet implements ONavigableSet {
    private final ONavigableMap m;

    KeySet(ONavigableMap map) {
      m = map;
    }

    @Override
    public OLazyIterator iterator() {
      if (m instanceof OMVRBTree)
        return ((OMVRBTree) m).keyIterator();
      else
        return (((OMVRBTree.NavigableSubMap) m).keyIterator());
    }

    public OLazyIterator descendingIterator() {
      if (m instanceof OMVRBTree)
        return ((OMVRBTree) 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(final Object o) {
      return m.containsKey(o);
    }

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

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

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

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

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

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

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

    public Comparator comparator() {
      return m.comparator();
    }

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

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

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

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

    public ONavigableSet headSet(final E toElement, final boolean inclusive) {
      return new OMVRBTreeSet(m.headMap(toElement, inclusive));
    }

    public ONavigableSet tailSet(final E fromElement, final boolean inclusive) {
      return new OMVRBTreeSet(m.tailMap(fromElement, inclusive));
    }

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

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

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

    public ONavigableSet descendingSet() {
      return new OMVRBTreeSet(m.descendingMap());
    }
  }

  /**
   * @serial include
   */
  static abstract class NavigableSubMap extends AbstractMap implements ONavigableMap, java.io.Serializable {
    /**
     * The backing map.
     */
    final OMVRBTree         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;
    // Views
    transient ONavigableMap descendingMapView   = null;

    // internal utilities
    transient EntrySetView        entrySetView        = null;
    transient KeySet           navigableKeySetView = null;

    abstract class EntrySetView extends AbstractSet> {
      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 n = absLowest();
        return n == null || tooHigh(n.getKey());
      }

      @Override
      public boolean contains(final Object o) {
        if (!(o instanceof OMVRBTreeEntry))
          return false;
        final OMVRBTreeEntry entry = (OMVRBTreeEntry) o;
        final 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 entry = (OMVRBTreeEntry) o;
        final K key = entry.getKey();
        if (!inRange(key))
          return false;
        final OMVRBTreeEntry node = m.getEntry(key, PartialSearchMode.NONE);
        if (node != null && valEquals(node.getValue(), entry.getValue())) {
          m.deleteEntry(node);
          return true;
        }
        return false;
      }
    }

    /**
     * Iterators for SubMaps
     */
    abstract class SubMapIterator implements OLazyIterator {
      final K                      fenceKey;
      OMVRBTreeEntryPosition lastReturned;
      OMVRBTreeEntryPosition next;
      int                          expectedModCount;

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

      public final boolean hasNext() {
        if (next != null) {
          final K k = next.getKey();
          return k != fenceKey && !k.equals(fenceKey);
        }
        return false;
      }

      final OMVRBTreeEntryPosition nextEntry() {
        final OMVRBTreeEntryPosition e;
        if (next != null)
          e = new OMVRBTreeEntryPosition(next);
        else
          e = null;
        if (e == null || e.entry == null)
          throw new NoSuchElementException();

        final K k = e.getKey();
        if (k == fenceKey || k.equals(fenceKey))
          throw new NoSuchElementException();

        if (m.modCount != expectedModCount)
          throw new ConcurrentModificationException();
        next.assign(OMVRBTree.next(e));
        lastReturned = e;
        return e;
      }

      final OMVRBTreeEntryPosition prevEntry() {
        final OMVRBTreeEntryPosition e;
        if (next != null)
          e = new OMVRBTreeEntryPosition(next);
        else
          e = null;

        if (e == null || e.entry == null)
          throw new NoSuchElementException();

        final K k = e.getKey();
        if (k == fenceKey || k.equals(fenceKey))
          throw new NoSuchElementException();

        if (m.modCount != expectedModCount)
          throw new ConcurrentModificationException();
        next.assign(OMVRBTree.previous(e));
        lastReturned = e;
        return e;
      }

      final public T update(final T iValue) {
        if (lastReturned == null)
          throw new IllegalStateException();
        if (m.modCount != expectedModCount)
          throw new ConcurrentModificationException();
        return (T) lastReturned.entry.setValue((V) iValue);
      }

      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> {
      SubMapEntryIterator(final OMVRBTreeEntryPosition first, final OMVRBTreeEntryPosition fence) {
        super(first, fence);
      }

      public Map.Entry next() {
        final Map.Entry e = OMVRBTree.exportEntry(next);
        nextEntry();
        return e;
      }

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

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

    final class SubMapKeyIterator extends SubMapIterator {
      SubMapKeyIterator(final OMVRBTreeEntryPosition first, final OMVRBTreeEntryPosition fence) {
        super(first, fence);
      }

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

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

    final class DescendingSubMapEntryIterator extends SubMapIterator> {
      DescendingSubMapEntryIterator(final OMVRBTreeEntryPosition last, final OMVRBTreeEntryPosition fence) {
        super(last, fence);
      }

      public Map.Entry next() {
        final Map.Entry e = OMVRBTree.exportEntry(next);
        prevEntry();
        return e;
      }

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

    final class DescendingSubMapKeyIterator extends SubMapIterator {
      DescendingSubMapKeyIterator(final OMVRBTreeEntryPosition last, final OMVRBTreeEntryPosition fence) {
        super(last, fence);
      }

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

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

    NavigableSubMap(final OMVRBTree m, final boolean fromStart, K lo, final boolean loInclusive, final boolean toEnd, K hi,
        final 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;
    }

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

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

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

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

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

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

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

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

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

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

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

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

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

    // public methods

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

    abstract OMVRBTreeEntry subLowest();

    abstract OMVRBTreeEntry subHighest();

    abstract OMVRBTreeEntry subCeiling(K key);

    abstract OMVRBTreeEntry subHigher(K key);

    abstract OMVRBTreeEntry subFloor(K key);

    abstract OMVRBTreeEntry subLower(K key);

    /** Returns ascending iterator from the perspective of this submap */
    abstract OLazyIterator keyIterator();

    /** Returns descending iterator from the perspective of this submap */
    abstract OLazyIterator descendingKeyIterator();

    @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 ceilingEntry(K key) {
      return exportEntry(subCeiling(key));
    }

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

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

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

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

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

    public final Map.Entry 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 firstEntry() {
      return exportEntry(subLowest());
    }

    public final Map.Entry lastEntry() {
      return exportEntry(subHighest());
    }

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

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

    // View classes

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

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

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

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

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

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

  /**
   * @serial include
   */
  static final class AscendingSubMap extends NavigableSubMap {
    private static final long serialVersionUID = 912986545866124060L;

    final class AscendingEntrySetView extends EntrySetView {
      @Override
      public Iterator> iterator() {
        return new SubMapEntryIterator(absLowest(), absHighFence());
      }
    }

    AscendingSubMap(final OMVRBTree 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 comparator() {
      return m.comparator();
    }

    public ONavigableMap 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(m, false, fromKey, fromInclusive, false, toKey, toInclusive);
    }

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

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

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

    @Override
    OLazyIterator keyIterator() {
      return new SubMapKeyIterator(absLowest(), absHighFence());
    }

    @Override
    OLazyIterator descendingKeyIterator() {
      return new DescendingSubMapKeyIterator(absHighest(), absLowFence());
    }

    @Override
    public Set> entrySet() {
      EntrySetView es = entrySetView;
      return (es != null) ? es : new AscendingEntrySetView();
    }

    @Override
    OMVRBTreeEntry subLowest() {
      return absLowest().entry;
    }

    @Override
    OMVRBTreeEntry subHighest() {
      return absHighest().entry;
    }

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

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

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

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

  /**
   * @serial include
   */
  static final class DescendingSubMap extends NavigableSubMap {
    private static final long serialVersionUID = 912986545866120460L;

    final class DescendingEntrySetView extends EntrySetView {
      @Override
      public Iterator> iterator() {
        return new DescendingSubMapEntryIterator(absHighest(), absLowFence());
      }
    }

    private final Comparator reverseComparator = Collections.reverseOrder(m.comparator);

    DescendingSubMap(final OMVRBTree 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 comparator() {
      return reverseComparator;
    }

    public ONavigableMap 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(m, false, toKey, toInclusive, false, fromKey, fromInclusive);
    }

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

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

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

    @Override
    OLazyIterator keyIterator() {
      return new DescendingSubMapKeyIterator(absHighest(), absLowFence());
    }

    @Override
    OLazyIterator descendingKeyIterator() {
      return new SubMapKeyIterator(absLowest(), absHighFence());
    }

    @Override
    public Set> entrySet() {
      EntrySetView es = entrySetView;
      return (es != null) ? es : new DescendingEntrySetView();
    }

    @Override
    OMVRBTreeEntry subLowest() {
      return absHighest().entry;
    }

    @Override
    OMVRBTreeEntry subHighest() {
      return absLowest().entry;
    }

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

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

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

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

  }

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

    public Iterator inverseIterator() {
      return new ValueInverseIterator(getLastEntry());
    }

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

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

    @Override
    public boolean remove(final Object o) {
      for (OMVRBTreeEntry 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();
    }
  }

  public class EntrySet extends AbstractSet> {
    @Override
    public Iterator> iterator() {
      return new EntryIterator(getFirstEntry());
    }

    public Iterator> inverseIterator() {
      return new InverseEntryIterator(getLastEntry());
    }

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

    @Override
    public boolean remove(final Object o) {
      if (!(o instanceof Map.Entry))
        return false;
      final OMVRBTreeEntry entry = (OMVRBTreeEntry) o;
      final V value = entry.getValue();
      OMVRBTreeEntry p = getEntry(entry.getKey(), PartialSearchMode.NONE);
      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();
    }
  }

  final class EntryIterator extends AbstractEntryIterator> {
    EntryIterator(final OMVRBTreeEntry first) {
      super(first);
    }

    public Map.Entry next() {
      return nextEntry();
    }
  }

  final class InverseEntryIterator extends AbstractEntryIterator> {
    InverseEntryIterator(final OMVRBTreeEntry last) {
      super(last);
      // we have to set ourselves after current index to make iterator work
      if (last != null) {
        pageIndex = last.getTree().getPageIndex() + 1;
      }
    }

    public Map.Entry next() {
      return prevEntry();
    }
  }

  final class ValueIterator extends AbstractEntryIterator {
    ValueIterator(final OMVRBTreeEntry first) {
      super(first);
    }

    @Override
    public V next() {
      return nextValue();
    }
  }

  final class ValueInverseIterator extends AbstractEntryIterator {
    ValueInverseIterator(final OMVRBTreeEntry last) {
      super(last);
      // we have to set ourselves after current index to make iterator work
      if (last != null) {
        pageIndex = last.getTree().getPageIndex() + 1;
      }
    }

    @Override
    public boolean hasNext() {
      return hasPrevious();
    }

    @Override
    public V next() {
      return prevValue();
    }
  }

  final class KeyIterator extends AbstractEntryIterator {
    KeyIterator(final OMVRBTreeEntry first) {
      super(first);
    }

    @Override
    public K next() {
      return nextKey();
    }
  }

  final class DescendingKeyIterator extends AbstractEntryIterator {
    DescendingKeyIterator(final OMVRBTreeEntry first) {
      super(first);
    }

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

  /**
   * 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 mutually comparable: k1.compareTo(k2) must not
   * throw a ClassCastException for any keys k1 and k2 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 put(Object key, Object value) call will throw a ClassCastException.
   */
  public OMVRBTree() {
    this(1);
  }

  public OMVRBTree(int keySize) {
    comparator = ODefaultComparator.INSTANCE;

    init();
    this.keySize = keySize;
  }

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

  /**
   * Constructs a new tree map containing the same mappings as the given map, ordered according to the natural ordering of
   * its keys. All keys inserted into the new map must implement the {@link Comparable} interface. Furthermore, all such keys must
   * be mutually comparable: k1.compareTo(k2) must not throw a ClassCastException for any keys k1
   * and k2 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 m) {
    comparator = ODefaultComparator.INSTANCE;

    init();
    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 m) {
    init();
    comparator = m.comparator();
    try {
      buildFromSorted(m.size(), m.entrySet().iterator(), null, null);
    } catch (java.io.IOException cannotHappen) {
    } catch (ClassNotFoundException cannotHappen) {
    }
  }

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

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

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

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

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

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

  public static  OMVRBTreeEntry successor(final OMVRBTreeEntryPosition 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  OMVRBTreeEntry successor(final OMVRBTreeEntry t) {
    if (t == null)
      return null;

    OMVRBTreeEntry p = null;

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

    return p;
  }

  public static  OMVRBTreeEntry next(final OMVRBTreeEntryPosition t) {
    t.entry.getTree().setPageIndex(t.position);
    return next(t.entry);
  }

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

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

    return succ;
  }

  public static  OMVRBTreeEntry predecessor(final OMVRBTreeEntryPosition 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  OMVRBTreeEntry predecessor(final OMVRBTreeEntry t) {
    if (t == null)
      return null;
    else if (t.getLeft() != null) {
      OMVRBTreeEntry p = t.getLeft();
      while (p.getRight() != null)
        p = p.getRight();
      return p;
    } else {
      OMVRBTreeEntry p = t.getParent();
      Entry ch = t;
      while (p != null && ch == p.getLeft()) {
        ch = p;
        p = p.getParent();
      }
      return p;
    }
  }

  // ONavigableMap API methods

  public static  OMVRBTreeEntry previous(final OMVRBTreeEntryPosition t) {
    t.entry.getTree().setPageIndex(t.position);
    return previous(t.entry);
  }

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

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

    final OMVRBTreeEntry prev;
    if (index <= 0) {
      prev = predecessor(t);
      if (prev != null)
        t.tree.pageIndex = prev.getSize() - 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  boolean colorOf(final OMVRBTreeEntry p) {
    return (p == null ? BLACK : p.getColor());
  }

  private static  OMVRBTreeEntry parentOf(final OMVRBTreeEntry p) {
    return (p == null ? null : p.getParent());
  }

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

  private static  OMVRBTreeEntry leftOf(final OMVRBTreeEntry p) {
    return (p == null) ? null : p.getLeft();
  }

  private static  OMVRBTreeEntry rightOf(final OMVRBTreeEntry p) {
    return (p == null) ? null : p.getRight();
  }

  /**
   * 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 getNodes() {
    int counter = -1;

    OMVRBTreeEntry entry = getFirstEntry();
    while (entry != null) {
      entry = successor(entry);
      counter++;
    }

    return counter;
  }

  public abstract int getDefaultPageSize();

  /**
   * Returns true if this map contains a mapping for the specified key.
   * 
   * @param key
   *          key whose presence in this map is to be tested
   * @return true 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, PartialSearchMode.NONE) != null;
  }

  /**
   * Returns true if this map maps one or more keys to the specified value. More formally, returns true if and
   * only if this map contains at least one mapping to a value v such that
   * (value==null ? v==null : value.equals(v)). 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 true if a mapping to value exists; false otherwise
   * @since 1.2
   */
  @Override
  public boolean containsValue(final Object value) {
    for (OMVRBTreeEntry e = getFirstEntry(); e != null; e = next(e))
      if (valEquals(value, e.getValue()))
        return true;
    return false;
  }

  // Views

  @Override
  public int size() {
    return getTreeSize();
  }

  /**
   * Returns the value to which the specified key is mapped, or {@code null} if this map contains no mapping for the key.
   * 
   * 

* 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.) * *

* A return value of {@code null} does not necessarily 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 (getTreeSize() == 0) return null; OMVRBTreeEntry entry = null; // TRY TO GET LATEST SEARCH final OMVRBTreeEntry 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, PartialSearchMode.NONE); return entry == null ? null : entry.getValue(); } public Comparator 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 map) { int mapSize = map.size(); if (getTreeSize() == 0 && mapSize != 0 && map instanceof SortedMap) { Comparator c = ((SortedMap) 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 null if the map does not contain an entry for the key. * * In case of {@link com.orientechnologies.orient.core.index.OCompositeKey} keys you can specify which key can be used: lowest, * highest, any. * * @param key * Key to search. * @param partialSearchMode * Which key can be used in case of {@link com.orientechnologies.orient.core.index.OCompositeKey} key is passed in. * * @return this map's entry for the given key, or null 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 */ public final OMVRBTreeEntry getEntry(final Object key, final PartialSearchMode partialSearchMode) { return getEntry(key, false, partialSearchMode); } final OMVRBTreeEntry getEntry(final Object key, final boolean iGetContainer, final PartialSearchMode partialSearchMode) { if (key == null) return setLastSearchNode(null, null); pageItemFound = false; if (getTreeSize() == 0) { pageIndex = 0; return iGetContainer ? root : null; } final K k; k = enhanceCompositeKey(key, partialSearchMode); OMVRBTreeEntry p = getBestEntryPoint(k); checkTreeStructure(p); if (p == null) return setLastSearchNode(key, null); OMVRBTreeEntry lastNode = p; OMVRBTreeEntry prevNode = null; OMVRBTreeEntry tmpNode; int beginKey = -1; try { while (p != null && p.getSize() > 0) { searchNodeCallback(); lastNode = p; beginKey = compare(k, p.getFirstKey()); 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); } pageItemComparator = compare(k, p.getLastKey()); if (beginKey < 0) { if (pageItemComparator < 0) { tmpNode = predecessor(p); if (tmpNode != null && tmpNode != prevNode) { // MINOR THAN THE CURRENT: GET THE LEFT NODE prevNode = p; p = tmpNode; continue; } } } else if (beginKey > 0) { if (pageItemComparator > 0) { tmpNode = successor(p); if (tmpNode != null && tmpNode != prevNode) { // MAJOR THAN THE CURRENT: GET THE RIGHT NODE prevNode = p; p = tmpNode; continue; } } } // SEARCH INSIDE THE NODE final V value = lastNode.search(k); // PROBABLY PARTIAL KEY IS FOUND USE SEARCH MODE TO FIND PREFERRED ONE if (key instanceof OCompositeKey) { final OCompositeKey compositeKey = (OCompositeKey) key; if (value != null && compositeKey.getKeys().size() == keySize) { return setLastSearchNode(key, lastNode); } if (partialSearchMode.equals(PartialSearchMode.NONE)) { if (value != null || iGetContainer) return lastNode; else return null; } if (partialSearchMode.equals(PartialSearchMode.HIGHEST_BOUNDARY)) { // FOUNDED ENTRY EITHER GREATER THAN EXISTING ITEM OR ITEM DOES NOT EXIST return adjustHighestPartialSearchResult(iGetContainer, lastNode, compositeKey); } if (partialSearchMode.equals(PartialSearchMode.LOWEST_BOUNDARY)) { return adjustLowestPartialSearchResult(iGetContainer, lastNode, compositeKey); } } if (value != null) { 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); } return setLastSearchNode(key, null); } public K enhanceCompositeKey(Object key, PartialSearchMode partialSearchMode) { K k; if (keySize == 1) k = (K) key; else if (((OCompositeKey) key).getKeys().size() == keySize) k = (K) key; else if (partialSearchMode.equals(PartialSearchMode.NONE)) k = (K) key; else { final OCompositeKey fullKey = new OCompositeKey((Comparable) key); int itemsToAdd = keySize - fullKey.getKeys().size(); final Comparable keyItem; if (partialSearchMode.equals(PartialSearchMode.HIGHEST_BOUNDARY)) keyItem = ALWAYS_GREATER_KEY; else keyItem = ALWAYS_LESS_KEY; for (int i = 0; i < itemsToAdd; i++) fullKey.addKey(keyItem); k = (K) fullKey; } return k; } /** * 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 * null. * * @param key * Key to search. * @param partialSearchMode * In case of {@link OCompositeKey} key is passed in this parameter will be used to find preferred one. */ public OMVRBTreeEntry getCeilingEntry(final K key, final PartialSearchMode partialSearchMode) { OMVRBTreeEntry p = getEntry(key, true, partialSearchMode); if (p == null) return null; if (pageItemFound) return p; // NOT MATCHED, POSITION IS ALREADY TO THE NEXT ONE else if (pageIndex < p.getSize()) { if (key instanceof OCompositeKey) return adjustSearchResult((OCompositeKey) key, partialSearchMode, p); else return p; } return null; } /** * 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 null. * * @param key * Key to search. * @param partialSearchMode * In case of {@link OCompositeKey} composite key is passed in this parameter will be used to find preferred one. */ public OMVRBTreeEntry getFloorEntry(final K key, final PartialSearchMode partialSearchMode) { OMVRBTreeEntry p = getEntry(key, true, partialSearchMode); if (p == null) return null; if (pageItemFound) return p; final OMVRBTreeEntry adjacentEntry = previous(p); if (adjacentEntry == null) return null; if (key instanceof OCompositeKey) { return adjustSearchResult((OCompositeKey) key, partialSearchMode, adjacentEntry); } return adjacentEntry; } /** * 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 null. */ public OMVRBTreeEntry getHigherEntry(final K key) { final OMVRBTreeEntry p = getEntry(key, true, PartialSearchMode.HIGHEST_BOUNDARY); 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 null. */ public OMVRBTreeEntry getLowerEntry(final K key) { final OMVRBTreeEntry p = getEntry(key, true, PartialSearchMode.LOWEST_BOUNDARY); 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 key, or null if there was no mapping for key. (A * null return can also indicate that the map previously associated null with 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 V put(final K key, final V value) { OMVRBTreeEntry parentNode = null; try { if (root == null) { root = createEntry(key, value); root.setColor(BLACK); setSize(1); modCount++; return null; } // TRY TO GET LATEST SEARCH parentNode = getLastSearchNodeForSameKey(key); if (parentNode != null) { if (lastSearchFound) { // EXACT MATCH: UPDATE THE VALUE pageIndex = lastSearchIndex; modCount++; return parentNode.setValue(value); } } // SEARCH THE ITEM parentNode = getEntry(key, true, PartialSearchMode.NONE); if (pageItemFound) { modCount++; // 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 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); OMVRBTreeEntry node = parentNode.getRight(); OMVRBTreeEntry prevNode = parentNode; int cmp = 0; final K fk = newNode.getFirstKey(); if (comparator != null) while (node != null) { cmp = comparator.compare(fk, node.getFirstKey()); if (cmp < 0) { prevNode = node; node = node.getLeft(); } else if (cmp > 0) { prevNode = node; node = node.getRight(); } else { throw new IllegalStateException("Duplicated keys were found in OMVRBTree."); } } else while (node != null) { cmp = compare(fk, node.getFirstKey()); if (cmp < 0) { prevNode = node; node = node.getLeft(); } else if (cmp > 0) { prevNode = node; node = node.getRight(); } else { throw new IllegalStateException("Duplicated keys were found in OMVRBTree."); } } if (prevNode == parentNode) parentNode.setRight(newNode); else if (cmp < 0) prevNode.setLeft(newNode); else if (cmp > 0) prevNode.setRight(newNode); else throw new IllegalStateException("Duplicated keys were found in OMVRBTree."); fixAfterInsertion(newNode); } modCount++; setSizeDelta(+1); } 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 key, or null if there was no mapping for key. (A * null return can also indicate that the map previously associated null with 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 V remove(final Object key) { OMVRBTreeEntry p = getEntry(key, PartialSearchMode.NONE); setLastSearchNode(null, null); if (p == null) return null; V oldValue = p.getValue(); deleteEntry(p); return oldValue; } // View class support /** * Removes all of the mappings from this map. The map will be empty after this call returns. */ @Override public void clear() { modCount++; setSize(0); setLastSearchNode(null, null); setRoot(null); } /** * Returns a shallow copy of this OMVRBTree instance. (The keys and values themselves are not cloned.) * * @return a shallow copy of this map */ @Override public Object clone() { OMVRBTree clone = null; try { clone = (OMVRBTree) super.clone(); } catch (CloneNotSupportedException e) { throw new InternalError(); } // Put clone into "virgin" state (except for comparator) clone.pageIndex = pageIndex; clone.pageItemFound = pageItemFound; clone.pageLoadFactor = pageLoadFactor; clone.root = null; clone.setSize(0); clone.modCount = 0; clone.entrySet = null; clone.navigableKeySet = null; clone.descendingMap = null; // Initialize clone with our mappings try { clone.buildFromSorted(getTreeSize(), entrySet().iterator(), null, null); } catch (java.io.IOException cannotHappen) { } catch (ClassNotFoundException cannotHappen) { } return clone; } /* * 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. */ /** * @since 1.6 */ public Map.Entry firstEntry() { return exportEntry(getFirstEntry()); } /** * @since 1.6 */ public Map.Entry lastEntry() { return exportEntry(getLastEntry()); } /** * @since 1.6 */ public Entry pollFirstEntry() { OMVRBTreeEntry p = getFirstEntry(); Map.Entry result = exportEntry(p); if (p != null) deleteEntry(p); return result; } /** * @since 1.6 */ public Entry pollLastEntry() { OMVRBTreeEntry p = getLastEntry(); Map.Entry 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 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 floorEntry(final K key) { return exportEntry(getFloorEntry(key, PartialSearchMode.NONE)); } /** * @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, PartialSearchMode.NONE)); } /** * @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 ceilingEntry(final K key) { return exportEntry(getCeilingEntry(key, PartialSearchMode.NONE)); } // Little utilities /** * @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, PartialSearchMode.NONE)); } /** * @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 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)); } /** * 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 remove operation), the results of the iteration are * undefined. The set supports element removal, which removes the corresponding mapping from the map, via the * Iterator.remove, Set.remove, removeAll, retainAll, and clear operations. It does * not support the add or addAll operations. */ @Override public Set keySet() { return navigableKeySet(); } /** * @since 1.6 */ public ONavigableSet navigableKeySet() { final KeySet nks = navigableKeySet; return (nks != null) ? nks : (navigableKeySet = (KeySet) new KeySet((ONavigableMap) this)); } /** * @since 1.6 */ public ONavigableSet 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 remove operation), the results of the iteration are undefined. The collection supports element removal, * which removes the corresponding mapping from the map, via the Iterator.remove, Collection.remove, * removeAll, retainAll and clear operations. It does not support the add or addAll * operations. */ @Override public Collection values() { final Collection vs = new Values(); return (vs != null) ? vs : null; } // SubMaps /** * 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 remove operation, or through the * setValue 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 Iterator.remove, * Set.remove, removeAll, retainAll and clear operations. It does not support the add * or addAll operations. */ @Override public Set> entrySet() { final EntrySet es = entrySet; return (es != null) ? es : (entrySet = new EntrySet()); } /** * @since 1.6 */ public ONavigableMap descendingMap() { final ONavigableMap km = descendingMap; return (km != null) ? km : (descendingMap = new DescendingSubMap(this, true, null, true, true, null, true)); } /** * @throws ClassCastException * {@inheritDoc} * @throws NullPointerException * if fromKey or toKey is null and this map uses natural ordering, or its comparator does not permit * null keys * @throws IllegalArgumentException * {@inheritDoc} * @since 1.6 */ public ONavigableMap subMap(final K fromKey, final boolean fromInclusive, final K toKey, final boolean toInclusive) { return new AscendingSubMap(this, false, fromKey, fromInclusive, false, toKey, toInclusive); } // Red-black mechanics /** * @throws ClassCastException * {@inheritDoc} * @throws NullPointerException * if toKey is null and this map uses natural ordering, or its comparator does not permit null keys * @throws IllegalArgumentException * {@inheritDoc} * @since 1.6 */ public ONavigableMap headMap(final K toKey, final boolean inclusive) { return new AscendingSubMap(this, true, null, true, false, toKey, inclusive); } /** * @throws ClassCastException * {@inheritDoc} * @throws NullPointerException * if fromKey is null and this map uses natural ordering, or its comparator does not permit null keys * @throws IllegalArgumentException * {@inheritDoc} * @since 1.6 */ public ONavigableMap tailMap(final K fromKey, final boolean inclusive) { return new AscendingSubMap(this, false, fromKey, inclusive, true, null, true); } /** * Node in the Tree. Doubles as a means to pass key-value pairs back to user (see Map.Entry). */ /** * @throws ClassCastException * {@inheritDoc} * @throws NullPointerException * if fromKey or toKey is null and this map uses natural ordering, or its comparator does not permit * null keys * @throws IllegalArgumentException * {@inheritDoc} */ public SortedMap subMap(final K fromKey, final K toKey) { return subMap(fromKey, true, toKey, false); } /** * @throws ClassCastException * {@inheritDoc} * @throws NullPointerException * if toKey is null and this map uses natural ordering, or its comparator does not permit null keys * @throws IllegalArgumentException * {@inheritDoc} */ public SortedMap headMap(final K toKey) { return headMap(toKey, false); } /** * @throws ClassCastException * {@inheritDoc} * @throws NullPointerException * if fromKey is null and this map uses natural ordering, or its comparator does not permit null keys * @throws IllegalArgumentException * {@inheritDoc} */ public SortedMap tailMap(final K fromKey) { return tailMap(fromKey, true); } OLazyIterator keyIterator() { return new KeyIterator(getFirstEntry()); } OLazyIterator descendingKeyIterator() { return new DescendingKeyIterator(getLastEntry()); } /** * Compares two keys using the correct comparison method for this OMVRBTree. */ final int compare(final Object k1, final Object k2) { return comparator == null ? ((Comparable) k1).compareTo((K) k2) : comparator.compare((K) k1, (K) k2); } /** * Returns the first Entry in the OMVRBTree (according to the OMVRBTree's key-sort function). Returns null if the OMVRBTree is * empty. */ public OMVRBTreeEntry getFirstEntry() { OMVRBTreeEntry 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. */ public OMVRBTreeEntry getLastEntry() { OMVRBTreeEntry p = root; if (p != null) while (p.getRight() != null) p = p.getRight(); if (p != null) pageIndex = p.getSize() - 1; return p; } /** * Delete node p, and then re-balance the tree. * * @param p * node to delete * @return */ OMVRBTreeEntry deleteEntry(OMVRBTreeEntry p) { setSizeDelta(-1); modCount++; if (pageIndex > -1) { // DELETE INSIDE THE NODE p.remove(); if (p.getSize() > 0) return p; } final OMVRBTreeEntry next = successor(p); // DELETE THE ENTIRE NODE, RE-BUILDING THE STRUCTURE removeNode(p); // RETURN NEXT NODE return next; } /** Intended to be called only from OTreeSet.readObject */ void readOTreeSet(int iSize, ObjectInputStream s, V defaultVal) throws java.io.IOException, ClassNotFoundException { buildFromSorted(iSize, null, s, defaultVal); } /** Intended to be called only from OTreeSet.addAll */ void addAllForOTreeSet(SortedSet set, V defaultVal) { try { buildFromSorted(set.size(), set.iterator(), null, defaultVal); } catch (java.io.IOException cannotHappen) { } catch (ClassNotFoundException cannotHappen) { } } public int getPageIndex() { return pageIndex; } public void setPageIndex(final int iPageIndex) { pageIndex = iPageIndex; } public OMVRBTreeEntry getRoot() { return root; } protected void setRoot(final OMVRBTreeEntry iRoot) { root = iRoot; } public void checkTreeStructure(final OMVRBTreeEntry iRootNode) { if (!runtimeCheckEnabled || iRootNode == null) return; int currPageIndex = pageIndex; OMVRBTreeEntry prevNode = null; int i = 0; for (OMVRBTreeEntry 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 (compare(e.getFirstKey(), e.getLastKey()) > 0) { OLogManager.instance().error(this, "[OMVRBTree.checkTreeStructure] begin key is > than last key\n", e.getFirstKey(), e.getLastKey()); } if (compare(e.getFirstKey(), 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); } } if (e.getLeftInMemory() != null && e.getLeftInMemory() == e) { OLogManager.instance().error(this, "[OMVRBTree.checkTreeStructure] Node %s has left that points to itself!\n", e); } if (e.getRightInMemory() != null && e.getRightInMemory() == e) { OLogManager.instance().error(this, "[OMVRBTree.checkTreeStructure] Node %s has right that points to itself!\n", e); } if (e.getLeftInMemory() != null && e.getLeftInMemory() == e.getRightInMemory()) { OLogManager.instance().error(this, "[OMVRBTree.checkTreeStructure] Node %s has left and right equals!\n", e); } 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()); } prevNode = e; ++i; } pageIndex = currPageIndex; } public boolean isRuntimeCheckEnabled() { return runtimeCheckEnabled; } public void setRuntimeCheckEnabled(boolean runtimeCheckEnabled) { this.runtimeCheckEnabled = runtimeCheckEnabled; } public void setChecks(boolean checks) { this.runtimeCheckEnabled = checks; } public boolean isDebug() { return debug; } public void setDebug(boolean debug) { this.debug = debug; } /** * Create a new entry with the first key/value to handle. */ protected abstract OMVRBTreeEntry createEntry(final K key, final V value); /** * Create a new node with the same parent of the node is splitting. */ protected abstract OMVRBTreeEntry createEntry(final OMVRBTreeEntry parent); protected abstract int getTreeSize(); protected abstract void setSize(int iSize); /** * Basic implementation that returns the root node. */ protected OMVRBTreeEntry getBestEntryPoint(final K key) { return root; } /** From CLR */ protected void rotateLeft(final OMVRBTreeEntry p) { if (p != null) { OMVRBTreeEntry 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); } } /** From CLR */ protected void rotateRight(final OMVRBTreeEntry p) { if (p != null) { OMVRBTreeEntry 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); } } /** * Remove a node from the tree. * * @param p * Node to remove * * @return Node that was removed. Passed and removed nodes may be different in case node to remove contains two children. In this * case node successor will be found and removed but it's content will be copied to the node that was passed in method. */ protected OMVRBTreeEntry removeNode(OMVRBTreeEntry 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 s = next(p); p.copyFrom(s); p = s; } // p has 2 children // Start fixup at replacement node, if it exists. final OMVRBTreeEntry 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 && size() == 0) { // return if we are the only node. Check the size to be sure the map is empty 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); } } return p; } protected OMVRBTreeEntry getLastSearchNodeForSameKey(final Object key) { if (key != null && lastSearchKey != null) { if (key instanceof OCompositeKey) return key.equals(lastSearchKey) ? lastSearchNode : null; if (comparator != null) return comparator.compare((K) key, (K) lastSearchKey) == 0 ? lastSearchNode : null; else try { return ((Comparable) key).compareTo((K) lastSearchKey) == 0 ? lastSearchNode : null; } catch (Exception e) { // IGNORE IT } } return null; } protected OMVRBTreeEntry setLastSearchNode(final Object iKey, final OMVRBTreeEntry iNode) { lastSearchKey = iKey; lastSearchNode = iNode; lastSearchFound = iNode != null ? iNode.tree.pageItemFound : false; lastSearchIndex = iNode != null ? iNode.tree.pageIndex : -1; return iNode; } protected void searchNodeCallback() { } protected void setSizeDelta(final int iDelta) { setSize(size() + iDelta); } private OMVRBTreeEntry adjustHighestPartialSearchResult(final boolean iGetContainer, final OMVRBTreeEntry lastNode, final OCompositeKey compositeKey) { final int oldPageIndex = pageIndex; final OMVRBTreeEntry prevNd = previous(lastNode); if (prevNd == null) { pageIndex = oldPageIndex; pageItemFound = false; if (iGetContainer) return lastNode; return null; } pageItemComparator = compare(prevNd.getKey(), compositeKey); if (pageItemComparator == 0) { pageItemFound = true; return prevNd; } else if (pageItemComparator > 1) { pageItemFound = false; if (iGetContainer) return prevNd; return null; } else { pageIndex = oldPageIndex; pageItemFound = false; if (iGetContainer) return lastNode; return null; } } private OMVRBTreeEntry adjustLowestPartialSearchResult(final boolean iGetContainer, OMVRBTreeEntry lastNode, final OCompositeKey compositeKey) { // RARE CASE WHEN NODE ITSELF DOES CONTAIN KEY, BUT ALL KEYS LESS THAN GIVEN ONE final int oldPageIndex = pageIndex; final OMVRBTreeEntry oldNode = lastNode; if (pageIndex >= lastNode.getSize()) { lastNode = next(lastNode); if (lastNode == null) { lastNode = oldNode; pageIndex = oldPageIndex; pageItemFound = false; if (iGetContainer) return lastNode; return null; } } pageItemComparator = compare(lastNode.getKey(), compositeKey); if (pageItemComparator == 0) { pageItemFound = true; return lastNode; } else { pageItemFound = false; if (iGetContainer) return lastNode; return null; } } private OMVRBTreeEntry adjustSearchResult(final OCompositeKey key, final PartialSearchMode partialSearchMode, final OMVRBTreeEntry foundEntry) { if (partialSearchMode.equals(PartialSearchMode.NONE)) return foundEntry; final OCompositeKey keyToSearch = key; final OCompositeKey foundKey = (OCompositeKey) foundEntry.getKey(); if (keyToSearch.getKeys().size() < keySize) { final OCompositeKey borderKey = new OCompositeKey(); final OCompositeKey keyToCompare = new OCompositeKey(); final List keyItems = foundKey.getKeys(); for (int i = 0; i < keySize - 1; i++) { final Object keyItem = keyItems.get(i); borderKey.addKey(keyItem); if (i < keyToSearch.getKeys().size()) keyToCompare.addKey(keyItem); } if (partialSearchMode.equals(PartialSearchMode.HIGHEST_BOUNDARY)) borderKey.addKey(ALWAYS_GREATER_KEY); else borderKey.addKey(ALWAYS_LESS_KEY); final OMVRBTreeEntry adjustedNode = getEntry(borderKey, true, PartialSearchMode.NONE); if (partialSearchMode.equals(PartialSearchMode.HIGHEST_BOUNDARY)) return adjustHighestPartialSearchResult(false, adjustedNode, keyToCompare); else return adjustLowestPartialSearchResult(false, adjustedNode, keyToCompare); } return foundEntry; } private OMVRBTreeEntry grandparent(final OMVRBTreeEntry n) { return parentOf(parentOf(n)); } private OMVRBTreeEntry uncle(final OMVRBTreeEntry n) { if (parentOf(n) == leftOf(grandparent(n))) return rightOf(grandparent(n)); else return leftOf(grandparent(n)); } private void fixAfterInsertion(final OMVRBTreeEntry n) { if (parentOf(n) == null) setColor(n, BLACK); else insert_case2(n); } private void insert_case2(final OMVRBTreeEntry n) { if (colorOf(parentOf(n)) == BLACK) return; /* Tree is still valid */ else insert_case3(n); } private void insert_case3(final OMVRBTreeEntry 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 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 n) { setColor(parentOf(n), BLACK); setColor(grandparent(n), RED); if (n == leftOf(parentOf(n)) && parentOf(n) == leftOf(grandparent(n))) { rotateRight(grandparent(n)); } else { rotateLeft(grandparent(n)); } } /** From CLR */ private void fixAfterDeletion(OMVRBTreeEntry x) { while (x != root && colorOf(x) == BLACK) { if (x == leftOf(parentOf(x))) { OMVRBTreeEntry 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 sib = leftOf(parentOf(x)); if (colorOf(sib) == RED) { setColor(sib, BLACK); setColor(parentOf(x), RED); rotateRight(parentOf(x)); sib = leftOf(parentOf(x)); } if (x != null && 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 OMVRBTree instance to a stream (i.e., serialize it). * * @serialData The size 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 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> i = entrySet().iterator(); i.hasNext();) { Entry e = i.next(); s.writeObject(e.getKey()); s.writeObject(e.getValue()); } } /** * Reconstitute the OMVRBTree instance from a stream (i.e., deserialize it). */ private void readObject(final java.io.ObjectInputStream s) throws IOException, ClassNotFoundException { // Read in the Comparator and any hidden stuff s.defaultReadObject(); // Read in size setSize(s.readInt()); buildFromSorted(size(), null, s, null); } /** * 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 { setSize(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 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 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 entry = (OMVRBTreeEntry) 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 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 right = buildFromSorted(level + 1, mid + 1, hi, redLevel, it, str, defaultVal); middle.setRight(right); right.setParent(middle); } return middle; } private void init() { } }