@@ -29,7 +29,7 @@ final class CNode<K, V> extends MainNode<K, V> {
2929
3030 final int bitmap ;
3131 final Branch <K , V >[] array ;
32- final Gen gen ;
32+ private final Gen gen ;
3333
3434 // Since concurrent computation should lead to same results we can update this field without any synchronization.
3535 private volatile int csize = NO_SIZE ;
@@ -54,6 +54,41 @@ private CNode(final Gen gen, final int bitmap, final Branch<K, V>... array) {
5454 this (gen , 0 , (Branch <K , V >[]) EMPTY_ARRAY );
5555 }
5656
57+ static <K , V > MainNode <K , V > dual (final SNode <K , V > first , final K key , final V value , final int hc ,
58+ final int initLev , final Gen gen ) {
59+ final var second = new SNode <>(key , value , hc );
60+ final var fhc = first .hc ();
61+
62+ // recursion control
63+ final var bmps = new int [MAX_DEPTH ];
64+ int len = 0 ;
65+ int lev = initLev ;
66+
67+ while (true ) {
68+ MainNode <K , V > deepest ;
69+ if (lev < HASH_BITS ) {
70+ final int xidx = fhc >>> lev & 0x1f ;
71+ final int yidx = hc >>> lev & 0x1f ;
72+ final int bmp = 1 << xidx | 1 << yidx ;
73+ if (xidx == yidx ) {
74+ // enter recursion: save bitmap and increment lev
75+ bmps [len ++] = bmp ;
76+ lev += LEVEL_BITS ;
77+ continue ;
78+ }
79+ deepest = xidx < yidx ? new CNode <>(gen , bmp , first , second ) : new CNode <>(gen , bmp , second , first );
80+ } else {
81+ deepest = new LNode <>(first , second );
82+ }
83+
84+ while (len > 0 ) {
85+ // exit recursion: load bitmap and wrap deepest with a CNode
86+ deepest = new CNode <>(gen , bmps [--len ], new INode <>(gen , deepest ));
87+ }
88+ return deepest ;
89+ }
90+ }
91+
5792 Object lookup (final TrieMap <K , V > ct , final Gen startGen , final int hc , final K key , final int lev ,
5893 final INode <K , V > parent ) {
5994 // 1) a multinode
@@ -76,49 +111,33 @@ Object lookup(final TrieMap<K, V> ct, final Gen startGen, final int hc, final K
76111 // 2) singleton node
77112 return sn .lookup (hc , key );
78113 } else {
79- throw TrieMap . invalidElement (sub );
114+ throw invalidElement (sub );
80115 }
81116 }
82117
83- @ Nullable Result <V > remove (final MutableTrieMap <K , V > ct , final Gen startGen , final int hc , final K key ,
84- final Object cond , final int lev , final INode <K , V > parent ) {
118+ boolean insert (final MutableTrieMap <K , V > ct , final Gen startGen , final int hc , final K key , final V val ,
119+ final int lev , final INode <K , V > parent ) {
120+ // 1) a multiway node
85121 final int idx = hc >>> lev & 0x1f ;
86122 final int flag = 1 << idx ;
123+ final int mask = flag - 1 ;
124+ final int pos = Integer .bitCount (bitmap & mask );
125+
87126 if ((bitmap & flag ) == 0 ) {
88- return Result . empty ( );
127+ return insert ( ct , parent , pos , flag , key , val , hc );
89128 }
90129
91- final int pos = Integer . bitCount ( bitmap & flag - 1 );
92- final var sub = array [pos ];
93- if (sub instanceof INode <K , V > in ) {
94- // renew if needed
95- return startGen != in .gen && ! renew (ct , parent , startGen )
96- ? null : in .remove (ct , startGen , hc , key , cond , lev + LEVEL_BITS , parent );
97- } else if (sub instanceof SNode <K , V > sn ) {
98- return remove (ct , parent , flag , pos , sn , key , hc , cond , lev );
130+ // 1a) insert below
131+ final var cnAtPos = array [pos ];
132+ if (cnAtPos instanceof INode <K , V > in ) {
133+ // try to renew if needed and enter next level
134+ return ( startGen == in .gen || renew (ct , parent , startGen ) )
135+ && in .insert (ct , startGen , hc , key , val , lev + LEVEL_BITS , parent );
136+ } else if (cnAtPos instanceof SNode <K , V > sn ) {
137+ return insert (ct , parent , pos , sn , key , val , hc , lev );
99138 } else {
100- throw TrieMap .invalidElement (sub );
101- }
102- }
103-
104- @ Nullable Result <V > remove (final MutableTrieMap <K , V > ct , final INode <K , V > in , final int flag , final int pos ,
105- final SNode <K , V > sn , final K key , final int hc , final Object cond , final int lev ) {
106- if (!sn .matches (hc , key ) || cond != null && !cond .equals (sn .value ())) {
107- return Result .empty ();
139+ throw invalidElement (cnAtPos );
108140 }
109-
110- final var arr = array ;
111- final int len = arr .length ;
112- final var narr = newArray (len - 1 );
113- System .arraycopy (arr , 0 , narr , 0 , pos );
114- System .arraycopy (arr , pos + 1 , narr , pos , len - pos - 1 );
115- final var onlySN = onlySNode (narr , lev );
116- return in .gcasWrite (onlySN != null ? onlySN .copyTombed (this ) : new CNode <>(this , gen , bitmap ^ flag , narr ), ct )
117- ? sn .toResult () : null ;
118- }
119-
120- boolean renew (final TrieMap <K , V > ct , final INode <K , V > in , final Gen ngen ) {
121- return in .gcasWrite (renewed (ngen , ct ), ct );
122141 }
123142
124143 boolean insert (final MutableTrieMap <K , V > ct , final INode <K , V > in , final int pos , final SNode <K , V > sn ,
@@ -140,7 +159,37 @@ boolean insert(final MutableTrieMap<K, V> ct, final INode<K, V> in, final int po
140159 return in .gcasWrite (rn .toInsertedAt (this , ngen , pos , flag , key , val , hc ), ct );
141160 }
142161
143- @ Nullable Result <V > insertIf (final MutableTrieMap <K , V > ct , final INode <K , V > in , final int pos ,
162+ @ Nullable Result <V > insertIf (final MutableTrieMap <K , V > ct , final Gen startGen , final int hc , final K key ,
163+ final V val , final Object cond , final int lev , final INode <K , V > parent ) {
164+ // 1) a multiway node
165+ final int idx = hc >>> lev & 0x1f ;
166+ final int flag = 1 << idx ;
167+ final int bmp = bitmap ;
168+ final int mask = flag - 1 ;
169+ final int pos = Integer .bitCount (bmp & mask );
170+
171+ if ((bmp & flag ) == 0 ) {
172+ // not found
173+ return cond != null && cond != ABSENT || insert (ct , parent , pos , flag , key , val , hc )
174+ ? Result .empty () : null ;
175+ }
176+
177+ // 1a) insert below
178+ final var cnAtPos = array [pos ];
179+ if (cnAtPos instanceof INode <K , V > in ) {
180+ // enter next level
181+ if (startGen != in .gen && !renew (ct , parent , startGen )) {
182+ return null ;
183+ }
184+ return in .insertIf (ct , startGen , hc , key , val , cond , lev + LEVEL_BITS , parent );
185+ } else if (cnAtPos instanceof SNode <K , V > sn ) {
186+ return insertIf (ct , parent , pos , sn , key , val , hc , cond , lev );
187+ } else {
188+ throw invalidElement (cnAtPos );
189+ }
190+ }
191+
192+ private @ Nullable Result <V > insertIf (final MutableTrieMap <K , V > ct , final INode <K , V > in , final int pos ,
144193 final SNode <K , V > sn , final K key , final V val , final int hc , final Object cond , final int lev ) {
145194 if (!sn .matches (hc , key )) {
146195 if (cond == null || cond == ABSENT ) {
@@ -159,44 +208,74 @@ boolean insert(final MutableTrieMap<K, V> ct, final INode<K, V> in, final int po
159208 return Result .empty ();
160209 }
161210
162- MainNode <K , V > toContracted (final CNode <K , V > prev , final int lev ) {
163- final var sn = onlySNode (array , lev );
164- return sn == null ? new CNode <>(prev , gen , bitmap , array ) : sn .copyTombed (prev );
165- }
211+ @ Nullable Result <V > remove (final MutableTrieMap <K , V > ct , final Gen startGen , final int hc , final K key ,
212+ final Object cond , final int lev , final INode <K , V > parent ) {
213+ final int idx = hc >>> lev & 0x1f ;
214+ final int flag = 1 << idx ;
215+ if ((bitmap & flag ) == 0 ) {
216+ return Result .empty ();
217+ }
166218
167- static <K , V > MainNode <K , V > dual (final SNode <K , V > first , final K key , final V value , final int hc ,
168- final int initLev , final Gen gen ) {
169- final var second = new SNode <>(key , value , hc );
170- final var fhc = first .hc ();
219+ final int pos = Integer .bitCount (bitmap & flag - 1 );
220+ final var sub = array [pos ];
221+ if (sub instanceof INode <K , V > in ) {
222+ // renew if needed
223+ return startGen != in .gen && !renew (ct , parent , startGen )
224+ ? null : in .remove (ct , startGen , hc , key , cond , lev + LEVEL_BITS , parent );
225+ } else if (sub instanceof SNode <K , V > sn ) {
226+ if (!sn .matches (hc , key ) || cond != null && !cond .equals (sn .value ())) {
227+ return Result .empty ();
228+ }
229+ return parent .gcasWrite (toRemoved (ct , flag , pos , lev ), ct ) ? sn .toResult () : null ;
230+ } else {
231+ throw invalidElement (sub );
232+ }
233+ }
171234
172- // recursion control
173- final var bmps = new int [MAX_DEPTH ];
174- int len = 0 ;
175- int lev = initLev ;
235+ private MainNode <K , V > toRemoved (final MutableTrieMap <K , V > ct , final int flag , final int pos , final int lev ) {
236+ final var arr = array ;
237+ final int len = arr .length ;
238+ final var narr = newArray (len - 1 );
239+ System .arraycopy (arr , 0 , narr , 0 , pos );
240+ System .arraycopy (arr , pos + 1 , narr , pos , len - pos - 1 );
176241
177- while (true ) {
178- MainNode <K , V > deepest ;
179- if (lev < HASH_BITS ) {
180- final int xidx = fhc >>> lev & 0x1f ;
181- final int yidx = hc >>> lev & 0x1f ;
182- final int bmp = 1 << xidx | 1 << yidx ;
183- if (xidx == yidx ) {
184- // enter recursion: save bitmap and increment lev
185- bmps [len ++] = bmp ;
186- lev += LEVEL_BITS ;
187- continue ;
188- }
189- deepest = xidx < yidx ? new CNode <>(gen , bmp , first , second ) : new CNode <>(gen , bmp , second , first );
190- } else {
191- deepest = new LNode <>(first , second );
192- }
242+ return toUpdated (gen , lev , narr , bitmap ^ flag );
243+ }
193244
194- while (len > 0 ) {
195- // exit recursion: load bitmap and wrap deepest with a CNode
196- deepest = new CNode <>(gen , bmps [--len ], new INode <>(gen , deepest ));
197- }
198- return deepest ;
245+ // - if the branching factor is 1 for this CNode, and the child is a tombed SNode, returns its tombed version
246+ // - otherwise, if there is at least one non-null node below, returns the version of this node with at least some
247+ // null-inodes removed (those existing when the op began)
248+ // - if there are only null-i-nodes below, returns null
249+ MainNode <K , V > toCompressed (final TrieMap <K , V > ct , final Gen ngen , final int lev ) {
250+ final var arr = array ;
251+ final int len = arr .length ;
252+ final var narr = newArray (len );
253+ for (int i = 0 ; i < len ; i ++) {
254+ final var tmp = arr [i ];
255+ narr [i ] = tmp instanceof INode <K , V > in ? resurrect (in , ct ) : tmp ;
199256 }
257+
258+ return toUpdated (ngen , lev , narr , bitmap );
259+ }
260+
261+ MainNode <K , V > toContracted (final Gen ngen , final int pos , final TNode <K , V > tn , final int lev ) {
262+ final int len = array .length ;
263+ final var narr = newArray (len );
264+ System .arraycopy (array , 0 , narr , 0 , len );
265+ narr [pos ] = new SNode <>(tn );
266+
267+ return toUpdated (ngen , lev , narr , bitmap );
268+ }
269+
270+ private MainNode <K , V > toUpdated (final Gen ngen , final int lev , final Branch <K , V >[] arr , final int bmp ) {
271+ // Note: special-case for root, so we always have a ct.root.main is always a CNode
272+ return lev > 0 && arr .length == 1 && arr [0 ] instanceof SNode <K , V > sn
273+ ? new TNode <>(this , sn ) : new CNode <>(this , ngen , bmp , arr );
274+ }
275+
276+ // tries to gcasWrite() a copy of this CNode renewed to ngen
277+ private boolean renew (final TrieMap <K , V > ct , final INode <K , V > in , final Gen ngen ) {
278+ return in .gcasWrite (renewed (ngen , ct ), ct );
200279 }
201280
202281 @ Override
@@ -238,13 +317,13 @@ private static int elementSize(final Branch<?, ?> elem, final ImmutableTrieMap<?
238317 if (elem instanceof SNode ) {
239318 return 1 ;
240319 } else if (elem instanceof INode <?, ?> inode ) {
241- return inode .size (ct );
320+ return inode .readSize (ct );
242321 } else {
243- throw TrieMap . invalidElement (elem );
322+ throw invalidElement (elem );
244323 }
245324 }
246325
247- CNode <K , V > updatedAt (final int pos , final Branch <K , V > nn , final Gen ngen ) {
326+ private CNode <K , V > updatedAt (final int pos , final Branch <K , V > nn , final Gen ngen ) {
248327 return toUpdatedAt (this , pos , nn , ngen );
249328 }
250329
@@ -285,22 +364,6 @@ private CNode<K, V> renewed(final Gen ngen, final TrieMap<K, V> ct) {
285364 return new CNode <>(this , ngen , bitmap , narr );
286365 }
287366
288- // - if the branching factor is 1 for this CNode, and the child is a tombed SNode, returns its tombed version
289- // - otherwise, if there is at least one non-null node below, returns the version of this node with at least some
290- // null-inodes removed (those existing when the op began)
291- // - if there are only null-i-nodes below, returns null
292- MainNode <K , V > toCompressed (final TrieMap <K , V > ct , final int lev , final Gen ngen ) {
293- final var arr = array ;
294- final int len = arr .length ;
295- final var narr = newArray (len );
296- for (int i = 0 ; i < len ; i ++) {
297- final var tmp = arr [i ];
298- narr [i ] = tmp instanceof INode <K , V > in ? resurrect (in , ct ) : tmp ;
299- }
300- final var sn = onlySNode (narr , lev );
301- return sn != null ? sn .copyTombed (this ) : new CNode <>(this , ngen , bitmap , narr );
302- }
303-
304367 @ Override
305368 public String toString () {
306369 return "CNode" ;
@@ -311,11 +374,12 @@ private Branch<K, V>[] newArray(final int size) {
311374 return new Branch [size ];
312375 }
313376
314- private @ Nullable SNode <K , V > onlySNode (final Branch <K , V >[] arr , final int lev ) {
315- return arr . length == 1 && lev > 0 && arr [ 0 ] instanceof SNode <K , V > sn ? sn : null ;
377+ private static <K , V > Branch < K , V > resurrect (final INode <K , V > in , final TrieMap < K , V > ct ) {
378+ return in . gcasReadNonNull ( ct ) instanceof TNode <K , V > tn ? new SNode <>( tn ) : in ;
316379 }
317380
318- private static <K , V > Branch <K , V > resurrect (final INode <K , V > in , final TrieMap <K , V > ct ) {
319- return in .gcasReadNonNull (ct ) instanceof TNode <K , V > tnode ? tnode .copyUntombed () : in ;
381+ // Visible for testing
382+ static VerifyException invalidElement (final Branch <?, ?> elem ) {
383+ throw new VerifyException ("A CNode can contain only INodes and SNodes, not " + elem );
320384 }
321385}
0 commit comments