/* * The MIT License * * Copyright (c) 2015-2016 The Broad Institute * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package picard.vcf; import htsjdk.samtools.SAMSequenceDictionary; import htsjdk.samtools.util.PeekableIterator; import htsjdk.variant.variantcontext.VariantContext; import htsjdk.variant.variantcontext.VariantContextComparator; import java.util.Iterator; import java.util.Optional; /** * An iterator that takes a pair of iterators over VariantContexts and iterates over them in tandem. * * A tuple will be returned with variant contexts for both contexts if present. Otherwise, the missing * context at that site will be empty. The contexts will be returned in coordinate order. * * */ public class PairedVariantSubContextIterator implements Iterator<PairedVariantSubContextIterator.VcfTuple> { private final PeekableIterator<VariantContext> leftIterator; private final String leftSample; private final PeekableIterator<VariantContext> rightIterator; private final String rightSample; private final VariantContextComparator comparator; public PairedVariantSubContextIterator(final Iterator<VariantContext> leftIterator, final String leftSample, final Iterator<VariantContext> rightIterator, final String rightSample, final SAMSequenceDictionary dict) { this.leftIterator = new PeekableIterator<>(leftIterator); this.leftSample = leftSample; this.rightIterator = new PeekableIterator<>(rightIterator); this.rightSample = rightSample; this.comparator = new VariantContextComparator(dict); } @Override public boolean hasNext() { return this.leftIterator.hasNext() || this.rightIterator.hasNext(); } @Override public VcfTuple next() { if (!hasNext()) throw new IllegalStateException("next() called while hasNext() is false."); final Optional<VariantContext> leftVariantContext = this.leftIterator.hasNext() ? Optional.of(this.leftIterator.peek()) : Optional.empty(); final Optional<VariantContext> rightVariantContext = this.rightIterator.hasNext() ? Optional.of(this.rightIterator.peek()) : Optional.empty(); // If one or the other is missing because there is no next, just return a one-sided tuple if (!leftVariantContext.isPresent() && !rightVariantContext.isPresent()) { throw new IllegalStateException("BUG: Both contexts empty."); } else if (!leftVariantContext.isPresent()) { return new VcfTuple(Optional.empty(), this.rightIterator.next().subContextFromSample(rightSample)); } else if (!rightVariantContext.isPresent()) { return new VcfTuple(this.leftIterator.next().subContextFromSample(leftSample), Optional.empty()); } else { // Otherwise check the ordering and do the right thing final int ordering = this.comparator.compare(leftVariantContext.get(), rightVariantContext.get()); if (ordering == 0) { return new VcfTuple(this.leftIterator.next().subContextFromSample(leftSample), this.rightIterator.next().subContextFromSample(rightSample)); } else if (ordering < 0) { return new VcfTuple(this.leftIterator.next().subContextFromSample(leftSample), Optional.empty()); } else { return new VcfTuple(Optional.empty(), this.rightIterator.next().subContextFromSample(rightSample)); } } } @Override public void remove() { throw new UnsupportedOperationException(); } /** Little class to hold a pair of VariantContexts that are in sync with one another. */ public static class VcfTuple { public final Optional<VariantContext> leftVariantContext; public final Optional<VariantContext> rightVariantContext; private VcfTuple(final Optional<VariantContext> leftVariantContext, final Optional<VariantContext> rightVariantContext) { this.leftVariantContext = leftVariantContext; this.rightVariantContext = rightVariantContext; } VcfTuple(final VariantContext leftVariantContext, final VariantContext rightVariantContext) { this(Optional.of(leftVariantContext), Optional.of(rightVariantContext)); } VcfTuple(final Optional<VariantContext> leftVariantContext, final VariantContext rightVariantContext) { this(leftVariantContext, Optional.of(rightVariantContext)); } VcfTuple(final VariantContext leftVariantContext, final Optional<VariantContext> rightVariantContext) { this(Optional.of(leftVariantContext), rightVariantContext); } } }