560 |
|
return false; |
561 |
|
} |
562 |
|
|
563 |
< |
/* |
564 |
< |
* Possible values for "how" argument in xfer method. |
565 |
< |
*/ |
563 |
> |
/** |
564 |
> |
* Collapse dead (matched) nodes between pred and q. |
565 |
> |
* @param pred the last known live node, or null if none |
566 |
> |
* @param c the first dead node |
567 |
> |
* @param p the last dead node |
568 |
> |
* @param q p.next: the next live node, or null if at end |
569 |
> |
* @return either old pred or p if pred dead or CAS failed |
570 |
> |
*/ |
571 |
> |
private Node skipDeadNodes(Node pred, Node c, Node p, Node q) { |
572 |
> |
// assert pred != c; |
573 |
> |
// assert p != q; |
574 |
> |
// assert c.isMatched(); |
575 |
> |
// assert p.isMatched(); |
576 |
> |
if (q == null) { |
577 |
> |
// Never unlink trailing node. |
578 |
> |
if (c == p) return pred; |
579 |
> |
q = p; |
580 |
> |
} |
581 |
> |
return (tryCasSuccessor(pred, c, q) |
582 |
> |
&& (pred == null || !pred.isMatched())) |
583 |
> |
? pred : p; |
584 |
> |
} |
585 |
> |
|
586 |
> |
/* Possible values for "how" argument in xfer method. */ |
587 |
> |
|
588 |
|
private static final int NOW = 0; // for untimed poll, tryTransfer |
589 |
|
private static final int ASYNC = 1; // for offer, put, add |
590 |
|
private static final int SYNC = 2; // for transfer, take |
1472 |
|
* @return {@code true} if this queue changed as a result of the call |
1473 |
|
*/ |
1474 |
|
public boolean remove(Object o) { |
1475 |
< |
if (o == null) |
1454 |
< |
return false; |
1475 |
> |
if (o == null) return false; |
1476 |
|
restartFromHead: for (;;) { |
1477 |
< |
for (Node p = head, c = p, pred = null, q; p != null; ) { |
1478 |
< |
final Object item; boolean pAlive; |
1479 |
< |
if (pAlive = ((item = p.item) != null && p.isData)) { |
1480 |
< |
if (o.equals(item) && p.tryMatchData()) { |
1481 |
< |
if ((q = p.next) == null) q = p; |
1482 |
< |
if (c != q) tryCasSuccessor(pred, c, q); |
1483 |
< |
return true; |
1477 |
> |
for (Node p = head, pred = null; p != null; ) { |
1478 |
> |
Node q = p.next; |
1479 |
> |
final Object item; |
1480 |
> |
if ((item = p.item) != null) { |
1481 |
> |
if (p.isData) { |
1482 |
> |
if (o.equals(item) && p.tryMatchData()) { |
1483 |
> |
skipDeadNodes(pred, p, p, q); |
1484 |
> |
return true; |
1485 |
> |
} |
1486 |
> |
pred = p; p = q; continue; |
1487 |
|
} |
1488 |
|
} |
1489 |
< |
else if (!p.isData && item == null) |
1489 |
> |
else if (!p.isData) |
1490 |
|
break; |
1491 |
< |
if ((c != p && !tryCasSuccessor(pred, c, c = p)) || pAlive) { |
1492 |
< |
pred = p; |
1493 |
< |
c = p = p.next; |
1491 |
> |
for (Node c = p;;) { |
1492 |
> |
if ((q = p.next) == null || !q.isMatched()) { |
1493 |
> |
pred = skipDeadNodes(pred, c, p, q); p = q; break; |
1494 |
> |
} |
1495 |
> |
if (p == (p = q)) continue restartFromHead; |
1496 |
|
} |
1471 |
– |
else if (p == (p = p.next)) |
1472 |
– |
continue restartFromHead; |
1497 |
|
} |
1498 |
|
return false; |
1499 |
|
} |
1508 |
|
* @return {@code true} if this queue contains the specified element |
1509 |
|
*/ |
1510 |
|
public boolean contains(Object o) { |
1511 |
< |
if (o == null) |
1488 |
< |
return false; |
1511 |
> |
if (o == null) return false; |
1512 |
|
restartFromHead: for (;;) { |
1513 |
< |
for (Node p = head, c = p, pred = null; p != null; ) { |
1514 |
< |
final Object item; final boolean pAlive; |
1515 |
< |
if (pAlive = ((item = p.item) != null && p.isData)) { |
1516 |
< |
if (o.equals(item)) |
1517 |
< |
return true; |
1513 |
> |
for (Node p = head, pred = null; p != null; ) { |
1514 |
> |
Node q = p.next; |
1515 |
> |
final Object item; |
1516 |
> |
if ((item = p.item) != null) { |
1517 |
> |
if (p.isData) { |
1518 |
> |
if (o.equals(item)) |
1519 |
> |
return true; |
1520 |
> |
pred = p; p = q; continue; |
1521 |
> |
} |
1522 |
|
} |
1523 |
< |
else if (!p.isData && item == null) |
1523 |
> |
else if (!p.isData) |
1524 |
|
break; |
1525 |
< |
if ((c != p && !tryCasSuccessor(pred, c, c = p)) || pAlive) { |
1526 |
< |
pred = p; |
1527 |
< |
c = p = p.next; |
1525 |
> |
for (Node c = p;;) { |
1526 |
> |
if ((q = p.next) == null || !q.isMatched()) { |
1527 |
> |
pred = skipDeadNodes(pred, c, p, q); p = q; break; |
1528 |
> |
} |
1529 |
> |
if (p == (p = q)) continue restartFromHead; |
1530 |
|
} |
1502 |
– |
else if (p == (p = p.next)) |
1503 |
– |
continue restartFromHead; |
1531 |
|
} |
1532 |
|
return false; |
1533 |
|
} |
1659 |
|
*/ |
1660 |
|
@SuppressWarnings("unchecked") |
1661 |
|
void forEachFrom(Consumer<? super E> action, Node p) { |
1662 |
< |
for (Node c = p, pred = null; p != null; ) { |
1663 |
< |
final Object item; final boolean pAlive; |
1664 |
< |
if (pAlive = ((item = p.item) != null && p.isData)) |
1665 |
< |
action.accept((E) item); |
1666 |
< |
else if (!p.isData && item == null) |
1662 |
> |
for (Node pred = null; p != null; ) { |
1663 |
> |
Node q = p.next; |
1664 |
> |
final Object item; |
1665 |
> |
if ((item = p.item) != null) { |
1666 |
> |
if (p.isData) { |
1667 |
> |
action.accept((E) item); |
1668 |
> |
pred = p; p = q; continue; |
1669 |
> |
} |
1670 |
> |
} |
1671 |
> |
else if (!p.isData) |
1672 |
|
break; |
1673 |
< |
if ((c != p && !tryCasSuccessor(pred, c, c = p)) || pAlive) { |
1674 |
< |
pred = p; |
1675 |
< |
c = p = p.next; |
1676 |
< |
} |
1677 |
< |
else if (p == (p = p.next)) { |
1646 |
< |
pred = null; |
1647 |
< |
c = p = head; |
1673 |
> |
for (Node c = p;;) { |
1674 |
> |
if ((q = p.next) == null || !q.isMatched()) { |
1675 |
> |
pred = skipDeadNodes(pred, c, p, q); p = q; break; |
1676 |
> |
} |
1677 |
> |
if (p == (p = q)) { pred = null; p = head; break; } |
1678 |
|
} |
1679 |
|
} |
1680 |
|
} |