Uses path copying for persistence.
HashCollision leaves vs extended hashing
Node polymorphism vs conditionals
No sub-tree pools or root-resizing
Any errors are Rich Hickey's (so he says), except those that I introduced.
/// <summary> /// Create a <see cref="PersistentArrayMap">PersistentArrayMap</see> (if small enough, else create a <see cref="PersistentHashMap">PersistentHashMap</see>. /// </summary> /// <param name="other">The BCL map to initialize from</param> /// <returns>A new persistent map.</returns> public static IPersistentMap create(IDictionary other) { // Java version has this. Seems wasteful. //IPersistentMap ret = EMPTY; //foreach (DictionaryEntry e in other) //{ // ret = ret.assoc(e.Key, e.Value); //} //return ret; if (other.Count > HASHTABLE_THRESHOLD / 2) { return(PersistentHashMap.create(other)); } object[] array = new object[other.Count * 2]; int i = 0; foreach (DictionaryEntry e in other) { array[2 * i] = e.Key; array[2 * i + 1] = e.Value; i++; } return(new PersistentArrayMap(array)); }
protected override ITransientMap doAssoc(object key, object val) { int i = IndexOfKey(key); if (i >= 0) //already have key, { if (_array[i + 1] != val) //no change, no op { _array[i + 1] = val; } } else //didn't have key, grow { if (_len >= _array.Length) { return(((ITransientMap)PersistentHashMap.create(_array).asTransient()).assoc(key, val)); } _array[_len++] = key; _array[_len++] = val; } return(this); }
/// <summary> /// Create an <see cref="IPersistentMap">IPersistentMap</see> to hold the data when /// an operation causes the threshhold size to be exceeded. /// </summary> /// <param name="init">The array of key/value pairs.</param> /// <returns>A new <see cref="IPersistentMap">IPersistentMap</see>.</returns> private IPersistentMap createHT(object[] init) { return(PersistentHashMap.create(meta(), init)); }
public TransientHashMap(PersistentHashMap m) : this(new AtomicReference<Thread>(Thread.CurrentThread),m._root,m._count, m._hasNull, m._nullValue) { }