Fork me on GitHub
#clojure-dev
<
2023-03-08
>
dmiller01:03:40

I'm off reading code again. Apologies in advance. Looking at PersistentHashMap. There are two little static helper methods createNode . They are almost identical. Both called from BitmapIndexedNode during an assoc operation, one for the transient case, one for the non-transient case. The non-transient one reads:

private static INode createNode(int shift, Object key1, Object val1, int key2hash, Object key2, Object val2) {
	int key1hash = hash(key1);
	if(key1hash == key2hash)
		return new HashCollisionNode(null, key1hash, 2, new Object[] {key1, val1, key2, val2});
	Box addedLeaf = new Box(null);
	AtomicReference<Thread> edit = new AtomicReference<Thread>();
	return BitmapIndexedNode.EMPTY
		.assoc(edit, shift, key1hash, key1, val1, addedLeaf)
		.assoc(edit, shift, key2hash, key2, val2, addedLeaf);
}
Why are we creating an edit value here and using the transient version of assoc? For the transient version:
private static INode createNode(AtomicReference<Thread> edit, int shift, Object key1, Object val1, int key2hash, Object key2, Object val2) {
	int key1hash = hash(key1);
	if(key1hash == key2hash)
		return new HashCollisionNode(null, key1hash, 2, new Object[] {key1, val1, key2, val2});
	Box addedLeaf = new Box(null);
	return BitmapIndexedNode.EMPTY
		.assoc(edit, shift, key1hash, key1, val1, addedLeaf)
		.assoc(edit, shift, key2hash, key2, val2, addedLeaf);
}
For the BitmapIndexedNode case it is okay to start with a BitmapIndexedNode.Empty , having a null edit field, because the first assoc will call ensureEditable and get us all fixed up. My question is: Why is the HashCollisionNode created with a null edit field? If it gets touched again during this transient transaction, it will be copied needlessly, yes? Even if I'm correct, I realize the impact is trivial and not worth consideration; I just don't like not understanding. ,