1033 |
|
abstract Node<E> firstNode(); |
1034 |
|
abstract Node<E> nextNode(Node<E> n); |
1035 |
|
|
1036 |
+ |
private Node<E> succ(Node<E> p) { |
1037 |
+ |
return (p == (p = nextNode(p))) ? firstNode() : p; |
1038 |
+ |
} |
1039 |
+ |
|
1040 |
|
AbstractItr() { |
1041 |
|
// set to initial position |
1042 |
|
final ReentrantLock lock = LinkedBlockingDeque.this.lock; |
1043 |
|
lock.lock(); |
1044 |
|
try { |
1045 |
< |
next = firstNode(); |
1046 |
< |
nextItem = (next == null) ? null : next.item; |
1045 |
> |
if ((next = firstNode()) != null) |
1046 |
> |
nextItem = next.item; |
1047 |
|
} finally { |
1048 |
|
// checkInvariants(); |
1049 |
|
lock.unlock(); |
1051 |
|
} |
1052 |
|
|
1053 |
|
/** |
1050 |
– |
* Returns the successor node of the given non-null, but |
1051 |
– |
* possibly previously deleted, node. |
1052 |
– |
*/ |
1053 |
– |
private Node<E> succ(Node<E> n) { |
1054 |
– |
// Chains of deleted nodes ending in null or self-links |
1055 |
– |
// are possible if multiple interior nodes are removed. |
1056 |
– |
for (;;) { |
1057 |
– |
Node<E> s = nextNode(n); |
1058 |
– |
if (s == null) |
1059 |
– |
return null; |
1060 |
– |
else if (s.item != null) |
1061 |
– |
return s; |
1062 |
– |
else if (s == n) |
1063 |
– |
return firstNode(); |
1064 |
– |
else |
1065 |
– |
n = s; |
1066 |
– |
} |
1067 |
– |
} |
1068 |
– |
|
1069 |
– |
/** |
1054 |
|
* Advances next. |
1055 |
|
*/ |
1056 |
|
void advance() { |
1057 |
+ |
// assert next != null; |
1058 |
|
final ReentrantLock lock = LinkedBlockingDeque.this.lock; |
1059 |
|
lock.lock(); |
1060 |
|
try { |
1061 |
< |
// assert next != null; |
1062 |
< |
next = succ(next); |
1063 |
< |
nextItem = (next == null) ? null : next.item; |
1061 |
> |
// Chains of deleted nodes ending in null or self-links |
1062 |
> |
// are possible if multiple interior nodes are removed. |
1063 |
> |
for (next = nextNode(next);; next = succ(next)) { |
1064 |
> |
if (next == null) { |
1065 |
> |
nextItem = null; |
1066 |
> |
break; |
1067 |
> |
} else if ((nextItem = next.item) != null) |
1068 |
> |
break; |
1069 |
> |
} |
1070 |
|
} finally { |
1071 |
|
// checkInvariants(); |
1072 |
|
lock.unlock(); |
1115 |
|
Node<E> nextNode(Node<E> n) { return n.prev; } |
1116 |
|
} |
1117 |
|
|
1118 |
< |
/** A customized variant of Spliterators.IteratorSpliterator */ |
1118 |
> |
/** |
1119 |
> |
* A customized variant of Spliterators.IteratorSpliterator. |
1120 |
> |
* Keep this class in sync with (very similar) LBQSpliterator. |
1121 |
> |
*/ |
1122 |
|
private final class LBDSpliterator implements Spliterator<E> { |
1123 |
|
static final int MAX_BATCH = 1 << 25; // max batch array size; |
1124 |
|
Node<E> current; // current node; null until initialized |
1125 |
|
int batch; // batch size for splits |
1126 |
|
boolean exhausted; // true when no more nodes |
1127 |
< |
long est; // size estimate |
1127 |
> |
long est = size(); // size estimate |
1128 |
|
|
1129 |
< |
LBDSpliterator() { est = size(); } |
1129 |
> |
LBDSpliterator() {} |
1130 |
> |
|
1131 |
> |
private Node<E> succ(Node<E> p) { |
1132 |
> |
return (p == (p = p.next)) ? first : p; |
1133 |
> |
} |
1134 |
|
|
1135 |
|
public long estimateSize() { return est; } |
1136 |
|
|
1139 |
|
int b = batch; |
1140 |
|
int n = (b <= 0) ? 1 : (b >= MAX_BATCH) ? MAX_BATCH : b + 1; |
1141 |
|
if (!exhausted && |
1142 |
< |
(((h = current) != null && h != h.next) |
1145 |
< |
|| (h = first) != null) |
1142 |
> |
((h = current) != null || (h = first) != null) |
1143 |
|
&& h.next != null) { |
1144 |
|
Object[] a = new Object[n]; |
1145 |
|
final ReentrantLock lock = LinkedBlockingDeque.this.lock; |
1147 |
|
Node<E> p = current; |
1148 |
|
lock.lock(); |
1149 |
|
try { |
1150 |
< |
if (((p != null && p != p.next) || (p = first) != null) |
1151 |
< |
&& p.item != null) |
1152 |
< |
for (; p != null && i < n; p = p.next) |
1153 |
< |
a[i++] = p.item; |
1150 |
> |
if (p != null || (p = first) != null) |
1151 |
> |
for (; p != null && i < n; p = succ(p)) |
1152 |
> |
if ((a[i] = p.item) != null) |
1153 |
> |
i++; |
1154 |
|
} finally { |
1155 |
|
// checkInvariants(); |
1156 |
|
lock.unlock(); |
1174 |
|
|
1175 |
|
public void forEachRemaining(Consumer<? super E> action) { |
1176 |
|
if (action == null) throw new NullPointerException(); |
1177 |
< |
if (exhausted) |
1178 |
< |
return; |
1179 |
< |
exhausted = true; |
1180 |
< |
final ReentrantLock lock = LinkedBlockingDeque.this.lock; |
1181 |
< |
Node<E> p = current; |
1182 |
< |
current = null; |
1183 |
< |
do { |
1177 |
> |
if (!exhausted) { |
1178 |
> |
exhausted = true; |
1179 |
> |
final ReentrantLock lock = LinkedBlockingDeque.this.lock; |
1180 |
> |
Node<E> p = current; |
1181 |
> |
current = null; |
1182 |
> |
do { |
1183 |
> |
E e = null; |
1184 |
> |
lock.lock(); |
1185 |
> |
try { |
1186 |
> |
if (p != null || (p = first) != null) |
1187 |
> |
do { |
1188 |
> |
e = p.item; |
1189 |
> |
p = succ(p); |
1190 |
> |
} while (e == null && p != null); |
1191 |
> |
} finally { |
1192 |
> |
// checkInvariants(); |
1193 |
> |
lock.unlock(); |
1194 |
> |
} |
1195 |
> |
if (e != null) |
1196 |
> |
action.accept(e); |
1197 |
> |
} while (p != null); |
1198 |
> |
} |
1199 |
> |
} |
1200 |
> |
|
1201 |
> |
public boolean tryAdvance(Consumer<? super E> action) { |
1202 |
> |
if (action == null) throw new NullPointerException(); |
1203 |
> |
if (!exhausted) { |
1204 |
> |
final ReentrantLock lock = LinkedBlockingDeque.this.lock; |
1205 |
> |
Node<E> p = current; |
1206 |
|
E e = null; |
1207 |
|
lock.lock(); |
1208 |
|
try { |
1209 |
< |
if ((p != null && p != p.next) || (p = first) != null) { |
1210 |
< |
e = p.item; |
1211 |
< |
p = p.next; |
1212 |
< |
} |
1209 |
> |
if (p != null || (p = first) != null) |
1210 |
> |
do { |
1211 |
> |
e = p.item; |
1212 |
> |
p = succ(p); |
1213 |
> |
} while (e == null && p != null); |
1214 |
|
} finally { |
1215 |
|
// checkInvariants(); |
1216 |
|
lock.unlock(); |
1217 |
|
} |
1218 |
< |
if (e != null) |
1218 |
> |
exhausted = ((current = p) == null); |
1219 |
> |
if (e != null) { |
1220 |
|
action.accept(e); |
1221 |
< |
} while (p != null); |
1201 |
< |
} |
1202 |
< |
|
1203 |
< |
public boolean tryAdvance(Consumer<? super E> action) { |
1204 |
< |
if (action == null) throw new NullPointerException(); |
1205 |
< |
if (exhausted) |
1206 |
< |
return false; |
1207 |
< |
final ReentrantLock lock = LinkedBlockingDeque.this.lock; |
1208 |
< |
Node<E> p = current; |
1209 |
< |
E e = null; |
1210 |
< |
lock.lock(); |
1211 |
< |
try { |
1212 |
< |
if ((p != null && p != p.next) || (p = first) != null) { |
1213 |
< |
e = p.item; |
1214 |
< |
p = p.next; |
1221 |
> |
return true; |
1222 |
|
} |
1216 |
– |
} finally { |
1217 |
– |
// checkInvariants(); |
1218 |
– |
lock.unlock(); |
1223 |
|
} |
1224 |
< |
exhausted = ((current = p) == null); |
1221 |
< |
if (e == null) |
1222 |
< |
return false; |
1223 |
< |
action.accept(e); |
1224 |
< |
return true; |
1224 |
> |
return false; |
1225 |
|
} |
1226 |
|
|
1227 |
|
public int characteristics() { |