code: /**
   *   Copyright (c) Rich Hickey. All rights reserved.
   *   The use and distribution terms for this software are covered by the
   *   Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
   *   which can be found in the file epl-v10.html at the root of this distribution.
   *   By using this software in any fashion, you are agreeing to be bound by
   * 	 the terms of this license.
   *   You must not remove this notice, or any other, from this software.
   **/
  
  package clojure.lang;
  
  import java.util.Map;
  
  import clojure.lang.PersistentHashMap.INode;
  
  public abstract class ATransientMap extends AFn implements ITransientMap, ITransientAssociative2 {
  	abstract void ensureEditable();
  	abstract ITransientMap doAssoc(Object key, Object val);
  	abstract ITransientMap doWithout(Object key);
  	abstract Object doValAt(Object key, Object notFound);
  	abstract int doCount();
  	abstract IPersistentMap doPersistent();
  
  	public ITransientMap conj(Object o) {
  		ensureEditable();
  		if(o instanceof Map.Entry)
  			{
  			Map.Entry e = (Map.Entry) o;
  		
  			return assoc(e.getKey(), e.getValue());
  			}
  		else if(o instanceof IPersistentVector)
  			{
  			IPersistentVector v = (IPersistentVector) o;
  			if(v.count() != 2)
  				throw new IllegalArgumentException("Vector arg to map conj must be a pair");
  			return assoc(v.nth(0), v.nth(1));
  			}
  		
  		ITransientMap ret = this;
  		for(ISeq es = RT.seq(o); es != null; es = es.next())
  			{
  			Map.Entry e = (Map.Entry) es.first();
  			ret = ret.assoc(e.getKey(), e.getValue());
  			}
  		return ret;
  	}
  
  	public final Object invoke(Object arg1) {
  		return valAt(arg1);
  	}
  
  	public final Object invoke(Object arg1, Object notFound) {
  		return valAt(arg1, notFound);
  	}
  
  	public final Object valAt(Object key) {
  		return valAt(key, null);
  	}
  
  	public final ITransientMap assoc(Object key, Object val) {
  		ensureEditable();
  		return doAssoc(key, val);
  	}
  
  	public final ITransientMap without(Object key) {
  		ensureEditable();
  		return doWithout(key);
  	}
  
  	public final IPersistentMap persistent() {
  		ensureEditable();
  		return doPersistent();
  	}
  
  	public final Object valAt(Object key, Object notFound) {
  		ensureEditable();
  		return doValAt(key, notFound);
  	}
  
  	private static final Object NOT_FOUND = new Object();
  	public final boolean containsKey(Object key){
  		return valAt(key, NOT_FOUND) != NOT_FOUND;
  	}
  	public final IMapEntry entryAt(Object key){
  		Object v = valAt(key, NOT_FOUND);
  		if(v != NOT_FOUND)
  			return MapEntry.create(key, v);
  		return null;
  	}
  
  	public final int count() {
  		ensureEditable();
  		return doCount();
  	}
  }
  