// no concurrent read/write is assumed public V put(double key, V value) { if (value == null) throw new NullPointerException(); // not incrementing b's refcnt, so need not release it. Node b = skipListMap.findGrandPredecessor(key); if (b == null) b = head; Node n = b.next; if (n == null) { n = Node.alloc(); n.put(key, value, this); n.next = null; b.next = n; return null; } Node f = n.next; if (f == null) { // put (key,value) into node n Object val = n.put(key, value, this); return (V) val; } else { assert f.len() > 0 && f.first() >= key; if (f.first() == key) { Object val = f.put(key, value, this); return (V) val; } else { Object val = n.put(key, value, this); return (V) val; } } }
Node ceilingNode(double key) { for (; ; ) { Node b = skipListMap.findGrandPredecessor(key, refCntCallback); if (b == null) b = head; if (b != head && key <= b.last()) { return b; } assert b == head || b.last() < key; Node n = safeNext(b); release(b); if (n == null) { return null; } else if (key <= n.last()) { return n; } Node f = safeNext(n); release(n); if (f == null) { return null; } else { if (isInconsistentNextNode(f, key)) { release(f); continue; } return f; } } }
V putAtomic(double key, V value, boolean onlyIfAbsent) { if (value == null) throw new NullPointerException(); for (; ; ) { Node b = skipListMap.findGrandPredecessor(key, refCntCallback); if (b == null) b = head; if (b != head && b.first() <= key && key <= b.last()) { release(b); continue; } assert b == head || b.last() < key; Node n = safeNext(b); if (n == null) { if (b.appendNewAtomic(key, value, this)) { release(b); return null; } else { release(b); continue; } } else if (n.first() <= key && key <= n.last()) { Object val = n.putAtomic(key, value, b, onlyIfAbsent, this); release(b, n); if (val == Retry) continue; return (V) val; } Node f = safeNext(n); if (f == null) { Object val = n.putAtomic(key, value, b, onlyIfAbsent, this); release(b, n); if (val == Retry) continue; return (V) val; } else { if (f.first() == key) { Object val = f.putAtomic(key, value, n, onlyIfAbsent, this); release(b, n, f); if (val == Retry) continue; return (V) val; } else { if (key > f.first()) { // inconsistent read, retry release(b, n, f); continue; } Object val = n.putAtomic(key, value, b, onlyIfAbsent, this); release(b, n, f); if (val == Retry) continue; return (V) val; } } } }
V doReplace(double key, V old, V value) { for (; ; ) { Node b = skipListMap.findGrandPredecessor(key, refCntCallback); if (b == null) b = head; if (b != head && b.first() <= key && key <= b.last()) { // can happen if there's inconsistency between skipListMap and orderedMap(this). // The inconsistency can happen from Node.putAtomicReally(), // where it adds to, and removes from skiplistMap. Object val = b.replace(key, old, value); release(b); if (val == Retry) continue; return (V) val; } assert b == head || b.last() < key; Node n = safeNext(b); release(b); if (n == null) { return null; } else if (n.first() <= key && key <= n.last()) { Object val = n.replace(key, old, value); release(n); if (val == Retry) continue; return (V) val; } Node f = safeNext(n); release(n); if (f == null) { return null; } else { if (isInconsistentNextNode(f, key)) { release(f); continue; } Object val = f.replace(key, old, value); release(f); if (val == Retry) continue; return (V) val; } } }