package com.ldbc.driver.generator; import java.util.ArrayList; import java.util.Comparator; import java.util.Iterator; import java.util.List; public class OrderedMultiGenerator<GENERATE_TYPE> extends Generator<GENERATE_TYPE> { private final List<GeneratorHead<GENERATE_TYPE>> generatorHeads; private final Comparator<GENERATE_TYPE> comparator; public OrderedMultiGenerator(Comparator<GENERATE_TYPE> comparator, int lookAheadDistance, Iterator<GENERATE_TYPE>... generators) { this.comparator = comparator; if (1 == lookAheadDistance) { this.generatorHeads = buildSimpleGeneratorHeads(generators); } else { this.generatorHeads = buildLookAheadGeneratorHeads(comparator, lookAheadDistance, generators); } } private static <T1> List<GeneratorHead<T1>> buildSimpleGeneratorHeads(Iterator<T1>... generators) { List<GeneratorHead<T1>> heads = new ArrayList<>(); for (Iterator<T1> generator : generators) { heads.add(new SimpleGeneratorHead<>(generator)); } return heads; } private static <T1> List<GeneratorHead<T1>> buildLookAheadGeneratorHeads(Comparator<T1> comparator, int distance, Iterator<T1>... generators) { List<GeneratorHead<T1>> heads = new ArrayList<>(); for (Iterator<T1> generator : generators) { heads.add(new LookaheadGeneratorHead<>(generator, comparator, distance)); } return heads; } @Override protected GENERATE_TYPE doNext() throws GeneratorException { GeneratorHead<GENERATE_TYPE> minGeneratorHead = getMinGeneratorHead(); return (null == minGeneratorHead) ? null : minGeneratorHead.removeHead(); } private GeneratorHead<GENERATE_TYPE> getMinGeneratorHead() { GeneratorHead<GENERATE_TYPE> minGeneratorHead = null; // Get generator head with lowest head element (removing empty ones encountered first) for (int i = 0; i < generatorHeads.size(); i++) { GeneratorHead<GENERATE_TYPE> generatorHead = generatorHeads.get(i); if (null == generatorHead) continue; if (null == generatorHead.inspectHead()) { generatorHeads.set(i, null); continue; } if (null == minGeneratorHead || comparator.compare(generatorHead.inspectHead(), minGeneratorHead.inspectHead()) < 0) { minGeneratorHead = generatorHead; } } return minGeneratorHead; } private static interface GeneratorHead<T1> { public T1 removeHead(); public T1 inspectHead(); } private static class SimpleGeneratorHead<T1> implements GeneratorHead<T1> { private final Iterator<T1> generator; private T1 head; public SimpleGeneratorHead(Iterator<T1> generator) { this.generator = generator; this.head = (this.generator.hasNext()) ? this.generator.next() : null; } @Override public T1 removeHead() { T1 oldHead = head; head = (generator.hasNext()) ? generator.next() : null; return oldHead; } @Override public T1 inspectHead() { return head; } } private static class LookaheadGeneratorHead<T1> implements GeneratorHead<T1> { private final Iterator<T1> generator; private final Comparator<T1> comparator; private final int lookaheadDistance; private List<T1> lookaheadBuffer; private T1 head; public LookaheadGeneratorHead(Iterator<T1> generator, Comparator<T1> comparator, int lookaheadDistance) { this.generator = generator; this.comparator = comparator; this.lookaheadDistance = lookaheadDistance; this.lookaheadBuffer = new ArrayList<>(); fillLookaheadBuffer(); this.head = getMinFromLookaheadBuffer(); } @Override public T1 removeHead() { T1 oldHead = head; fillLookaheadBuffer(); head = getMinFromLookaheadBuffer(); return oldHead; } @Override public T1 inspectHead() { return head; } private T1 getMinFromLookaheadBuffer() { Iterator<T1> lookaheadBufferIterator = lookaheadBuffer.iterator(); if (false == lookaheadBufferIterator.hasNext()) { return null; } int index = 0; int minIndex = index; T1 min = lookaheadBufferIterator.next(); while (lookaheadBufferIterator.hasNext()) { index++; T1 next = lookaheadBufferIterator.next(); if (comparator.compare(next, min) < 0) { minIndex = index; min = next; } } lookaheadBuffer.remove(minIndex); return min; } private void fillLookaheadBuffer() { while (generator.hasNext()) { if (lookaheadBuffer.size() >= lookaheadDistance) break; lookaheadBuffer.add(generator.next()); } } } }