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

io.permazen.util.ConvertedNavigableMap Maven / Gradle / Ivy

The newest version!

/*
 * Copyright (C) 2015 Archie L. Cobbs. All rights reserved.
 */

package io.permazen.util;

import com.google.common.base.Converter;
import com.google.common.base.Preconditions;

import java.util.Comparator;
import java.util.Map;
import java.util.NavigableMap;
import java.util.NavigableSet;
import java.util.NoSuchElementException;
import java.util.Set;

/**
 * Provides a transformed view of a wrapped {@link NavigableMap} using a strictly invertible {@link Converter}.
 *
 * 

* Supplied {@link Converter}s may throw {@link ClassCastException} or {@link IllegalArgumentException} * if given an objects whose runtime type does not match the expected type. * * @param key type of this map * @param value type of this map * @param key type of wrapped map * @param value type of wrapped map */ public class ConvertedNavigableMap extends AbstractNavigableMap { private final NavigableMap map; private final Converter keyConverter; private final Converter valueConverter; /** * Constructor. * * @param map wrapped map * @param keyConverter key converter * @param valueConverter value converter * @throws IllegalArgumentException if any parameter is null */ public ConvertedNavigableMap(NavigableMap map, Converter keyConverter, Converter valueConverter) { this(map, keyConverter, valueConverter, new Bounds<>()); } /** * Internal constructor. * * @param map wrapped map * @param keyConverter key converter * @param valueConverter value converter * @throws IllegalArgumentException if any parameter is null */ ConvertedNavigableMap(NavigableMap map, Converter keyConverter, Converter valueConverter, Bounds bounds) { super(bounds); Preconditions.checkArgument(map != null, "null map"); Preconditions.checkArgument(keyConverter != null, "null keyConverter"); Preconditions.checkArgument(valueConverter != null, "null valueConverter"); this.map = map; this.keyConverter = keyConverter; this.valueConverter = valueConverter; } public Converter getKeyConverter() { return this.keyConverter; } public Converter getValueConverter() { return this.valueConverter; } @Override public Comparator comparator() { return new ConvertedComparator(this.map.comparator(), this.keyConverter); } @Override @SuppressWarnings("unchecked") public V get(Object key) { WK wkey = null; if (key != null) { try { wkey = this.keyConverter.convert((K)key); } catch (IllegalArgumentException | ClassCastException e) { return null; } } final WV wvalue = this.map.get(wkey); return wvalue != null ? this.valueConverter.reverse().convert(wvalue) : null; } @Override public Set> entrySet() { return new ConvertedEntrySet<>(this.map, this.keyConverter, this.valueConverter); } @Override public NavigableSet navigableKeySet() { return new ConvertedNavigableSet<>(this.map.navigableKeySet(), this.keyConverter); } @Override public V put(K key, V value) { final WK wkey = key != null ? this.keyConverter.convert(key) : null; final WV wvalue = value != null ? this.valueConverter.convert(value) : null; final WV wprev = this.map.put(wkey, wvalue); return wprev != null ? this.valueConverter.reverse().convert(wprev) : null; } @Override @SuppressWarnings("unchecked") public V remove(Object key) { WK wkey = null; if (key != null) { try { wkey = this.keyConverter.convert((K)key); } catch (IllegalArgumentException | ClassCastException e) { return null; } } final WV wvalue = this.map.remove(wkey); return wvalue != null ? this.valueConverter.reverse().convert(wvalue) : null; } @Override public void clear() { this.map.clear(); } @Override public boolean isEmpty() { return this.map.isEmpty(); } @Override public int size() { return this.map.size(); } @Override protected Map.Entry searchBelow(K maxKey, boolean inclusive) { try { return super.searchBelow(maxKey, inclusive); } catch (IllegalArgumentException e) { // handle case where elem is out of bounds final Map.Entry lastEntry; try { lastEntry = this.lastEntry(); } catch (NoSuchElementException e2) { return null; } return this.getComparator(false).compare(maxKey, lastEntry.getKey()) > 0 ? lastEntry : null; } } @Override protected Map.Entry searchAbove(K minKey, boolean inclusive) { try { return super.searchAbove(minKey, inclusive); } catch (IllegalArgumentException e) { // handle case where elem is out of bounds final Map.Entry firstEntry; try { firstEntry = this.firstEntry(); } catch (NoSuchElementException e2) { return null; } return this.getComparator(false).compare(minKey, firstEntry.getKey()) < 0 ? firstEntry : null; } } @Override protected NavigableMap createSubMap(boolean reverse, Bounds newBounds) { final K lower = newBounds.getLowerBound(); final K upper = newBounds.getUpperBound(); final WK wlower = newBounds.getLowerBoundType() != BoundType.NONE && lower != null ? this.keyConverter.convert(lower) : null; final WK wupper = newBounds.getUpperBoundType() != BoundType.NONE && upper != null ? this.keyConverter.convert(upper) : null; NavigableMap subMap = reverse ? this.map.descendingMap() : this.map; if (newBounds.getLowerBoundType() != BoundType.NONE && newBounds.getUpperBoundType() != BoundType.NONE) { subMap = subMap.subMap( wlower, newBounds.getLowerBoundType().isInclusive(), wupper, newBounds.getUpperBoundType().isInclusive()); } else if (newBounds.getLowerBoundType() != BoundType.NONE) subMap = subMap.tailMap(wlower, newBounds.getLowerBoundType().isInclusive()); else if (newBounds.getUpperBoundType() != BoundType.NONE) subMap = subMap.headMap(wupper, newBounds.getUpperBoundType().isInclusive()); return new ConvertedNavigableMap<>(subMap, this.keyConverter, this.valueConverter, newBounds); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy