package org.khelekore.prtree; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; /** A node getter that multiplexes min and max values * @param <N> the type of the node */ class MinMaxNodeGetter<T, N> implements NodeGetter<N> { private final List<NodeUsage<T>> min; private final List<NodeUsage<T>> max; private final NodeFactory<N> factory; private final TakeCounter takeCounter; private final int id; private int minPos = 0; private int maxPos = 0; private int takenNodes = 0; public MinMaxNodeGetter (List<NodeUsage<T>> data, NodeFactory<N> factory, Comparator<T> minSorter, Comparator<T> maxSorter, TakeCounter takeCounter, int id) { min = new ArrayList<NodeUsage<T>> (data); Collections.sort (min, new NodeUsageSorter<T> (minSorter)); max = new ArrayList<NodeUsage<T>> (data); Collections.sort (max, new NodeUsageSorter<T> (maxSorter)); this.factory = factory; this.takeCounter = takeCounter; this.id = id; } private MinMaxNodeGetter (List<NodeUsage<T>> min, List<NodeUsage<T>> max, NodeFactory<N> factory, TakeCounter takeCounter, int id, int minPos, int maxPos) { this.min = min; this.max = max; this.factory = factory; this.takeCounter = takeCounter; this.id = id; this.minPos = minPos; this.maxPos = maxPos; } public MinMaxNodeGetter<T, N> getCopyFor (int newId, int size, TakeCounter takeCounter) { return new MinMaxNodeGetter<T, N> (min, max, factory, takeCounter, newId, minPos, maxPos); } public int getSize () { return takeCounter.getSize (); } public TakeCounter getTakeCounter () { return takeCounter; } private boolean isUsedNode (List<NodeUsage<T>> ls, int pos) { NodeUsage<T> nu = ls.get (pos); return nu == null || nu.isUsed () || nu.getUser () != id; } private int findNextFree (List<NodeUsage<T>> ls, int pos) { int s = ls.size (); while (pos < s && isUsedNode (ls, pos)) pos++; return pos; } private T getFirstUnusedMin () { takeCounter.take (); minPos = findNextFree (min, minPos); NodeUsage<T> nu = min.set (minPos++, null); nu.use (); return nu.getData (); } private T getFirstUnusedMax () { takeCounter.take (); maxPos = findNextFree (max, maxPos); NodeUsage<T> nu = max.set (maxPos++, null); nu.use (); return nu.getData (); } public N getNextNode (int maxObjects) { int num = Math.min (takeCounter.getNumLeft (), maxObjects); Object[] data = new Object[num]; for (int i = 0; i < num; i++) data[i] = takenNodes == 0 ? getFirstUnusedMin () : getFirstUnusedMax (); takenNodes++; return factory.create (data); } public boolean hasMoreNodes () { return takenNodes < 2 && hasMoreData (); } public boolean hasMoreData () { return takeCounter.canTakeMore (); } public List<MinMaxNodeGetter<T, N>> split (int lowId, int highId) { int e = takeCounter.getNumLeft (); int lowSize = (e + 1) / 2; int highSize = e - lowSize; // Store start pos, but only min that changes int minPosSave = minPos; // mark half the elements for lowId for (int i = 0; i < lowSize; i++) markForId (lowId); TakeCounter tcLow = new TakeCounter (lowSize); MinMaxNodeGetter<T, N> lowPart = new MinMaxNodeGetter<T, N> (min, max, factory, tcLow, lowId, minPosSave, maxPos); minPosSave = minPos; // mark the rest for (int i = 0; i < highSize; i++) markForId (highId); TakeCounter tcHigh = new TakeCounter (highSize); MinMaxNodeGetter<T, N> highPart = new MinMaxNodeGetter<T, N> (min, max, factory, tcHigh, highId, minPosSave, maxPos); List<MinMaxNodeGetter<T, N>> ret = new ArrayList<MinMaxNodeGetter<T, N>> (2); ret.add (lowPart); ret.add (highPart); return ret; } private void markForId (int id) { takeCounter.take (); minPos = findNextFree (min, minPos); NodeUsage<T> nu = min.get (minPos++); nu.setUser (id); } }