// 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;
      }
    }
    // 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;
      }
    }