mirror of
https://github.com/OpenHFT/Chronicle-Map.git
synced 2021-09-13 01:26:12 +00:00
137 lines
3.8 KiB
Java
137 lines
3.8 KiB
Java
/*
|
|
* 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 <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
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<K, V, E> implements Iterator<E>, Consumer<MapEntry<K, V>> {
|
|
|
|
final AbstractChronicleMap<K, V> map;
|
|
private final Thread ownerThread = Thread.currentThread();
|
|
private final Queue<E> entryBuffer = new ArrayDeque<>();
|
|
private int segmentIndex;
|
|
E returned;
|
|
|
|
ChronicleMapIterator(AbstractChronicleMap<K, V> 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<K, V, ?> c = map.segmentContext(segmentIndex)) {
|
|
segmentIndex--;
|
|
if (c.size() == 0)
|
|
continue;
|
|
c.forEachSegmentEntry(this);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void accept(MapEntry<K, V> e) {
|
|
entryBuffer.add(read(e));
|
|
}
|
|
|
|
abstract E read(MapEntry<K, V> 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<K, V> extends ChronicleMapIterator<K, V, Entry<K, V>> {
|
|
|
|
OfEntries(AbstractChronicleMap<K, V> map) {
|
|
super(map);
|
|
}
|
|
|
|
@Override
|
|
Entry<K, V> read(MapEntry<K, V> 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<K, V> extends ChronicleMapIterator<K, V, K> {
|
|
|
|
OfKeys(AbstractChronicleMap<K, V> map) {
|
|
super(map);
|
|
}
|
|
|
|
@Override
|
|
K read(MapEntry<K, V> entry) {
|
|
return entry.key().getUsing(null);
|
|
}
|
|
|
|
@Override
|
|
void removeReturned() {
|
|
map.remove(returned);
|
|
}
|
|
}
|
|
}
|