// 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;
     }
   }
 }
    int findBeginIndex(Node n, double key, boolean inclusive) {
      boolean exclusive = !inclusive;
      if (key <= n.first()) {
        if (key == n.first() && exclusive) return 1;
        return 0;
      }
      int pos = n.findKeyIndex(key);
      if (pos < 0) pos = -(pos + 1);
      else if (!inclusive) pos++;

      return pos;
    }
  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;
        }
      }
    }
  }
 private boolean isInconsistentNextNode(Node f, double key) {
   /**
    * With skipListMap.findGrandPredecessor, we expect the key of the target node (next of next
    * node of returned node) to be greater than or equal to the given key. If not, there is
    * inconsistency between skipListMap and this ordered list map.
    *
    * @see Node#putAtomicReally for the cause of this inconsistency
    */
   return f.next != null && f.first() < key;
 }
 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;
     }
   }
 }
 public void doSanityCheck() {
   int count = 0;
   double prevKey = Double.MIN_VALUE;
   Node n = safeNext(head);
   while (n != null) {
     count++;
     if (!skipListMap.containsKey(n.first())) {
       System.out.println("Node n not in skiplistMap:" + n.first());
       n._print();
     }
     if (n.first() < prevKey) {
       System.out.println("Error in ordering, prevKey:" + prevKey + ", n:" + n);
     }
     prevKey = n.first();
     Node next = safeNext(n);
     release(n);
     n = next;
   }
   if (skipListMap.size() != count) {
     System.out.println("skipListMap.size:" + skipListMap.size() + ", count:" + count);
   }
 }
    int findEndIndex(Node n, double key, boolean inclusive) {
      boolean exclusive = !inclusive;
      if (key < n.first()) return -1;
      if (key >= n.last()) {
        if (key == n.last() && exclusive) return n.len() - 2;
        return n.len() - 1;
      }
      int pos = n.findKeyIndex(key);
      if (pos < 0) pos = -(pos + 1);
      else if (!inclusive) pos--;

      if (pos == n.len()) pos--;
      return pos;
    }
Пример #8
0
 protected Node first() {
   if (left == nullNode) return this;
   return left.first();
 }
Пример #9
0
 public K first() {
   if (isEmpty()) return null;
   if (from == null) return root.first().key;
   if (fromInclusive) return ceiling(from);
   return higher(from);
 }