/** * Get the smallest or largest key using the given bounds. * * @param key the key * @param min whether to retrieve the smallest key * @param excluding if the given upper/lower bound is exclusive * @return the key, or null if the map is empty */ protected K getMinMax(K key, boolean min, boolean excluding) { checkOpen(); if (size() == 0) { return null; } return getMinMax(root, key, min, excluding); }
/** * Get the index of the given key in the map. * * <p>This is a O(log(size)) operation. * * <p>If the key was found, the returned value is the index in the key array. If not found, the * returned value is negative, where -1 means the provided key is smaller than any keys. See also * Arrays.binarySearch. * * @param key the key * @return the index */ public long getKeyIndex(K key) { checkOpen(); if (size() == 0) { return -1; } Page p = root; long offset = 0; while (true) { int x = p.binarySearch(key); if (p.isLeaf()) { if (x < 0) { return -offset + x; } return offset + x; } if (x < 0) { x = -x - 1; } else { x++; } for (int i = 0; i < x; i++) { offset += p.getCounts(i); } p = p.getChildPage(x); } }
/** * Get the key at the given index. * * <p>This is a O(log(size)) operation. * * @param index the index * @return the key */ @SuppressWarnings("unchecked") public K getKey(long index) { checkOpen(); if (index < 0 || index >= size()) { return null; } Page p = root; long offset = 0; while (true) { if (p.isLeaf()) { if (index >= offset + p.getKeyCount()) { return null; } return (K) p.getKey((int) (index - offset)); } int i = 0, size = p.getChildPageCount(); for (; i < size; i++) { long c = p.getCounts(i); if (index < c + offset) { break; } offset += c; } if (i == size) { return null; } p = p.getChildPage(i); } }
/** * This method is called before writing to the map. The default implementation checks whether * writing is allowed, and tries to detect concurrent modification. * * @throws UnsupportedOperationException if the map is read-only, or if another thread is * concurrently writing */ protected void beforeWrite() { if (readOnly) { checkOpen(); throw DataUtils.newUnsupportedOperationException("This map is read-only"); } checkConcurrentWrite(); writing = true; store.beforeWrite(); }
/** Remove all entries, and close the map. */ public void removeMap() { checkOpen(); if (this == store.getMetaMap()) { return; } beforeWrite(); try { root.removeAllRecursive(); store.removeMap(id); close(); } finally { afterWrite(); } }
/** * Get the first (lowest) or last (largest) key. * * @param first whether to retrieve the first key * @return the key, or null if the map is empty */ @SuppressWarnings("unchecked") protected K getFirstLast(boolean first) { checkOpen(); if (size() == 0) { return null; } Page p = root; while (true) { if (p.isLeaf()) { return (K) p.getKey(first ? 0 : p.getKeyCount() - 1); } p = p.getChildPage(first ? 0 : p.getChildPageCount() - 1); } }
public Set<K> keySet() { checkOpen(); final MVMap<K, V> map = this; final Page root = this.root; return new AbstractSet<K>() { @Override public Iterator<K> iterator() { return new Cursor<K>(map, root, null); } @Override public int size() { return MVMap.this.size(); } @Override public boolean contains(Object o) { return MVMap.this.containsKey(o); } }; }
public long getSize() { checkOpen(); return root.getTotalCount(); }
/** * Iterate over all keys. * * @param from the first key to return * @return the iterator */ public Cursor<K> keyIterator(K from) { checkOpen(); return new Cursor<K>(this, root, from); }
/** * Get a value. * * @param key the key * @return the value, or null if not found */ @SuppressWarnings("unchecked") public V get(Object key) { checkOpen(); return (V) binarySearch(root, key); }