// synchronized
sclass SeenAndQueue implements Iterable {
Set seen = syncSet();
L queue = syncLinkedList();
Int max; // stop after this many elements if not null
transient L onAddedToQueue = syncList(); // L
transient L onQueueEmpty = syncList();
// queue handler
transient ReliableSingleThread rst;
*() {}
*(Runnable handler) { rst(handler); }
bool add(A a) {
if (a == null || maxReached() || !seen.add(a)) false;
queue.add(a);
pcallFAll(onAddedToQueue, a);
true;
}
void addAll(Iterable l) { fOr (A a : l) add(a); }
A popQueue() {
ping();
synchronized(queue) {
A a = syncPopFirst(queue);
if (a != null && empty(queue))
pcallFAll(onQueueEmpty);
ret a;
}
}
// ends when queue is empty
ItIt queueIterator() {
ret iteratorFromFunction_if0(() -> popQueue());
}
public ItIt iterator() { ret queueIterator(); }
void onAddedToQueue(O r) { onAddedToQueue.add(r); }
ReliableSingleThread rst(Runnable handler) {
if (rst != null) fail("rst already set");
rst = ReliableSingleThread(handler);
onAddedToQueue.add(rst);
ret rst;
}
void cleanMeUp {
cleanUp(rst);
rst = null;
}
bool queueEmpty() { ret queue.isEmpty(); }
bool idle() { ret queueEmpty() && !rstRunning(rst); }
S stats() { ret l(seen) + " seen, " + l(queue) + " queued"
+ (max == null ? "" : ", max: " + max); }
bool maxReached() { ret max != null && l(seen) + l(queue) >= max; }
Set asSet() { ret seen; }
}