/** * Inserts a new key value pair, given that a specific condition is met. * * @param cond * null - don't care if the key was there * KEY_ABSENT - key wasn't there * KEY_PRESENT - key was there * other value `v` - key must be bound to `v` * @return null if unsuccessful, Option[V] otherwise (indicating * previous value bound to the key) */ public Option <V> rec_insertif(K k, V v, int hc, Object cond, int lev, INode <K, V> parent, Gen startgen, ConcurrentTrieDictionary <K, V> ct) { while (true) { MainNode <K, V> m = GCAS_READ(ct); // use -Yinline! if (m is CNode <K, V> ) { // 1) a multiway node CNode <K, V> cn = (CNode <K, V>)m; int idx = (int)((uint)hc >> lev) & 0x1f; int flag = 1 << idx; int bmp = cn.bitmap; int mask = flag - 1; int pos = JavaCompat.SparseBitcount(bmp & mask); if ((bmp & flag) != 0) { // 1a) insert below BasicNode cnAtPos = cn.array[pos]; if (cnAtPos is INode <K, V> ) { INode <K, V> _in = (INode <K, V>)cnAtPos; if (startgen == _in.gen) { return(_in.rec_insertif(k, v, hc, cond, lev + 5, this, startgen, ct)); } else { if (GCAS(cn, cn.renewed(startgen, ct), ct)) { // return rec_insertif (k, v, hc, cond, lev, // parent, startgen, ct); // tailrec continue; } else { return(null); } } } else if (cnAtPos is SNode <K, V> ) { SNode <K, V> sn = (SNode <K, V>)cnAtPos; if (cond == null) { if (sn.hc == hc && equal(sn.k, k, ct)) { if (GCAS(cn, cn.updatedAt(pos, new SNode <K, V>(k, v, hc), gen), ct)) { return(Option <V> .makeOption(sn.v)); } else { return(null); } } else { CNode <K, V> rn = (cn.gen == gen) ? cn : cn.renewed(gen, ct); MainNode <K, V> nn = rn.updatedAt(pos, inode(CNode <K, V> .dual(sn, sn.hc, new SNode <K, V>(k, v, hc), hc, lev + 5, gen)), gen); if (GCAS(cn, nn, ct)) { return(Option <V> .makeOption()); // None; } else { return(null); } } } else if (cond == INode <K, V> .KEY_ABSENT) { if (sn.hc == hc && equal(sn.k, k, ct)) { return(Option <V> .makeOption(sn.v)); } else { CNode <K, V> rn = (cn.gen == gen) ? cn : cn.renewed(gen, ct); MainNode <K, V> nn = rn.updatedAt(pos, inode(CNode <K, V> .dual(sn, sn.hc, new SNode <K, V>(k, v, hc), hc, lev + 5, gen)), gen); if (GCAS(cn, nn, ct)) { return(Option <V> .makeOption()); // None } else { return(null); } } } else if (cond == INode <K, V> .KEY_PRESENT) { if (sn.hc == hc && equal(sn.k, k, ct)) { if (GCAS(cn, cn.updatedAt(pos, new SNode <K, V>(k, v, hc), gen), ct)) { return(Option <V> .makeOption(sn.v)); } else { return(null); } } else { return(Option <V> .makeOption());// None; } } else { if (sn.hc == hc && equal(sn.k, k, ct) && sn.v.Equals(cond)) { if (GCAS(cn, cn.updatedAt(pos, new SNode <K, V>(k, v, hc), gen), ct)) { return(Option <V> .makeOption(sn.v)); } else { return(null); } } else { return(Option <V> .makeOption()); // None } } } } else if (cond == null || cond == INode <K, V> .KEY_ABSENT) { CNode <K, V> rn = (cn.gen == gen) ? cn : cn.renewed(gen, ct); CNode <K, V> ncnode = rn.insertedAt(pos, flag, new SNode <K, V>(k, v, hc), gen); if (GCAS(cn, ncnode, ct)) { return(Option <V> .makeOption());// None } else { return(null); } } else if (cond == INode <K, V> .KEY_PRESENT) { return(Option <V> .makeOption());// None; } else { return(Option <V> .makeOption()); // None } } else if (m is TNode <K, V> ) { clean(parent, ct, lev - 5); return(null); } else if (m is LNode <K, V> ) { // 3) an l-node LNode <K, V> ln = (LNode <K, V>)m; if (cond == null) { Option <V> optv = ln.get(k); if (insertln(ln, k, v, ct)) { return(optv); } else { return(null); } } else if (cond == INode <K, V> .KEY_ABSENT) { Option <V> t = ln.get(k); if (t == null) { if (insertln(ln, k, v, ct)) { return(Option <V> .makeOption());// None } else { return(null); } } else { return(t); } } else if (cond == INode <K, V> .KEY_PRESENT) { Option <V> t = ln.get(k); if (t != null) { if (insertln(ln, k, v, ct)) { return(t); } else { return(null); } } else { return(null); // None } } else { Option <V> t = ln.get(k); if (t != null) { if (((Some <V>)t).get().Equals(cond)) { if (insertln(ln, k, v, ct)) { return(new Some <V>((V)cond)); } else { return(null); } } else { return(Option <V> .makeOption()); } } } } // throw new RuntimeException ("Should not happen"); } }
/** * Inserts a key value pair, overwriting the old pair if the keys match. * * @return true if successful, false otherwise */ public bool rec_insert(K k, V v, int hc, int lev, INode <K, V> parent, Gen startgen, ConcurrentTrieDictionary <K, V> ct) { while (true) { MainNode <K, V> m = GCAS_READ(ct); // use -Yinline! if (m is CNode <K, V> ) { // 1) a multiway node CNode <K, V> cn = (CNode <K, V>)m; int idx = (int)((uint)hc >> lev) & 0x1f; int flag = 1 << idx; int bmp = cn.bitmap; int mask = flag - 1; int pos = JavaCompat.SparseBitcount(bmp & mask); if ((bmp & flag) != 0) { // 1a) insert below BasicNode cnAtPos = cn.array[pos]; if (cnAtPos is INode <K, V> ) { INode <K, V> _in = (INode <K, V>)cnAtPos; if (startgen == _in.gen) { return(_in.rec_insert(k, v, hc, lev + 5, this, startgen, ct)); } else { if (GCAS(cn, cn.renewed(startgen, ct), ct)) { // return rec_insert (k, v, hc, lev, parent, // startgen, ct); // tailrec continue; } else { return(false); } } } else if (cnAtPos is SNode <K, V> ) { SNode <K, V> sn = (SNode <K, V>)cnAtPos; if (sn.hc == hc && equal((K)sn.k, k, ct)) { return(GCAS(cn, cn.updatedAt(pos, new SNode <K, V>(k, v, hc), gen), ct)); } else { CNode <K, V> rn = (cn.gen == gen) ? cn : cn.renewed(gen, ct); MainNode <K, V> nn = rn.updatedAt(pos, inode(CNode <K, V> .dual(sn, sn.hc, new SNode <K, V>(k, v, hc), hc, lev + 5, gen)), gen); return(GCAS(cn, nn, ct)); } } } else { CNode <K, V> rn = (cn.gen == gen) ? cn : cn.renewed(gen, ct); MainNode <K, V> ncnode = rn.insertedAt(pos, flag, new SNode <K, V>(k, v, hc), gen); return(GCAS(cn, ncnode, ct)); } } else if (m is TNode <K, V> ) { clean(parent, ct, lev - 5); return(false); } else if (m is LNode <K, V> ) { LNode <K, V> ln = (LNode <K, V>)m; MainNode <K, V> nn = ln.inserted(k, v); return(GCAS(ln, nn, ct)); } throw new RuntimeException("Should not happen"); } }