| /* |
| * Copyright 2014 Google Inc. |
| * |
| * 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 java.util; |
| |
| import jsinterop.annotations.JsNonNull; |
| |
| /** |
| * Skeletal implementation of a NavigableMap. |
| */ |
| abstract class AbstractNavigableMap<K, V> extends AbstractMap<K, V> implements NavigableMap<K, V> { |
| |
| class DescendingMap extends AbstractNavigableMap<K, V> { |
| @Override |
| public void clear() { |
| ascendingMap().clear(); |
| } |
| |
| @Override |
| public Comparator<? super K> comparator() { |
| return Collections.reverseOrder(ascendingMap().comparator()); |
| } |
| |
| @Override |
| public NavigableMap<K, V> descendingMap() { |
| return ascendingMap(); |
| } |
| |
| @Override |
| public NavigableMap<K, V> headMap(K toKey, boolean inclusive) { |
| return ascendingMap().tailMap(toKey, inclusive).descendingMap(); |
| } |
| |
| @Override |
| public V put(K key, V value) { |
| return ascendingMap().put(key, value); |
| } |
| |
| @Override |
| public V remove(Object key) { |
| return ascendingMap().remove(key); |
| } |
| |
| @Override |
| public int size() { |
| return ascendingMap().size(); |
| } |
| |
| @Override |
| public NavigableMap<K, V> subMap(K fromKey, boolean fromInclusive, |
| K toKey, boolean toInclusive) { |
| return ascendingMap().subMap(toKey, toInclusive, fromKey, fromInclusive).descendingMap(); |
| } |
| |
| @Override |
| public NavigableMap<K, V> tailMap(K fromKey, boolean inclusive) { |
| return ascendingMap().headMap(fromKey, inclusive).descendingMap(); |
| } |
| |
| AbstractNavigableMap<K, V> ascendingMap() { |
| return AbstractNavigableMap.this; |
| } |
| |
| @Override |
| Iterator<Entry<K, V>> descendingEntryIterator() { |
| return ascendingMap().entryIterator(); |
| } |
| |
| @Override |
| Iterator<Entry<K, V>> entryIterator() { |
| return ascendingMap().descendingEntryIterator(); |
| } |
| |
| @Override |
| Entry<K, V> getEntry(K key) { |
| return ascendingMap().getEntry(key); |
| } |
| |
| @Override |
| Entry<K, V> getFirstEntry() { |
| return ascendingMap().getLastEntry(); |
| } |
| |
| @Override |
| Entry<K, V> getLastEntry() { |
| return ascendingMap().getFirstEntry(); |
| } |
| |
| @Override |
| Entry<K, V> getCeilingEntry(K key) { |
| return ascendingMap().getFloorEntry(key); |
| } |
| |
| @Override |
| Entry<K, V> getFloorEntry(K key) { |
| return ascendingMap().getCeilingEntry(key); |
| } |
| |
| @Override |
| Entry<K, V> getHigherEntry(K key) { |
| return ascendingMap().getLowerEntry(key); |
| } |
| |
| @Override |
| Entry<K, V> getLowerEntry(K key) { |
| return ascendingMap().getHigherEntry(key); |
| } |
| |
| @Override |
| boolean removeEntry(Entry<K, V> entry) { |
| return ascendingMap().removeEntry(entry); |
| } |
| } |
| |
| class EntrySet extends AbstractSet<Entry<K, V>> { |
| @Override |
| public boolean contains(Object o) { |
| return (o instanceof Entry) && containsEntry((Entry<?, ?>) o); |
| } |
| |
| @Override |
| public Iterator<Entry<K, V>> iterator() { |
| return entryIterator(); |
| } |
| |
| @SuppressWarnings("unchecked") |
| @Override |
| public boolean remove(Object o) { |
| if (o instanceof Entry) { |
| Entry<K, V> entry = (Entry<K, V>) o; |
| return removeEntry(entry); |
| } |
| return false; |
| } |
| |
| @Override |
| public int size() { |
| return AbstractNavigableMap.this.size(); |
| } |
| } |
| |
| private static final class NavigableKeySet<K, V> extends AbstractSet<K> |
| implements NavigableSet<K> { |
| |
| private final NavigableMap<K, V> map; |
| |
| NavigableKeySet(NavigableMap<K, V> map) { |
| this.map = map; |
| } |
| |
| @Override |
| public K ceiling(K k) { |
| return map.ceilingKey(k); |
| } |
| |
| @Override |
| public void clear() { |
| map.clear(); |
| } |
| |
| @Override |
| public Comparator<? super K> comparator() { |
| return map.comparator(); |
| } |
| |
| @Override |
| public boolean contains(Object o) { |
| return map.containsKey(o); |
| } |
| |
| @Override |
| public Iterator<K> descendingIterator() { |
| return descendingSet().iterator(); |
| } |
| |
| @Override |
| public NavigableSet<K> descendingSet() { |
| return map.descendingMap().navigableKeySet(); |
| } |
| |
| @Override |
| public K first() { |
| return map.firstKey(); |
| } |
| |
| @Override |
| public K floor(K k) { |
| return map.floorKey(k); |
| } |
| |
| @Override |
| public SortedSet<K> headSet(K toElement) { |
| return headSet(toElement, false); |
| } |
| |
| @Override |
| public NavigableSet<K> headSet(K toElement, boolean inclusive) { |
| return map.headMap(toElement, inclusive).navigableKeySet(); |
| } |
| |
| @Override |
| public K higher(K k) { |
| return map.higherKey(k); |
| } |
| |
| @Override |
| public Iterator<K> iterator() { |
| final Iterator<Entry<K, V>> entryIterator = map.entrySet().iterator(); |
| return new Iterator<K>() { |
| @Override |
| public boolean hasNext() { |
| return entryIterator.hasNext(); |
| } |
| |
| @Override |
| public K next() { |
| Entry<K, V> entry = entryIterator.next(); |
| return entry.getKey(); |
| } |
| |
| @Override |
| public void remove() { |
| entryIterator.remove(); |
| } |
| }; |
| } |
| |
| @Override |
| public K last() { |
| return map.lastKey(); |
| } |
| |
| @Override |
| public K lower(K k) { |
| return map.lowerKey(k); |
| } |
| |
| @Override |
| public K pollFirst() { |
| return getEntryKeyOrNull(map.pollFirstEntry()); |
| } |
| |
| @Override |
| public K pollLast() { |
| return getEntryKeyOrNull(map.pollLastEntry()); |
| } |
| |
| @Override |
| public boolean remove(Object o) { |
| if (map.containsKey(o)) { |
| map.remove(o); |
| return true; |
| } |
| return false; |
| } |
| |
| @Override |
| public int size() { |
| return map.size(); |
| } |
| |
| @Override |
| public NavigableSet<K> subSet(K fromElement, boolean fromInclusive, |
| K toElement, boolean toInclusive) { |
| return map.subMap(fromElement, fromInclusive, toElement, toInclusive).navigableKeySet(); |
| } |
| |
| @Override |
| public SortedSet<K> subSet(K fromElement, K toElement) { |
| return subSet(fromElement, true, toElement, false); |
| } |
| |
| @Override |
| public SortedSet<K> tailSet(K fromElement) { |
| return tailSet(fromElement, true); |
| } |
| |
| @Override |
| public NavigableSet<K> tailSet(K fromElement, boolean inclusive) { |
| return map.tailMap(fromElement, inclusive).navigableKeySet(); |
| } |
| } |
| |
| private static <K, V> Entry<K, V> copyOf(Entry<K, V> entry) { |
| return entry == null ? null : new SimpleImmutableEntry<K, V>(entry); |
| } |
| |
| private static <K, V> K getKeyOrNSE(Entry<K, V> entry) { |
| if (entry == null) { |
| throw new NoSuchElementException(); |
| } |
| return entry.getKey(); |
| } |
| |
| @Override |
| public Entry<K, V> ceilingEntry(K key) { |
| return copyOf(getCeilingEntry(key)); |
| } |
| |
| @Override |
| public K ceilingKey(K key) { |
| return getEntryKeyOrNull(getCeilingEntry(key)); |
| } |
| |
| @SuppressWarnings("unchecked") |
| @Override |
| public boolean containsKey(Object k) { |
| K key = (K) k; |
| return getEntry(key) != null; |
| } |
| |
| @Override |
| public NavigableSet<K> descendingKeySet() { |
| return descendingMap().navigableKeySet(); |
| } |
| |
| @Override |
| public NavigableMap<K, V> descendingMap() { |
| return new DescendingMap(); |
| } |
| |
| @Override |
| public Set<Entry<K, V>> entrySet() { |
| return new EntrySet(); |
| } |
| |
| @Override |
| public Entry<K, V> firstEntry() { |
| return copyOf(getFirstEntry()); |
| } |
| |
| @Override |
| public K firstKey() { |
| return getKeyOrNSE(getFirstEntry()); |
| } |
| |
| @Override |
| public Entry<K, V> floorEntry(K key) { |
| return copyOf(getFloorEntry(key)); |
| } |
| |
| @Override |
| public K floorKey(K key) { |
| return getEntryKeyOrNull(getFloorEntry(key)); |
| } |
| |
| @SuppressWarnings("unchecked") |
| @Override |
| public V get(Object k) { |
| K key = (K) k; |
| return getEntryValueOrNull(getEntry(key)); |
| } |
| |
| @Override |
| public SortedMap<K, V> headMap(K toKey) { |
| return headMap(toKey, false); |
| } |
| |
| @Override |
| public Entry<K, V> higherEntry(K key) { |
| return copyOf(getHigherEntry(key)); |
| } |
| |
| @Override |
| public K higherKey(K key) { |
| return getEntryKeyOrNull(getHigherEntry(key)); |
| } |
| |
| @Override |
| @JsNonNull |
| public Set<K> keySet() { |
| return navigableKeySet(); |
| } |
| |
| @Override |
| public Entry<K, V> lastEntry() { |
| return copyOf(getLastEntry()); |
| } |
| |
| @Override |
| public K lastKey() { |
| return getKeyOrNSE(getLastEntry()); |
| } |
| |
| @Override |
| public Entry<K, V> lowerEntry(K key) { |
| return copyOf(getLowerEntry(key)); |
| } |
| |
| @Override |
| public K lowerKey(K key) { |
| return getEntryKeyOrNull(getLowerEntry(key)); |
| } |
| |
| @Override |
| public NavigableSet<K> navigableKeySet() { |
| return new NavigableKeySet<K, V>(this); |
| } |
| |
| @Override |
| public Entry<K, V> pollFirstEntry() { |
| return pollEntry(getFirstEntry()); |
| } |
| |
| @Override |
| public Entry<K, V> pollLastEntry() { |
| return pollEntry(getLastEntry()); |
| } |
| |
| @Override |
| public SortedMap<K, V> subMap(K fromKey, K toKey) { |
| return subMap(fromKey, true, toKey, false); |
| } |
| |
| @Override |
| public SortedMap<K, V> tailMap(K fromKey) { |
| return tailMap(fromKey, true); |
| } |
| |
| @SuppressWarnings("unchecked") |
| @Override |
| boolean containsEntry(Entry<?, ?> entry) { |
| K key = (K) entry.getKey(); |
| Entry<K, V> lookupEntry = getEntry(key); |
| return lookupEntry != null && Objects.equals(lookupEntry.getValue(), entry.getValue()); |
| } |
| |
| /** |
| * Returns an iterator over the entries in this map in descending order. |
| */ |
| abstract Iterator<Entry<K, V>> descendingEntryIterator(); |
| |
| /** |
| * Returns an iterator over the entries in this map in ascending order. |
| */ |
| abstract Iterator<Entry<K, V>> entryIterator(); |
| |
| /** |
| * Returns the entry corresponding to the specified key. If no such entry exists returns |
| * {@code null}. |
| */ |
| abstract Entry<K, V> getEntry(K key); |
| |
| /** |
| * Returns the first entry or {@code null} if map is empty. |
| */ |
| abstract Entry<K, V> getFirstEntry(); |
| |
| /** |
| * Returns the last entry or {@code null} if map is empty. |
| */ |
| abstract Entry<K, V> getLastEntry(); |
| |
| /** |
| * Gets the entry corresponding to the specified key or the entry for the least key greater than |
| * the specified key. If no such entry exists returns {@code null}. |
| */ |
| abstract Entry<K, V> getCeilingEntry(K key); |
| |
| /** |
| * Gets the entry corresponding to the specified key or the entry for the greatest key less than |
| * the specified key. If no such entry exists returns {@code null}. |
| */ |
| abstract Entry<K, V> getFloorEntry(K key); |
| |
| /** |
| * Gets the entry for the least key greater than the specified key. If no such entry exists |
| * returns {@code null}. |
| */ |
| abstract Entry<K, V> getHigherEntry(K key); |
| |
| /** |
| * Returns the entry for the greatest key less than the specified key. If no such entry exists |
| * returns {@code null}. |
| */ |
| abstract Entry<K, V> getLowerEntry(K key); |
| |
| /** |
| * Remove an entry from the tree, returning whether it was found. |
| */ |
| abstract boolean removeEntry(Entry<K, V> entry); |
| |
| private Entry<K, V> pollEntry(Entry<K, V> entry) { |
| if (entry != null) { |
| removeEntry(entry); |
| } |
| return copyOf(entry); |
| } |
| } |