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.
   **/
  
  /* rich Mar 3, 2008 */
  
  package clojure.lang;
  
  import java.util.List;
  
  public class PersistentHashSet extends APersistentSet implements IObj, IEditableCollection {
  
  private static final long serialVersionUID = 6973890746204954938L;
  
  static public final PersistentHashSet EMPTY = new PersistentHashSet(null, PersistentHashMap.EMPTY);
  
  final IPersistentMap _meta;
  
  public static PersistentHashSet create(Object... init){
  	ITransientSet ret = (ITransientSet)EMPTY.asTransient();
  	for(int i = 0; i < init.length; i++)
  		{
  		ret = (ITransientSet)ret.conj(init[i]);
  		}
  	return (PersistentHashSet)ret.persistent();
  }
  
  public static PersistentHashSet create(List init){
  	ITransientSet ret = (ITransientSet)EMPTY.asTransient();
  	for(Object key : init)
  		{
  		ret = (ITransientSet) ret.conj(key);
  		}
  	return (PersistentHashSet)ret.persistent();
  }
  
  static public PersistentHashSet create(ISeq items){
  	ITransientSet ret = (ITransientSet)EMPTY.asTransient();
  	for(; items != null; items = items.next())
  		{
  		ret = (ITransientSet) ret.conj(items.first());
  		}
  	return (PersistentHashSet)ret.persistent();
  }
  
  public static PersistentHashSet createWithCheck(Object... init){
      ITransientSet ret = (ITransientSet)EMPTY.asTransient();
  	for(int i = 0; i < init.length; i++)
  		{
  		ret = (ITransientSet) ret.conj(init[i]);
  		if(ret.count() != i + 1)
  			throw new IllegalArgumentException("Duplicate key: " + init[i]);
  		}
  	return (PersistentHashSet) ret.persistent();
  }
  
  public static PersistentHashSet createWithCheck(List init){
      ITransientSet ret = (ITransientSet)EMPTY.asTransient();
  	int i=0;
  	for(Object key : init)
  		{
  		ret = (ITransientSet) ret.conj(key);
  		if(ret.count() != i + 1)
  			throw new IllegalArgumentException("Duplicate key: " + key);		
  		++i;
  		}
      return (PersistentHashSet) ret.persistent();
  }
  
  static public PersistentHashSet createWithCheck(ISeq items){
      ITransientSet ret = (ITransientSet)EMPTY.asTransient();
  	for(int i=0; items != null; items = items.next(), ++i)
  		{
  		ret = (ITransientSet) ret.conj(items.first());
  		if(ret.count() != i + 1)
  			throw new IllegalArgumentException("Duplicate key: " + items.first());
  		}
      return (PersistentHashSet) ret.persistent();
  }
  
  PersistentHashSet(IPersistentMap meta, IPersistentMap impl){
  	super(impl);
  	this._meta = meta;
  }
  
  public IPersistentSet disjoin(Object key) {
  	if(contains(key))
  		return new PersistentHashSet(meta(),impl.without(key));
  	return this;
  }
  
  public IPersistentSet cons(Object o){
  	if(contains(o))
  		return this;
  	return new PersistentHashSet(meta(),impl.assoc(o,o));
  }
  
  public IPersistentCollection empty(){
  	return EMPTY.withMeta(meta());	
  }
  
  public PersistentHashSet withMeta(IPersistentMap meta){
  	if(meta() == meta)
  		return this;
  	return new PersistentHashSet(meta, impl);
  }
  
  public ITransientCollection asTransient() {
  	return new TransientHashSet(((PersistentHashMap) impl).asTransient());
  }
  
  public IPersistentMap meta(){
  	return _meta;
  }
  
  static final class TransientHashSet extends ATransientSet {
  	TransientHashSet(ITransientMap impl) {
  		super(impl);
  	}
  
  	public IPersistentCollection persistent() {
  		return new PersistentHashSet(null, impl.persistent());
  	}
  }
  
  }
  