| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You 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 org.apache.lucene.queries.intervals; |
| |
| import java.io.IOException; |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.List; |
| import java.util.Objects; |
| import java.util.stream.Collectors; |
| |
| class BlockIntervalsSource extends ConjunctionIntervalsSource { |
| |
| static IntervalsSource build(List<IntervalsSource> subSources) { |
| if (subSources.size() == 1) { |
| return subSources.get(0); |
| } |
| return Intervals.or(Disjunctions.pullUp(subSources, BlockIntervalsSource::new)); |
| } |
| |
| private static List<IntervalsSource> flatten(List<IntervalsSource> sources) { |
| List<IntervalsSource> flattened = new ArrayList<>(); |
| for (IntervalsSource s : sources) { |
| if (s instanceof BlockIntervalsSource) { |
| flattened.addAll(((BlockIntervalsSource)s).subSources); |
| } |
| else { |
| flattened.add(s); |
| } |
| } |
| return flattened; |
| } |
| |
| private BlockIntervalsSource(List<IntervalsSource> sources) { |
| super(flatten(sources), true); |
| } |
| |
| @Override |
| protected IntervalIterator combine(List<IntervalIterator> iterators) { |
| return new BlockIntervalIterator(iterators); |
| } |
| |
| @Override |
| public int minExtent() { |
| int minExtent = 0; |
| for (IntervalsSource subSource : subSources) { |
| minExtent += subSource.minExtent(); |
| } |
| return minExtent; |
| } |
| |
| @Override |
| public Collection<IntervalsSource> pullUpDisjunctions() { |
| return Collections.singletonList(this); // Disjunctions already pulled up in build() |
| } |
| |
| @Override |
| public int hashCode() { |
| return Objects.hash(subSources); |
| } |
| |
| @Override |
| public boolean equals(Object other) { |
| if (other instanceof BlockIntervalsSource == false) return false; |
| BlockIntervalsSource b = (BlockIntervalsSource) other; |
| return Objects.equals(this.subSources, b.subSources); |
| } |
| |
| @Override |
| public String toString() { |
| return "BLOCK(" + subSources.stream().map(IntervalsSource::toString).collect(Collectors.joining(",")) + ")"; |
| } |
| |
| private static class BlockIntervalIterator extends ConjunctionIntervalIterator { |
| |
| int start = -1, end = -1; |
| |
| BlockIntervalIterator(List<IntervalIterator> subIterators) { |
| super(subIterators); |
| } |
| |
| @Override |
| public int start() { |
| return start; |
| } |
| |
| @Override |
| public int end() { |
| return end; |
| } |
| |
| @Override |
| public int gaps() { |
| return 0; |
| } |
| |
| @Override |
| public int nextInterval() throws IOException { |
| if (subIterators.get(0).nextInterval() == IntervalIterator.NO_MORE_INTERVALS) |
| return start = end = IntervalIterator.NO_MORE_INTERVALS; |
| int i = 1; |
| while (i < subIterators.size()) { |
| while (subIterators.get(i).start() <= subIterators.get(i - 1).end()) { |
| if (subIterators.get(i).nextInterval() == IntervalIterator.NO_MORE_INTERVALS) |
| return start = end = IntervalIterator.NO_MORE_INTERVALS; |
| } |
| if (subIterators.get(i).start() == subIterators.get(i - 1).end() + 1) { |
| i = i + 1; |
| } |
| else { |
| if (subIterators.get(0).nextInterval() == IntervalIterator.NO_MORE_INTERVALS) |
| return start = end = IntervalIterator.NO_MORE_INTERVALS; |
| i = 1; |
| } |
| } |
| start = subIterators.get(0).start(); |
| end = subIterators.get(subIterators.size() - 1).end(); |
| return start; |
| } |
| |
| @Override |
| protected void reset() { |
| start = end = -1; |
| } |
| } |
| } |