/*
* Copyright (C) 2015 higherfrequencytrading.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
package net.openhft.chronicle.map;
import java.util.ArrayDeque;
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.NoSuchElementException;
import java.util.Queue;
import java.util.function.Consumer;
/**
* Very inefficient (esp. if segments are large), but CORRECT implementation
*/
abstract class ChronicleMapIterator implements Iterator, Consumer> {
final AbstractChronicleMap map;
private final Thread ownerThread = Thread.currentThread();
private final Queue entryBuffer = new ArrayDeque<>();
private int segmentIndex;
E returned;
ChronicleMapIterator(AbstractChronicleMap map) {
this.map = map;
segmentIndex = map.segments() - 1;
}
private void checkSingleThreaded() {
if (ownerThread != Thread.currentThread()) {
throw new IllegalStateException(
"Iterator should be accessed only from a single thread");
}
}
private void fillEntryBuffer() {
if (!entryBuffer.isEmpty())
return;
while (true) {
if (segmentIndex < 0)
return;
try (MapSegmentContext c = map.segmentContext(segmentIndex)) {
segmentIndex--;
if (c.size() == 0)
continue;
c.forEachSegmentEntry(this);
return;
}
}
}
@Override
public void accept(MapEntry e) {
entryBuffer.add(read(e));
}
abstract E read(MapEntry entry);
@Override
public boolean hasNext() {
checkSingleThreaded();
fillEntryBuffer();
return !entryBuffer.isEmpty();
}
@Override
public E next() {
checkSingleThreaded();
fillEntryBuffer();
E e;
if ((e = entryBuffer.poll()) == null)
throw new NoSuchElementException();
return returned = e;
}
@Override
public void remove() {
checkSingleThreaded();
if (returned == null)
throw new IllegalStateException();
removeReturned();
returned = null;
}
abstract void removeReturned();
static class OfEntries extends ChronicleMapIterator> {
OfEntries(AbstractChronicleMap map) {
super(map);
}
@Override
Entry read(MapEntry entry) {
K key = entry.key().getUsing(null);
V value = entry.value().getUsing(null);
return new WriteThroughEntry<>(map, key, value);
}
@Override
void removeReturned() {
map.remove(returned.getKey(), returned.getValue());
}
}
static class OfKeys extends ChronicleMapIterator {
OfKeys(AbstractChronicleMap map) {
super(map);
}
@Override
K read(MapEntry entry) {
return entry.key().getUsing(null);
}
@Override
void removeReturned() {
map.remove(returned);
}
}
}