// 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; } } }
// concurrent read/write access is allowed boolean appendNewAtomic(double key, Object value, ConcurrentDoubleOrderedListMap orderedMap) { synchronized (this) { if (isMarked()) return false; if (next != null) return false; Node n = Node.alloc(); n.put(key, value, orderedMap); // assert n.len()==1; n.next = null; boolean success = casNext(null, n); assert success; return true; } }
// only used by putAtomic and PutAtomicIfAbsent. Inside synchronized(b) and synchronized(this). private void putAtomicReally( Node b, int pos, double key, Object value, ConcurrentDoubleOrderedListMap orderedMap) { int len = len(); if (len + 1 <= keys.length) { if (pos == len) { // in-place append in the current node keys[pos] = key; vals[pos] = value; length = len + 1; if (pos == 0) { orderedMap.skipListMap.put(keys[0], this); } } else { // copied to a new node, replacing the current node mark(); Node n = Node.alloc(); n.next = this.next; if (next != null) next.incRefCnt(); double[] nkeys = n.keys; Object[] nvals = n.vals; n.length = len + 1; nodeCopy(keys, vals, 0, nkeys, nvals, 0, pos); nkeys[pos] = key; nvals[pos] = value; nodeCopy(keys, vals, pos, nkeys, nvals, pos + 1, len - pos); orderedMap.skipListMap.put(nkeys[0], n); b.casNext(this, n); // should always succeed. if (pos == 0) { orderedMap.skipListMap.remove(keys[0], this); } release(this); free(this); } } else { // requires 2 new nodes, to replace the current node mark(); Node n1 = Node.alloc(); double[] n1keys = n1.keys; Object[] n1vals = n1.vals; Node n2 = Node.alloc(); double[] n2keys = n2.keys; Object[] n2vals = n2.vals; int l1 = len / 2, l2 = len - l1; if (pos < l1) { // key, value stored in n1 n1.length = l1 + 1; n2.length = l2; nodeCopy(keys, vals, 0, n1keys, n1vals, 0, pos); n1keys[pos] = key; n1vals[pos] = value; nodeCopy(keys, vals, pos, n1keys, n1vals, pos + 1, l1 - pos); nodeCopy(keys, vals, l1, n2keys, n2vals, 0, l2); n1.next = n2; n2.next = this.next; if (next != null) next.incRefCnt(); orderedMap.skipListMap.put(n1keys[0], n1); orderedMap.skipListMap.put(n2keys[0], n2); b.casNext(this, n1); // should always succeed. if (pos == 0) { orderedMap.skipListMap.remove(keys[0], this); } release(this); free(this); } else { // key,value is stored in n2 n1.length = l1; n2.length = l2 + 1; int newpos = pos - l1; nodeCopy(keys, vals, 0, n1keys, n1vals, 0, l1); nodeCopy(keys, vals, l1, n2keys, n2vals, 0, newpos); n2keys[newpos] = key; n2vals[newpos] = value; nodeCopy(keys, vals, pos, n2keys, n2vals, newpos + 1, l2 - newpos); n1.next = n2; n2.next = this.next; if (next != null) next.incRefCnt(); orderedMap.skipListMap.put(n1keys[0], n1); orderedMap.skipListMap.put(n2keys[0], n2); b.casNext(this, n1); // should always succeed. release(this); free(this); } } }
// no concurrent read/write access is assumed private void putReally( int pos, double key, Object value, ConcurrentDoubleOrderedListMap orderedMap) { int len = len(); if (len + 1 <= keys.length) { // inserted in the current node nodeCopy(keys, vals, pos, keys, vals, pos + 1, len - pos); keys[pos] = key; vals[pos] = value; length = len + 1; if (pos == 0) { orderedMap.skipListMap.put(keys[0], this); if (len != 0) orderedMap.skipListMap.remove(keys[1], this); } } else if (emptySlotInNextTwo()) { if (pos == len) { next.put(key, value, orderedMap); return; } next.put(keys[len - 1], vals[len - 1], orderedMap); nodeCopy(keys, vals, pos, keys, vals, pos + 1, len - pos - 1); keys[pos] = key; vals[pos] = value; if (pos == 0) { orderedMap.skipListMap.remove(keys[1], this); orderedMap.skipListMap.put(keys[0], this); } } else { // current node is full, so requires a new node Node n = Node.alloc(); double[] nkeys = n.keys; Object[] nvals = n.vals; int l1 = len / 2, l2 = len - l1; if (next == null && pos == len) { // this is the last node, simply add to the new node. nkeys[0] = key; nvals[0] = value; n.length = 1; orderedMap.skipListMap.put(nkeys[0], n); } else if (pos < l1) { // key,value is stored in the current node length = l1 + 1; n.length = l2; nodeCopy(keys, vals, l1, nkeys, nvals, 0, l2); nodeCopy(keys, vals, pos, keys, vals, pos + 1, l1 - pos); keys[pos] = key; vals[pos] = value; if (pos == 0) { orderedMap.skipListMap.remove(keys[1]); orderedMap.skipListMap.put(keys[0], this); } orderedMap.skipListMap.put(nkeys[0], n); } else { // key,value is stored in the new node length = l1; n.length = l2 + 1; int newpos = pos - l1; nodeCopy(keys, vals, l1, nkeys, nvals, 0, newpos); nkeys[newpos] = key; nvals[newpos] = value; nodeCopy(keys, vals, pos, nkeys, nvals, newpos + 1, l2 - newpos); orderedMap.skipListMap.put(nkeys[0], n); } n.next = this.next; this.next = n; } }