/**
* Copyright (C) 2014-2016 LinkedIn Corp. (pinot-core@linkedin.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.linkedin.pinot.core.util.debug;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.roaringbitmap.IntIterator;
import org.roaringbitmap.buffer.ImmutableRoaringBitmap;
/**
* Debug class to display docId ranges ([1;5], 7 instead of {1,2,3,4,5,7}), for example
* <pre><code>System.out.println(DocIdGatherer.from(docIdList))</code></pre>. Assumes that the doc ids are in ascending
* order.
*/
public class DocIdGatherer {
private class DocIdRange {
private int _start;
private int _end;
public DocIdRange(int docId) {
_start = docId;
_end = docId;
}
public DocIdRange(int start, int end) {
_start = start;
_end = end;
}
public boolean isContainedOrAdjacent(int value) {
return _start - 1 <= value && value <= _end + 1;
}
public void updateWithDocId(int value) {
if (!isContainedOrAdjacent(value)) {
throw new IllegalArgumentException("Value " + value + " not contained or adjacent to range " + this.toString());
}
_start = Math.min(_start, value);
_end = Math.max(_end, value);
}
@Override
public String toString() {
if (_start != _end) {
return "[" + _start + ";" + _end + "]";
} else {
return Integer.toString(_start);
}
}
}
private List<DocIdRange> _docIdRangeList = new ArrayList<>();
public void addDocId(int docId) {
if (_docIdRangeList.isEmpty()) {
_docIdRangeList.add(new DocIdRange(docId));
} else {
DocIdRange lastRange = _docIdRangeList.get(_docIdRangeList.size() - 1);
if (lastRange.isContainedOrAdjacent(docId)) {
lastRange.updateWithDocId(docId);
} else {
_docIdRangeList.add(new DocIdRange(docId));
}
}
}
@Override
public String toString() {
return Arrays.toString(_docIdRangeList.toArray());
}
public static DocIdGatherer from(ImmutableRoaringBitmap roaringBitmap) {
DocIdGatherer gatherer = new DocIdGatherer();
IntIterator intIterator = roaringBitmap.getIntIterator();
while(intIterator.hasNext()) {
gatherer.addDocId(intIterator.next());
}
return gatherer;
}
public static DocIdGatherer from(List<Integer> listOfInts) {
DocIdGatherer gatherer = new DocIdGatherer();
for (Integer anInt : listOfInts) {
gatherer.addDocId(anInt);
}
return gatherer;
}
public static DocIdGatherer from(int[] ints) {
DocIdGatherer gatherer = new DocIdGatherer();
for (int anInt : ints) {
gatherer.addDocId(anInt);
}
return gatherer;
}
}