All Downloads are FREE. Search and download functionalities are using the official Maven repository.

inet.ipaddr.IPAddressSeqRange Maven / Gradle / Ivy

There is a newer version: 5.5.1
Show newest version
/*
 * Copyright 2018 Sean C Foley
 *
 * 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
 *     or at
 *     https://github.com/seancfoley/IPAddress/blob/master/LICENSE
 *
 * 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 inet.ipaddr;

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.IntFunction;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.function.ToLongFunction;
import java.util.function.UnaryOperator;
import java.util.stream.Stream;

import inet.ipaddr.AddressNetwork.AddressSegmentCreator;
import inet.ipaddr.IPAddressSection.IPAddressSeqRangeSpliterator;
import inet.ipaddr.IPAddressSection.IPAddressSeqRangePrefixSpliterator;
import inet.ipaddr.IPAddressSection.SegFunction;
import inet.ipaddr.IPAddressSection.SeqRangeIteratorProvider;
import inet.ipaddr.format.AddressComponentRange;
import inet.ipaddr.format.IPAddressRange;
import inet.ipaddr.format.standard.AddressCreator;
import inet.ipaddr.format.util.AddressComponentRangeSpliterator;
import inet.ipaddr.format.util.AddressComponentSpliterator;
import inet.ipaddr.format.validate.ParsedAddressGrouping;

/**
 * This class can be used to represent an arbitrary range of consecutive IP addresses.  
 * 

* Note that the IPAddress and IPAddressString classes allow you to specify a range of values for each segment. * That allows you to represent single addresses, any address prefix subnet (eg 1.2.0.0/16 or 1:2:3:4::/64) or any subnet that can be represented with segment ranges (1.2.0-255.* or 1:2:3:4:*), see * {@link IPAddressString} for details. *

* IPAddressString and IPAddress cover all potential subnets and addresses that can be represented by a single address string of 4 or less segments for IPv4, and 8 or less segments for IPv6. *

* This class allows the representation of any sequential address range, including those that cannot be represented by IPAddress. *

* String representations include the full address for both the lower and upper bounds of the range. * * @custom.core * @author sfoley * */ public abstract class IPAddressSeqRange implements IPAddressRange { private static final long serialVersionUID = 1L; public static final String DEFAULT_RANGE_SEPARATOR = " -> "; private static final IPAddressSeqRange EMPTY_RANGES[] = new IPAddressSeqRange[0]; protected final IPAddress lower, upper; private transient BigInteger count; private transient int hashCode; protected IPAddressSeqRange(T first, T second, boolean preSet) { lower = first; upper = second; } protected IPAddressSeqRange( T first, T other, UnaryOperator getLower, UnaryOperator getUpper, UnaryOperator prefixLenRemover) { boolean f; if((f = first.contains(other)) || other.contains(first)) { T addr = f ? prefixLenRemover.apply(first) : prefixLenRemover.apply(other); lower = getLower.apply(addr); upper = getUpper.apply(addr); } else { T firstLower = getLower.apply(first); T otherLower = getLower.apply(other); T firstUpper = getUpper.apply(first); T otherUpper = getUpper.apply(other); T lower = compareLowValues(firstLower, otherLower) > 0 ? otherLower : firstLower; T upper = compareLowValues(firstUpper, otherUpper) < 0 ? otherUpper : firstUpper; this.lower = prefixLenRemover.apply(lower); this.upper = prefixLenRemover.apply(upper); } } protected IPAddressSeqRange( T first, T second) { lower = first; upper = second; } private static int compareLowValues(IPAddress one, IPAddress two) { return IPAddress.compareLowValues(one, two); } @Override public BigInteger getCount() { BigInteger result = count; if(result == null) { count = result = getCountImpl(); } return result; } @Override public boolean isMultiple() { BigInteger count = this.count; if(count == null) { return !getLower().equals(getUpper()); } return IPAddressRange.super.isMultiple(); } /** * * @param other the range to compare, which does not need to range across the same address space * @return whether this range spans more addresses than the provided range. */ public boolean isMore(IPAddressSeqRange other) { return getCount().compareTo(other.getCount()) > 0; } protected BigInteger getCountImpl() { return IPAddressRange.super.getCount(); } @Override public abstract Iterable getIterable(); protected static int getNetworkSegmentIndex(int networkPrefixLength, int bytesPerSegment, int bitsPerSegment) { return ParsedAddressGrouping.getNetworkSegmentIndex(networkPrefixLength, bytesPerSegment, bitsPerSegment); } protected static int getHostSegmentIndex(int networkPrefixLength, int bytesPerSegment, int bitsPerSegment) { return ParsedAddressGrouping.getHostSegmentIndex(networkPrefixLength, bytesPerSegment, bitsPerSegment); } /** * Iterates through the range of prefix blocks in this range instance using the given prefix length. * * @param prefLength * @return */ @Override public abstract Iterator prefixBlockIterator(int prefLength); @Override public abstract AddressComponentRangeSpliterator prefixBlockSpliterator(int prefLength); @Override public abstract Stream prefixBlockStream(int prefLength); protected static interface IPAddressSeqRangeSplitterSink{ void setSplitValues(S left, S right); S getAddressItem(); }; @FunctionalInterface protected static interface IPAddressSeqRangeIteratorProvider extends SeqRangeIteratorProvider{} protected static AddressComponentRangeSpliterator createSpliterator( S forIteration, Predicate> splitter, IPAddressSeqRangeIteratorProvider iteratorProvider, ToLongFunction longSizer) { return new IPAddressSeqRangeSpliterator(forIteration, splitter, iteratorProvider, longSizer); } protected static AddressComponentRangeSpliterator createSpliterator( S forIteration, Predicate> splitter, IPAddressSeqRangeIteratorProvider iteratorProvider, Function sizer, Predicate downSizer, ToLongFunction longSizer) { return new IPAddressSeqRangeSpliterator(forIteration, splitter, iteratorProvider, sizer, downSizer, longSizer); } protected static AddressComponentSpliterator createPrefixSpliterator( S forIteration, Predicate> splitter, IPAddressSeqRangeIteratorProvider iteratorProvider, ToLongFunction longSizer) { return new IPAddressSeqRangePrefixSpliterator(forIteration, splitter, iteratorProvider, longSizer); } protected static AddressComponentSpliterator createPrefixSpliterator( S forIteration, Predicate> splitter, IPAddressSeqRangeIteratorProvider iteratorProvider, Function sizer, Predicate downSizer, ToLongFunction longSizer) { return new IPAddressSeqRangePrefixSpliterator(forIteration, splitter, iteratorProvider, sizer, downSizer, longSizer); } protected static Iterator rangedIterator(Iterator iter) { return new Iterator() { @Override public boolean hasNext() { return iter.hasNext(); } @SuppressWarnings("unchecked") @Override public R next() { return (R) iter.next().toSequentialRange(); } }; } /** * Iterates through the range of prefixes in this range instance using the given prefix length. *

* Since a range between two arbitrary addresses cannot always be represented with a single IPAddress instance, * the returned iterator iterates through {@link IPAddressSeqRange} instances. *

* For instance, if iterating from 1.2.3.4 to 1.2.4.5 with prefix 8, the range shares the same prefix 1, * but the range cannot be represented by the address 1.2.3-4.4-5 which does not include 1.2.3.255 or 1.2.4.0 both of which are in the original range. * Nor can the range be represented by 1.2.3-4.0-255 which includes 1.2.4.6 and 1.2.3.3, both of which were not in the original range. * An IPAddressSeqRange is thus required to represent that prefixed range. * * @param prefixLength * @return */ @Override public Iterator prefixIterator(int prefixLength) { if(prefixLength < 0) { throw new PrefixLenException(prefixLength); } if(!isMultiple()) { return new Iterator() { IPAddressSeqRange orig = IPAddressSeqRange.this; @Override public boolean hasNext() { return orig != null; } @Override public IPAddressSeqRange next() { if(orig == null) { throw new NoSuchElementException(); } IPAddressSeqRange result = orig; orig = null; return result; } }; } return new Iterator() { Iterator prefixBlockIterator = prefixBlockIterator(prefixLength); private boolean first = true; @Override public boolean hasNext() { return prefixBlockIterator.hasNext(); } @Override public IPAddressSeqRange next() { IPAddress next = prefixBlockIterator.next(); if(first) { first = false; // next is a prefix block IPAddress lower = getLower(); if(hasNext()) { if(!lower.includesZeroHost(prefixLength)) { return create(lower, next.getUpper()); } } else { IPAddress upper = getUpper(); if(!lower.includesZeroHost(prefixLength) || !upper.includesMaxHost(prefixLength)) { return create(lower, upper); } } } else if(!hasNext()) { IPAddress upper = getUpper(); if(!upper.includesMaxHost(prefixLength)) { return create(next.getLower(), upper); } } return next.toSequentialRange(); } }; } @Override public abstract AddressComponentSpliterator prefixSpliterator(int prefLength); @Override public abstract Stream prefixStream(int prefLength); @FunctionalInterface protected interface SegValueComparator { boolean apply(T segmentSeries1, T segmentSeries2, int index); } /** * Splits a sequential range into two. *

* Returns false if it cannot be done. * * @param beingSplit * @param transformer * @param segmentCreator * @param originalSegments * @param networkSegmentIndex if this index matches hostSegmentIndex, splitting will attempt to split the network part of this segment * @param hostSegmentIndex splitting will work with the segments prior to this one * @param prefixLength * @return */ protected static boolean split( IPAddressSeqRangeSplitterSink sink, BiFunction transformer, AddressSegmentCreator segmentCreator, S originalSegmentsLower[], S originalSegmentsUpper[], int networkSegmentIndex, //for regular iterators (not prefix block), networkSegmentIndex is last segment (count - 1) - it is only instrumental with prefix iterators int hostSegmentIndex, // for regular iterators hostSegmentIndex is past last segment (count) - it is only instrumental with prefix iterators Integer prefixLength) { int i = 0; S lowerSeg, upperSeg; lowerSeg = upperSeg = null; boolean isSplit = false; for(; i < hostSegmentIndex; i++) { S segLower = originalSegmentsLower[i]; S segUpper = originalSegmentsUpper[i]; int lower = segLower.getSegmentValue(); int upper = segUpper.getSegmentValue(); // if multiple, split into two if(lower != upper) { isSplit = true; int size = upper - lower; int mid = lower + (size >>> 1); lowerSeg = segmentCreator.createSegment(mid); upperSeg = segmentCreator.createSegment(mid + 1); break; } } if(i == networkSegmentIndex && !isSplit) { // prefix or prefix block iterators: no need to differentiate, handle both as prefix, iteration will handle the rest S segLower = originalSegmentsLower[i]; S segUpper = originalSegmentsUpper[i]; int segBitCount = segLower.getBitCount(); Integer pref = IPAddressSection.getSegmentPrefixLength(segBitCount, prefixLength, i); int shiftAdjustment = segBitCount - pref; int lower = segLower.getSegmentValue(); int upper = segUpper.getSegmentValue(); lower >>>= shiftAdjustment; upper >>>= shiftAdjustment; if(lower != upper) { isSplit = true; int size = upper - lower; int mid = lower + (size >>> 1); int next = mid + 1; mid = (mid << shiftAdjustment) | ~(~0 << shiftAdjustment); next <<= shiftAdjustment; lowerSeg = segmentCreator.createSegment(mid); upperSeg = segmentCreator.createSegment(next); } } if(isSplit) { int len = originalSegmentsLower.length; S lowerUpperSegs[] = segmentCreator.createSegmentArray(len); S upperLowerSegs[] = segmentCreator.createSegmentArray(len); System.arraycopy(originalSegmentsLower, 0, lowerUpperSegs, 0, i); System.arraycopy(originalSegmentsLower, 0, upperLowerSegs, 0, i); int j = i + 1; lowerUpperSegs[i] = lowerSeg; upperLowerSegs[i] = upperSeg; Arrays.fill(lowerUpperSegs, j, lowerUpperSegs.length, segmentCreator.createSegment(lowerSeg.getMaxSegmentValue())); Arrays.fill(upperLowerSegs, j, upperLowerSegs.length, segmentCreator.createSegment(0)); sink.setSplitValues(transformer.apply(originalSegmentsLower, lowerUpperSegs), transformer.apply(upperLowerSegs, originalSegmentsUpper)); } return isSplit; } @Override public abstract Iterator iterator(); @Override public abstract AddressComponentRangeSpliterator spliterator(); @Override public abstract Stream stream(); /* * This iterator is used for the case where the range is non-multiple */ protected static Iterator iterator(T original, AddressCreator creator) { return IPAddressSection.iterator(original, creator, null); } /* This iterator is (not surprisingly) 2 to 3 times faster (based on measurements I've done) than an iterator that uses the increment method like: return iterator(a -> a.increment(1)); protected Iterator iterator(UnaryOperator incrementor) { return new Iterator() { BigInteger count = getCount(); T current = lower; @Override public boolean hasNext() { return !count.equals(BigInteger.ZERO); } @Override public T next() { if(hasNext()) { T result = current; current = incrementor.apply(current); count = count.subtract(BigInteger.ONE); return result; } throw new NoSuchElementException(); } }; } */ protected static Iterator iterator( T lower, T upper, AddressCreator creator, SegFunction segProducer, SegFunction> segmentIteratorProducer, SegValueComparator segValueComparator, int networkSegmentIndex, int hostSegmentIndex, SegFunction> prefixedSegIteratorProducer) { int divCount = lower.getSegmentCount(); // at any given point in time, this list provides an iterator for the segment at each index ArrayList>> segIteratorProducerList = new ArrayList>>(divCount); // at any given point in time, finalValue[i] is true if and only if we have reached the very last value for segment i - 1 // when that happens, the next iterator for the segment at index i will be the last boolean finalValue[] = new boolean[divCount + 1]; // here is how the segment iterators will work: // the low and high values at each segment are low, high // the maximum possible values for any segment are min, max // we first find the first k >= 0 such that low != high for the segment at index k // the initial set of iterators at each index are as follows: // for i < k finalValue[i] is set to true right away. // we create an iterator from seg = new Seg(low) // for i == k we create a wrapped iterator from Seg(low, high), wrapper will set finalValue[i] once we reach the final value of the iterator // for i > k we create an iterator from Seg(low, max) // // after the initial iterator has been supplied, any further iterator supplied for the same segment is as follows: // for i <= k, there was only one iterator, there will be no further iterator // for i > k, // if i == 0 or of if flagged[i - 1] is true, we create a wrapped iterator from Seg(low, high), wrapper will set finalValue[i] once we reach the final value of the iterator // otherwise we create an iterator from Seg(min, max) // // By following these rules, we iterate through all possible addresses boolean notDiffering = true; finalValue[0] = true; S allSegShared = null; for(int i = 0; i < divCount; i++) { SegFunction> segIteratorProducer; if(prefixedSegIteratorProducer != null && i >= networkSegmentIndex) { segIteratorProducer = prefixedSegIteratorProducer; } else { segIteratorProducer = segmentIteratorProducer; } S lowerSeg = segProducer.apply(lower, i); int indexi = i; if(notDiffering) { notDiffering = segValueComparator.apply(lower, upper, i); if(notDiffering) { // there is only one iterator and it produces only one value finalValue[i + 1] = true; Iterator iterator = segIteratorProducer.apply(lowerSeg, i); segIteratorProducerList.add(() -> iterator); } else { // in the first differing segment the only iterator will go from segment value of lower address to segment value of upper address Iterator iterator = segIteratorProducer.apply( creator.createSegment(lowerSeg.getSegmentValue(), upper.getSegment(i).getSegmentValue(), null), i); // the wrapper iterator detects when the iterator has reached its final value Iterator wrappedFinalIterator = new Iterator() { @Override public boolean hasNext() { return iterator.hasNext(); } @Override public S next() { S next = iterator.next(); if(!iterator.hasNext()) { finalValue[indexi + 1] = true; } return next; } }; segIteratorProducerList.add(() -> wrappedFinalIterator); } } else { // in the second and all following differing segments, rather than go from segment value of lower address to segment value of upper address // we go from segment value of lower address to the max seg value the first time through // then we go from the min value of the seg to the max seg value each time until the final time, // the final time we go from the min value to the segment value of upper address // we know it is the final time through when the previous iterator has reached its final value, which we track // the first iterator goes from the segment value of lower address to the max value of the segment Iterator firstIterator = segIteratorProducer.apply(creator.createSegment(lowerSeg.getSegmentValue(), lower.getMaxSegmentValue(), null), i); // the final iterator goes from 0 to the segment value of our upper address Iterator finalIterator = segIteratorProducer.apply(creator.createSegment(0, upper.getSegment(i).getSegmentValue(), null), i); // the wrapper iterator detects when the final iterator has reached its final value Iterator wrappedFinalIterator = new Iterator() { @Override public boolean hasNext() { return finalIterator.hasNext(); } @Override public S next() { S next = finalIterator.next(); if(!finalIterator.hasNext()) { finalValue[indexi + 1] = true; } return next; } }; if(allSegShared == null) { allSegShared = creator.createSegment(0, lower.getMaxSegmentValue(), null); } // all iterators after the first iterator and before the final iterator go from 0 the max segment value, // and there will be many such iterators S allSeg = allSegShared; Supplier> finalIteratorProducer = () -> finalValue[indexi] ? wrappedFinalIterator : segIteratorProducer.apply(allSeg, indexi); segIteratorProducerList.add(() -> { //the first time through, we replace the iterator producer so the first iterator used only once segIteratorProducerList.set(indexi, finalIteratorProducer); return firstIterator; }); } } IntFunction> iteratorProducer = iteratorIndex -> segIteratorProducerList.get(iteratorIndex).get(); return IPAddressSection.iterator(null, creator, IPAddressSection.iterator( lower.getSegmentCount(), creator, iteratorProducer, networkSegmentIndex, hostSegmentIndex, iteratorProducer) ); } /** * Returns the lowest address in the sequential range, the one with the lowest numeric value */ @Override public IPAddress getLower() { return lower; } /** * Returns the highest address in the sequential range, the one with the highest numeric value */ @Override public IPAddress getUpper() { return upper; } public String toNormalizedString(String separator) { Function stringer = IPAddress::toNormalizedString; return toString(stringer, separator, stringer); } /** * Produces a normalized string for the address range. * It has the format "lower -> upper" where lower and upper are the normalized strings for the lowest and highest addresses in the range, given by {@link #getLower()} and {@link #getUpper()}. */ @Override public String toNormalizedString() { return toNormalizedString(DEFAULT_RANGE_SEPARATOR); } /** * Produces a canonical string for the address range with the given separator string. */ public String toCanonicalString(String separator) { Function stringer = IPAddress::toCanonicalString; return toString(stringer, separator, stringer); } /** * Produces a canonical string for the address range. * It has the format "lower -> upper" where lower and upper are the canonical strings for the lowest and highest addresses in the range, given by {@link #getLower()} and {@link #getUpper()}. */ @Override public String toCanonicalString() { return toCanonicalString(DEFAULT_RANGE_SEPARATOR); } public String toString(Function lowerStringer, String separator, Function upperStringer) { return lowerStringer.apply(getLower()) + separator + upperStringer.apply(getUpper()); } /** * Produces the canonical string for the address, also available from {@link #toCanonicalString()}. */ @Override public String toString() { return toCanonicalString(); } /** * Returns the minimal-size prefix block that covers all the addresses in this range. * The resulting block will have a larger count than this, unless this range already directly corresponds to a prefix block. */ @Override public abstract IPAddress coverWithPrefixBlock(); @Override public abstract IPAddress[] spanWithPrefixBlocks(); @Override public abstract IPAddress[] spanWithSequentialBlocks(); /** * Joins the given ranges into the fewest number of ranges. * This method can handle null ranges, which are ignored. * The returned array will never be null and will be sorted by ascending lowest range value. * * @param ranges * @return */ public static IPAddressSeqRange[] join(IPAddressSeqRange... ranges) { if(ranges.length == 0) { return EMPTY_RANGES; } ranges = ranges.clone(); // null entries are automatic joins int joinedCount = 0; for(int i = 0, j = ranges.length - 1; i <= j; i++) { if(ranges[i] == null) { joinedCount++; while(ranges[j] == null && j > i) { j--; joinedCount++; } if(j > i) { ranges[i] = ranges[j]; ranges[j] = null; j--; } } } int len = ranges.length - joinedCount; Arrays.sort(ranges, 0, len, Address.ADDRESS_LOW_VALUE_COMPARATOR); for(int i = 0; i < len; ) { IPAddressSeqRange range = ranges[i]; IPAddress currentLower = range.getLower(); IPAddress currentUpper = range.getUpper(); boolean didJoin = false; int j = i + 1; for(; j < len; j++) { IPAddressSeqRange range2 = ranges[j]; IPAddress nextLower = range2.getLower(); if(compareLowValues(currentUpper, nextLower) >= 0 || (currentUpper.getIPVersion().equals(nextLower.getIPVersion()) && currentUpper.increment(1).equals(nextLower))) { // join them joinedCount++; IPAddress nextUpper = range2.getUpper(); if(compareLowValues(currentUpper, nextUpper) < 0) { currentUpper = nextUpper; } ranges[j] = null; didJoin = true; } else break; } if(didJoin) { ranges[i] = range.create(currentLower, currentUpper); } i = j; } if(joinedCount == 0) { return ranges; } if(ranges.length == joinedCount) { return EMPTY_RANGES; } IPAddressSeqRange joined[] = new IPAddressSeqRange[ranges.length - joinedCount]; if(joined.length > 0) { for(int i = 0, j = 0; ; i++) { IPAddressSeqRange range = ranges[i]; if(range == null) { continue; } joined[j++] = range; if(j >= joined.length) { break; } } } return joined; } /** * Returns true if this sequential range overlaps with the given sequential range. * * @param other * @return */ public boolean overlaps(IPAddressSeqRange other) { return compareLowValues(other.getLower(), getUpper()) <= 0 && compareLowValues(other.getUpper(), getLower()) >= 0; } // we choose to not make this public // it is simply wrong to do an instanceof in the IPAddressRange interface, it assumes you know all implementors, // it will not work if/when someone adds a new implementation. // If you do not know how an IPAddressRange is implemented, can you do the contains? // Yes, but only by iterating, which is damn ugly for large ranges. // Now that we have toSequentialRange() in IPAddressRange, it is easy to do this for sequential subnets. // And for non-sequential, there is no simple way of doing it, // in IPAddress you need to either go through the segments, or you need to go through the sequential blocks, // and there is no general way to do it for any implementation of IPAddressRange. private boolean containsRange(IPAddressRange other) { return compareLowValues(other.getLower(), getLower()) >= 0 && compareLowValues(other.getUpper(), getUpper()) <= 0; } @Override public boolean contains(IPAddress other) { return containsRange(other); } @Override public boolean contains(IPAddressSeqRange other) { return containsRange(other); } /** * Returns whether the address or subnet represents a range of values that are sequential. *

* IP address sequential ranges are sequential by definition, so this returns true. * * @return true */ @Override public boolean isSequential() { return true; } @Override public int hashCode() { int res = hashCode; if(res == 0) { res = 31 * getLower().hashCode() + getUpper().hashCode(); hashCode = res; } return res; } /** * Returns whether the given sequential address range is equal to this sequential address range. * Two sequential address ranges are equal if their lower and upper range boundaries are equal. */ @Override public boolean equals(Object o) { if(o instanceof IPAddressSeqRange) { IPAddressSeqRange otherRange = (IPAddressSeqRange) o; return getLower().equals(otherRange.getLower()) && getUpper().equals(otherRange.getUpper()); } return false; } /** * Returns the intersection of this range with the given range, a range which includes those addresses in both this and the given range. * @param other * @return */ public IPAddressSeqRange intersect(IPAddressSeqRange other) { IPAddress otherLower = other.getLower(); IPAddress otherUpper = other.getUpper(); IPAddress lower = getLower(); IPAddress upper = getUpper(); if(compareLowValues(lower, otherLower) <= 0) { if(compareLowValues(upper, otherUpper) >= 0) { return other; } else if(compareLowValues(upper, otherLower) < 0) { return null; } return create(otherLower, upper); } else if(compareLowValues(otherUpper, upper) >= 0) { return this; } else if(compareLowValues(otherUpper, lower) < 0) { return null; } return create(lower, otherUpper); } /** * Joins two ranges if they are contiguous ranges. * * If this range overlaps with the given range, * or if the highest value of the lower range is one below the lowest value of the higher range, * then the two are joined into a new larger range that is returned. *

* Otherwise, null is returned. * * @param other * @return */ public IPAddressSeqRange join(IPAddressSeqRange other) { IPAddress otherLower = other.getLower(); IPAddress otherUpper = other.getUpper(); IPAddress lower = getLower(); IPAddress upper = getUpper(); int lowerComp = compareLowValues(lower, otherLower); if(!overlaps(other)) { if(lower.getIPVersion().equals(otherLower.getIPVersion())) { if(lowerComp >= 0) { if(otherUpper.increment(1).equals(lower)) { return create(otherLower, upper); } } else { if(upper.increment(1).equals(otherLower)) { return create(lower, otherUpper); } } } return null; } int upperComp = compareLowValues(upper, otherUpper); IPAddress lowestLower, highestUpper; if(lowerComp >= 0) { if(lowerComp == 0 && upperComp == 0) { return this; } lowestLower = otherLower; } else { lowestLower = lower; } highestUpper = upperComp >= 0 ? upper : otherUpper; return create(lowestLower, highestUpper); } /** * Extend this sequential range to include all address in the given range, which can be an IPAddress or IPAddressSeqRange. * If the argument has a different IP version than this, null is returned. * Otherwise, this method returns the range that includes this range, the given range, and all addresses in-between. * * @param other * @return */ public IPAddressSeqRange extend(IPAddressRange other) { IPAddress otherLower = other.getLower(); IPAddress otherUpper = other.getUpper(); IPAddress lower = getLower(); IPAddress upper = getUpper(); int lowerComp = compareLowValues(lower, otherLower); int upperComp = compareLowValues(upper, otherUpper); if(lowerComp > 0) { // if(upperComp <= 0) { // ol l u ou return other.toSequentialRange(); } if(!upper.getIPVersion().equals(otherLower.getIPVersion())) { return null; } // ol l ou u or ol ou l u return create(otherLower, upper); } // lowerComp <= 0 if(upperComp >= 0) { // l ol ou u return this; } if(!lower.getIPVersion().equals(otherUpper.getIPVersion())) { return null; } return create(lower, otherUpper);// l ol u ou or l u ol ou } /** * Subtracts the given range from this range, to produce either zero, one, or two address ranges that contain the addresses in this range and not in the given range. * If the result has length 2, the two ranges are ordered by ascending lowest range value. * * @param other * @return */ public IPAddressSeqRange[] subtract(IPAddressSeqRange other) { IPAddress otherLower = other.getLower(); IPAddress otherUpper = other.getUpper(); IPAddress lower = getLower(); IPAddress upper = getUpper(); if(compareLowValues(lower, otherLower) < 0) { if(compareLowValues(upper, otherUpper) > 0) { // l ol ou u return createPair(lower, otherLower.increment(-1), otherUpper.increment(1), upper); } else { int comp = compareLowValues(upper, otherLower); if(comp < 0) { // l u ol ou return createSingle(); } return createSingle(lower, otherLower.increment(-1)); // l ol u ou (includes l u == ol ou) } } else if(compareLowValues(otherUpper, upper) >= 0) { // ol l u ou return createEmpty(); } else { int comp = compareLowValues(otherUpper, lower); if(comp < 0) { return createSingle(); // ol ou l u } return createSingle(otherUpper.increment(1), upper); // ol l ou u (includes ol ou == l u) } } protected abstract IPAddressSeqRange create(IPAddress lower, IPAddress upper); protected abstract IPAddressSeqRange[] createPair(IPAddress lower1, IPAddress upper1, IPAddress lower2, IPAddress upper2); protected abstract IPAddressSeqRange[] createSingle(IPAddress lower, IPAddress upper); protected abstract IPAddressSeqRange[] createSingle(); protected abstract IPAddressSeqRange[] createEmpty(); @Override public boolean containsPrefixBlock(int prefixLen) { IPAddressSection.checkSubnet(lower, prefixLen); int divCount = lower.getDivisionCount(); int bitsPerSegment = lower.getBitsPerSegment(); int i = getHostSegmentIndex(prefixLen, lower.getBytesPerSegment(), bitsPerSegment); if(i < divCount) { IPAddressSegment div = lower.getSegment(i); IPAddressSegment upperDiv = upper.getSegment(i); int segmentPrefixLength = IPAddressSection.getPrefixedSegmentPrefixLength(bitsPerSegment, prefixLen, i); if(!div.containsPrefixBlock(div.getSegmentValue(), upperDiv.getSegmentValue(), segmentPrefixLength)) { return false; } for(++i; i < divCount; i++) { div = lower.getSegment(i); upperDiv = upper.getSegment(i); //is full range? if(!div.includesZero() || !upperDiv.includesMax()) { return false; } } } return true; } @Override public boolean containsSinglePrefixBlock(int prefixLen) { IPAddressSection.checkSubnet(lower, prefixLen); int prevBitCount = 0; int divCount = lower.getDivisionCount(); for(int i = 0; i < divCount; i++) { IPAddressSegment div = lower.getSegment(i); IPAddressSegment upperDiv = upper.getSegment(i); int bitCount = div.getBitCount(); int totalBitCount = bitCount + prevBitCount; if(prefixLen >= totalBitCount) { if(!div.isSameValues(upperDiv)) { return false; } } else { int divPrefixLen = Math.max(0, prefixLen - prevBitCount); if(!div.containsSinglePrefixBlock(div.getSegmentValue(), upperDiv.getSegmentValue(), divPrefixLen)) { return false; } for(++i; i < divCount; i++) { div = lower.getSegment(i); upperDiv = upper.getSegment(i); //is full range? if(!div.includesZero() || !upperDiv.includesMax()) { return false; } } return true; } prevBitCount = totalBitCount; } return true; } @Override public int getBitCount() { return getLower().getBitCount(); } @Override public byte[] getBytes() { return getLower().getBytes(); } @Override public byte[] getBytes(byte[] bytes) { return getLower().getBytes(bytes); } @Override public byte[] getBytes(byte[] bytes, int index) { return getLower().getBytes(bytes, index); } @Override public byte[] getUpperBytes() { return getUpper().getUpperBytes(); } @Override public byte[] getUpperBytes(byte[] bytes) { return getUpper().getUpperBytes(bytes); } @Override public byte[] getUpperBytes(byte[] bytes, int index) { return getUpper().getUpperBytes(bytes, index); } @Override public BigInteger getValue() { return getLower().getValue(); } @Override public BigInteger getUpperValue() { return getUpper().getValue(); } /** * Returns whether this sequential range spans from the zero address to itself. */ @Override public boolean isZero() { return includesZero() && !isMultiple(); } /** * Returns whether this sequential range's lower value is the zero address. */ @Override public boolean includesZero() { return getLower().isZero(); } /** * Returns whether this sequential range spans from the highest address, the address whose bits are all ones, to itself. */ @Override public boolean isMax() { return includesMax() && !isMultiple(); } /** * Returns whether this sequential range's upper value is the highest address, the address whose bits are all ones. */ @Override public boolean includesMax() { return getUpper().isMax(); } }