498 |
|
* @return {@code true} if this list contained the specified element |
499 |
|
*/ |
500 |
|
public boolean remove(Object o) { |
501 |
+ |
Object[] snapshot = getArray(); |
502 |
+ |
int index = indexOf(o, snapshot, 0, snapshot.length); |
503 |
+ |
return (index < 0) ? false : remove(o, snapshot, index); |
504 |
+ |
} |
505 |
+ |
|
506 |
+ |
/** |
507 |
+ |
* A version of remove(Object) using the strong hint that given |
508 |
+ |
* recent snapshot contains o at the given index. |
509 |
+ |
*/ |
510 |
+ |
private boolean remove(Object o, Object[] snapshot, int index) { |
511 |
|
final ReentrantLock lock = this.lock; |
512 |
|
lock.lock(); |
513 |
|
try { |
514 |
< |
Object[] elements = getArray(); |
515 |
< |
int len = elements.length; |
516 |
< |
if (len != 0) { |
517 |
< |
// Copy while searching for element to remove |
518 |
< |
// This wins in the normal case of element being present |
519 |
< |
int newlen = len - 1; |
520 |
< |
Object[] newElements = new Object[newlen]; |
521 |
< |
|
522 |
< |
for (int i = 0; i < newlen; ++i) { |
513 |
< |
if (eq(o, elements[i])) { |
514 |
< |
// found one; copy remaining and exit |
515 |
< |
for (int k = i + 1; k < len; ++k) |
516 |
< |
newElements[k-1] = elements[k]; |
517 |
< |
setArray(newElements); |
518 |
< |
return true; |
519 |
< |
} else |
520 |
< |
newElements[i] = elements[i]; |
521 |
< |
} |
522 |
< |
|
523 |
< |
// special handling for last cell |
524 |
< |
if (eq(o, elements[newlen])) { |
525 |
< |
setArray(newElements); |
526 |
< |
return true; |
514 |
> |
Object[] current = getArray(); |
515 |
> |
int len = current.length; |
516 |
> |
if (snapshot != current) findIndex: { |
517 |
> |
int prefix = Math.min(index, len); |
518 |
> |
for (int i = 0; i < prefix; i++) { |
519 |
> |
if (current[i] != snapshot[i] && eq(o, current[i])) { |
520 |
> |
index = i; |
521 |
> |
break findIndex; |
522 |
> |
} |
523 |
|
} |
524 |
+ |
if (index >= len) |
525 |
+ |
return false; |
526 |
+ |
if (current[index] == o) |
527 |
+ |
break findIndex; |
528 |
+ |
index = indexOf(o, current, index, len); |
529 |
+ |
if (index < 0) |
530 |
+ |
return false; |
531 |
|
} |
532 |
< |
return false; |
532 |
> |
Object[] newElements = new Object[len - 1]; |
533 |
> |
System.arraycopy(current, 0, newElements, 0, index); |
534 |
> |
System.arraycopy(current, index + 1, |
535 |
> |
newElements, index, |
536 |
> |
len - index - 1); |
537 |
> |
setArray(newElements); |
538 |
> |
return true; |
539 |
|
} finally { |
540 |
|
lock.unlock(); |
541 |
|
} |
585 |
|
* @return {@code true} if the element was added |
586 |
|
*/ |
587 |
|
public boolean addIfAbsent(E e) { |
588 |
+ |
Object[] snapshot = getArray(); |
589 |
+ |
return indexOf(e, snapshot, 0, snapshot.length) >= 0 ? false : |
590 |
+ |
addIfAbsent(e, snapshot); |
591 |
+ |
} |
592 |
+ |
|
593 |
+ |
/** |
594 |
+ |
* A version of addIfAbsent using the strong hint that given |
595 |
+ |
* recent snapshot does not contain e. |
596 |
+ |
*/ |
597 |
+ |
private boolean addIfAbsent(E e, Object[] snapshot) { |
598 |
|
final ReentrantLock lock = this.lock; |
599 |
|
lock.lock(); |
600 |
|
try { |
601 |
< |
Object[] elements = getArray(); |
602 |
< |
int len = elements.length; |
603 |
< |
for (int i = 0; i < len; ++i) { |
604 |
< |
if (eq(e, elements[i])) |
605 |
< |
return false; |
601 |
> |
Object[] current = getArray(); |
602 |
> |
int len = current.length; |
603 |
> |
if (snapshot != current) { |
604 |
> |
// Optimize for lost race to another addXXX operation |
605 |
> |
int common = Math.min(snapshot.length, len); |
606 |
> |
for (int i = 0; i < common; i++) |
607 |
> |
if (current[i] != snapshot[i] && eq(e, current[i])) |
608 |
> |
return false; |
609 |
> |
if (indexOf(e, current, common, len) >= 0) |
610 |
> |
return false; |
611 |
|
} |
612 |
< |
Object[] newElements = Arrays.copyOf(elements, len + 1); |
612 |
> |
Object[] newElements = Arrays.copyOf(current, len + 1); |
613 |
|
newElements[len] = e; |
614 |
|
setArray(newElements); |
615 |
|
return true; |