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

org.pcollections.IntTreePMap Maven / Gradle / Ivy

/*
  * Copyright (c) 2008 Harold Cooper. All rights reserved.  
  * Licensed under the MIT License.
  * See LICENSE file in the project root for full license information.
*/

package org.pcollections;

import java.io.Serializable;
import java.util.AbstractMap;
import java.util.AbstractSet;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;




/**
 * 
 * An efficient persistent map from integer keys to non-null values.
 * 

* Iteration occurs in the integer order of the keys. *

* This implementation is thread-safe (assuming Java's AbstractMap and AbstractSet are thread-safe), * although its iterators may not be. *

* The balanced tree is based on the Glasgow Haskell Compiler's Data.Map implementation, * which in turn is based on "size balanced binary trees" as described by: *

* Stephen Adams, "Efficient sets: a balancing act", * Journal of Functional Programming 3(4):553-562, October 1993, * http://www.swiss.ai.mit.edu/~adams/BB/. *

* J. Nievergelt and E.M. Reingold, "Binary search trees of bounded balance", * SIAM journal of computing 2(1), March 1973. * * @author harold * * @param */ public final class IntTreePMap extends AbstractMap implements PMap, Serializable { private static final long serialVersionUID = 1L; //// STATIC FACTORY METHODS //// private static final IntTreePMap EMPTY = new IntTreePMap(IntTree.EMPTYNODE); /** * @param * @return an empty map */ @SuppressWarnings("unchecked") public static IntTreePMap empty() { return (IntTreePMap)EMPTY; } /** * @param * @param key * @param value * @return empty().plus(key, value) */ public static IntTreePMap singleton(final Integer key, final V value) { return IntTreePMap.empty().plus(key, value); } /** * @param * @param map * @return empty().plusAll(map) */ @SuppressWarnings("unchecked") public static IntTreePMap from(final Map map) { if(map instanceof IntTreePMap) return (IntTreePMap)map; //(actually we only know it's IntTreePMap) // but that's good enough for an immutable // (i.e. we can't mess someone else up by adding the wrong type to it) return IntTreePMap.empty().plusAll(map); } //// PRIVATE CONSTRUCTORS //// private final IntTree root; // not externally instantiable (or subclassable): private IntTreePMap(final IntTree root) { this.root = root; } private IntTreePMap withRoot(final IntTree root) { if(root==this.root) return this; return new IntTreePMap(root); } //// UNINHERITED METHODS OF IntTreePMap //// IntTreePMap withKeysChangedAbove(final int key, final int delta) { // TODO check preconditions of changeKeysAbove() // TODO make public? return withRoot( root.changeKeysAbove(key, delta) ); } IntTreePMap withKeysChangedBelow(final int key, final int delta) { // TODO check preconditions of changeKeysAbove() // TODO make public? return withRoot( root.changeKeysBelow(key, delta) ); } //// REQUIRED METHODS FROM AbstractMap //// // this cache variable is thread-safe, since assignment in Java is atomic: private Set> entrySet = null; @Override public Set> entrySet() { if(entrySet==null) entrySet = new AbstractSet>() { // REQUIRED METHODS OF AbstractSet // @Override public int size() { // same as Map return IntTreePMap.this.size(); } @Override public Iterator> iterator() { return root.iterator(); } // OVERRIDDEN METHODS OF AbstractSet // @Override public boolean contains(final Object e) { if(!(e instanceof Entry)) return false; V value = get(((Entry)e).getKey()); return value!=null && value.equals(((Entry)e).getValue()); } }; return entrySet; } //// OVERRIDDEN METHODS FROM AbstractMap //// @Override public int size() { return root.size(); } @Override public boolean containsKey(final Object key) { if(!(key instanceof Integer)) return false; return root.containsKey((Integer)key); } @Override public V get(final Object key) { if(!(key instanceof Integer)) return null; return root.get((Integer)key); } //// IMPLEMENTED METHODS OF PMap//// public IntTreePMap plus(final Integer key, final V value) { return withRoot( root.plus(key, value) ); } public IntTreePMap minus(final Object key) { if(!(key instanceof Integer)) return this; return withRoot( root.minus((Integer)key) ); } public IntTreePMap plusAll(final Map map) { IntTree root = this.root; for(Entry entry : map.entrySet()) root = root.plus(entry.getKey(), entry.getValue()); return withRoot(root); } public IntTreePMap minusAll(final Collection keys) { IntTree root = this.root; for(Object key : keys) if(key instanceof Integer) root = root.minus((Integer)key); return withRoot(root); } }