tikhomirov@520: /* tikhomirov@520: * Copyright (c) 2012 TMate Software Ltd tikhomirov@520: * tikhomirov@520: * This program is free software; you can redistribute it and/or modify tikhomirov@520: * it under the terms of the GNU General Public License as published by tikhomirov@520: * the Free Software Foundation; version 2 of the License. tikhomirov@520: * tikhomirov@520: * This program is distributed in the hope that it will be useful, tikhomirov@520: * but WITHOUT ANY WARRANTY; without even the implied warranty of tikhomirov@520: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the tikhomirov@520: * GNU General Public License for more details. tikhomirov@520: * tikhomirov@520: * For information on how to redistribute this software under tikhomirov@520: * the terms of a license other than GNU General Public License tikhomirov@520: * contact TMate Software at support@hg4j.com tikhomirov@520: */ tikhomirov@520: package org.tmatesoft.hg.internal; tikhomirov@520: tikhomirov@520: import java.util.Arrays; tikhomirov@520: import java.util.NoSuchElementException; tikhomirov@520: tikhomirov@520: /** tikhomirov@520: * Helper to break given range [start..end] (inclusive bounds) to series of ranges, tikhomirov@520: * all but last are of batchSize length, and the last one is at most of batchSize+batchSizeTolerance length. tikhomirov@520: * tikhomirov@520: * Range is [{@link #start()rangeStart}..{@link #end() rangeEnd}], where rangeStart is less or equal to rangeEnd. tikhomirov@520: * tikhomirov@520: * When reverse range iteration is requested, original range is iterated from end to start, but the subranges tikhomirov@520: * boundaries are in natural order. i.e. for 0..100, 10 first subrange would be [91..100], not [100..91]. This tikhomirov@520: * helps clients of this class to get [start()..end()] in natural order regardless of iteration direction. tikhomirov@520: * tikhomirov@520: * Note, this class (and its treatment of inclusive boundaries) is designed solely for use with methods that navigate tikhomirov@520: * revlogs and take (start,end) pair of inclusive range. tikhomirov@520: * tikhomirov@520: * @author Artem Tikhomirov tikhomirov@520: * @author TMate Software Ltd. tikhomirov@520: */ tikhomirov@520: public class BatchRangeHelper { tikhomirov@520: tikhomirov@520: private final int rangeCount; tikhomirov@520: private final int rangeDelta; tikhomirov@520: private final int nextValueDelta; tikhomirov@520: private final int firstBoundary, lastBoundary; tikhomirov@520: private int rangeIndex, rangeValue, rangeStart, rangeEnd; tikhomirov@520: tikhomirov@520: public BatchRangeHelper(int start, int end, int batchSize, boolean reverse) { tikhomirov@520: this(start, end, batchSize, batchSize/5, reverse); tikhomirov@520: } tikhomirov@520: tikhomirov@520: public BatchRangeHelper(int start, int end, int batchSize, int batchSizeTolerance, boolean reverse) { tikhomirov@520: assert end >= start; tikhomirov@520: assert start >= 0; tikhomirov@520: assert batchSize > 0; tikhomirov@520: assert batchSizeTolerance >= 0; tikhomirov@520: final int totalElements = end-start+1; tikhomirov@520: int batchRangeCount = totalElements / batchSize; tikhomirov@520: // batchRangeCount == 0, totalElements > 0 => need at least 1 range tikhomirov@520: if (batchRangeCount == 0 || batchRangeCount*batchSize+batchSizeTolerance < totalElements) { tikhomirov@520: batchRangeCount++; tikhomirov@520: } tikhomirov@520: rangeCount = batchRangeCount; tikhomirov@520: rangeDelta = batchSize-1; // ranges are inclusive, and always grow naturally. tikhomirov@520: nextValueDelta = reverse ? -batchSize : batchSize; tikhomirov@520: firstBoundary = reverse ? end-rangeDelta : start; tikhomirov@520: lastBoundary = reverse ? start : end; tikhomirov@520: reset(); tikhomirov@520: } tikhomirov@520: tikhomirov@520: public boolean hasNext() { tikhomirov@520: return rangeIndex < rangeCount; tikhomirov@520: } tikhomirov@520: tikhomirov@520: public void next() { tikhomirov@520: if (!hasNext()) { tikhomirov@520: throw new NoSuchElementException(); tikhomirov@520: } tikhomirov@520: rangeStart = rangeValue; tikhomirov@520: rangeEnd = rangeValue + rangeDelta; tikhomirov@520: rangeValue += nextValueDelta; tikhomirov@520: if (++rangeIndex >= rangeCount) { tikhomirov@520: if (nextValueDelta < 0) { tikhomirov@520: // reverse iteration, lastBoundary represents start tikhomirov@520: rangeStart = lastBoundary; tikhomirov@520: } else { tikhomirov@520: // lastBoundary represents end tikhomirov@520: rangeEnd = lastBoundary; tikhomirov@520: } tikhomirov@520: } tikhomirov@520: } tikhomirov@520: tikhomirov@520: public int start() { tikhomirov@520: return rangeStart; tikhomirov@520: } tikhomirov@520: tikhomirov@520: public int end() { tikhomirov@520: return rangeEnd; tikhomirov@520: } tikhomirov@520: tikhomirov@520: public BatchRangeHelper reset() { tikhomirov@520: rangeValue = firstBoundary; tikhomirov@520: rangeIndex = 0; tikhomirov@520: return this; tikhomirov@520: } tikhomirov@520: tikhomirov@520: public int[] toArray() { tikhomirov@520: int[] rv = new int[rangeCount*2]; tikhomirov@520: reset(); tikhomirov@520: int i = 0; tikhomirov@520: while (hasNext()) { tikhomirov@520: next(); tikhomirov@520: rv[i++] = start(); tikhomirov@520: rv[i++] = end(); tikhomirov@520: } tikhomirov@520: reset(); tikhomirov@520: return rv; tikhomirov@520: } tikhomirov@520: tikhomirov@520: public static void main(String[] args) { tikhomirov@520: System.out.println("With remainder within tolerance"); tikhomirov@520: System.out.println(Arrays.toString(new BatchRangeHelper(0, 102, 10, 4, false).toArray())); tikhomirov@520: System.out.println(Arrays.toString(new BatchRangeHelper(0, 102, 10, 4, true).toArray())); tikhomirov@520: System.out.println("With remainder out of tolerance"); tikhomirov@520: System.out.println(Arrays.toString(new BatchRangeHelper(0, 102, 10, 2, false).toArray())); tikhomirov@520: System.out.println(Arrays.toString(new BatchRangeHelper(0, 102, 10, 2, true).toArray())); tikhomirov@520: System.out.println("Range smaller than batch"); tikhomirov@520: System.out.println(Arrays.toString(new BatchRangeHelper(1, 9, 10, false).toArray())); tikhomirov@520: System.out.println(Arrays.toString(new BatchRangeHelper(1, 9, 10, true).toArray())); tikhomirov@520: System.out.println("Range smaller than batch and smaller than tolerance"); tikhomirov@520: System.out.println(Arrays.toString(new BatchRangeHelper(1, 9, 10, 20, false).toArray())); tikhomirov@520: System.out.println(Arrays.toString(new BatchRangeHelper(1, 9, 10, 20, true).toArray())); tikhomirov@520: System.out.println("Zero tolerance"); tikhomirov@520: System.out.println(Arrays.toString(new BatchRangeHelper(0, 100, 10, 0, false).toArray())); tikhomirov@520: System.out.println(Arrays.toString(new BatchRangeHelper(0, 100, 10, 0, true).toArray())); tikhomirov@520: System.out.println("Right to boundary"); tikhomirov@520: System.out.println(Arrays.toString(new BatchRangeHelper(1, 100, 10, false).toArray())); tikhomirov@520: System.out.println(Arrays.toString(new BatchRangeHelper(1, 100, 10, true).toArray())); tikhomirov@520: } tikhomirov@520: }