Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright 2010-2012 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.io.ObjectInputStream;
import java.io.ObjectOutputStream;
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.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.SortedMap;
import java.util.SortedSet;
import com.orientechnologies.common.comparator.ODefaultComparator;
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
* Key type
* @param
* Value type
*/
@SuppressWarnings({ "unchecked", "serial" })
public abstract class OMVRBTree extends AbstractMap implements ONavigableMap, Cloneable, java.io.Serializable {
private static final OAlwaysLessKey ALWAYS_LESS_KEY = new OAlwaysLessKey();
private static final OAlwaysGreaterKey ALWAYS_GREATER_KEY = new OAlwaysGreaterKey();
boolean pageItemFound = false;
protected int pageItemComparator = 0;
protected int pageIndex = -1;
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 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 lastSearchNode;
protected boolean lastSearchFound = false;
protected int lastSearchIndex = -1;
protected int keySize = 1;
/**
* Indicates search behavior in case of {@link 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
}
/**
* 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 super K> 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 extends K, ? extends V> 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) {
}
}
/**
* 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);
public int getNodes() {
int counter = -1;
OMVRBTreeEntry entry = getFirstEntry();
while (entry != null) {
entry = successor(entry);
counter++;
}
return counter;
}
protected abstract void setSize(int iSize);
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;
}
/**
* 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 (size() == 0)
return null;
OMVRBTreeEntry entry = null;
final long timer = OProfiler.getInstance().startChrono();
try {
// 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();
} 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 null if the map does not contain an entry for the key.
*
* In case of {@link 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 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 (size() == 0) {
pageIndex = 0;
return iGetContainer ? root : null;
}
final 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 super K>) 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;
}
OMVRBTreeEntry p = getBestEntryPoint(k);
checkTreeStructure(p);
if (p == null)
return setLastSearchNode(key, null);
OMVRBTreeEntry lastNode = p;
OMVRBTreeEntry prevNode = null;
OMVRBTreeEntry tmpNode;
int beginKey = -1;
int steps = -1;
try {
while (p != null && p.getSize() > 0) {
searchNodeCallback();
steps++;
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);
OProfiler.getInstance().updateStat("[OMVRBTree.getEntry] Steps of search", steps);
}
return setLastSearchNode(key, null);
}
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;
}
}
/**
* Basic implementation that returns the root node.
*/
protected OMVRBTreeEntry getBestEntryPoint(final K key) {
return root;
}
/**
* 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 (key instanceof OCompositeKey) {
return adjustSearchResult((OCompositeKey) key, partialSearchMode, adjacentEntry);
}
return adjacentEntry;
}
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