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

inet.ipaddr.IPAddressSegment Maven / Gradle / Ivy

/*
 * Copyright 2016-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.Iterator;
import java.util.function.Supplier;
import java.util.stream.Stream;

import inet.ipaddr.AddressNetwork.AddressSegmentCreator;
import inet.ipaddr.IPAddress.IPVersion;
import inet.ipaddr.IPAddressNetwork.IPAddressCreator;
import inet.ipaddr.IPAddressSection.IPStringCache;
import inet.ipaddr.IPAddressSection.IPStringOptions;
import inet.ipaddr.format.standard.AddressDivision;
import inet.ipaddr.format.standard.IPAddressDivision;
import inet.ipaddr.format.string.IPAddressStringDivisionSeries;
import inet.ipaddr.format.util.AddressComponentSpliterator;
import inet.ipaddr.format.util.IPAddressStringWriter;
import inet.ipaddr.format.validate.ParsedIPAddress.BitwiseOrer;
import inet.ipaddr.format.validate.ParsedIPAddress.Masker;
import inet.ipaddr.ipv4.IPv4Address;
import inet.ipaddr.ipv6.IPv6Address;

/**
 * This represents a single segment of an IP address.  For IPv4, segments are 1 byte.  For IPv6, they are two bytes.
 * 
 * IPAddressSegment objects are immutable and thus also thread-safe.
 * 
 * @author sfoley
 *
 */
public abstract class IPAddressSegment extends IPAddressDivision implements AddressSegment {
	
	private static final long serialVersionUID = 4L;
	
	// These two values define the uniqueness of a segment with respect to equality and comparison, while the prefix is ignored as these values encapsulate the range of addresses created by the prefix.
	private final int value; // the lower value of the segment
	private final int upperValue; // the upper value of a CIDR or other type of range, if not a range it is the same as value
	
	/**
	 * Constructs a segment of an IPv4 or IPv6 address with the given value.
	 * 
	 * @param value the value of the segment
	 */
	protected IPAddressSegment(int value) {
		if(value < 0) {
			throw new AddressValueException(value);
		}
		this.value = this.upperValue = value;
	}
	
	/**
	 * Constructs a segment of an IPv4 or IPv6 address.
	 * 
	 * @param value the value of the segment.
	 * 		If the segmentPrefixLength is non-null, the network prefix of the value is used, and the segment represents all segment values with the same network prefix (all network or subnet segments, in other words).
	 * @param segmentPrefixLength the segment prefix bits, which can be null
	 */
	protected IPAddressSegment(int value, Integer segmentPrefixLength) {
		this(value, value, segmentPrefixLength);
	}
	
	/**
	 * Constructs a segment of an IPv4 or IPv6 address that represents a range of values.
	 * 
	 * @param segmentPrefixLength the segment prefix bits, which can be null.  If segmentPrefixLength is non-null, this segment represents a range of segment values with the given network prefix length.
	 * @param lower the lower value of the range of values represented by the segment.  If segmentPrefixLength is non-null, the lower value becomes the smallest value with the same network prefix.
	 * @param upper the upper value of the range of values represented by the segment.  If segmentPrefixLength is non-null, the upper value becomes the largest value with the same network prefix.
	 */
	protected IPAddressSegment(int lower, int upper, Integer segmentPrefixLength) {
		super(segmentPrefixLength);
		if(lower < 0 || upper < 0) {
			throw new AddressValueException(lower < 0 ? lower : upper);
		}
		if(lower > upper) {
			int tmp = lower;
			lower = upper;
			upper = tmp;
		}
		segmentPrefixLength = getSegmentPrefixLength();
		if(segmentPrefixLength == null || segmentPrefixLength >= getBitCount() || !getNetwork().getPrefixConfiguration().allPrefixedAddressesAreSubnets()) {
			this.value = lower;
			this.upperValue = upper;
		} else {
			int mask = getSegmentNetworkMask(segmentPrefixLength);
			this.value = lower & mask;
			this.upperValue = upper | getSegmentHostMask(segmentPrefixLength);
		}
	}
	
	@Override
	public abstract IPAddressNetwork getNetwork();
	
	public boolean isIPv4() {
		return false;
	}
	
	public boolean isIPv6() {
		return false;
	}
	
	public abstract IPVersion getIPVersion();

	protected static Integer getSplitSegmentPrefix(int bitsPerSegment, Integer networkPrefixLength, int segmentIndex) {
		return IPAddressSection.getSegmentPrefixLength(bitsPerSegment, networkPrefixLength, segmentIndex);
	}
	
	@Override
	protected long getDivisionNetworkMask(int bits) {
		return getSegmentNetworkMask(bits);
	}
	
	@Override
	protected long getDivisionHostMask(int bits) {
		return getSegmentHostMask(bits);
	}
	
	protected abstract int getSegmentNetworkMask(int bits);
	
	protected abstract int getSegmentHostMask(int bits);
	
	@Override
	public int getMinPrefixLengthForBlock() {
		if(getNetwork().getPrefixConfiguration().allPrefixedAddressesAreSubnets() && isPrefixed() && getSegmentPrefixLength() == 0) {
			return 0;
		}
		return super.getMinPrefixLengthForBlock();
	}
	
	public static int getMaxSegmentValue(IPVersion version) {
		return version.isIPv4() ? IPv4Address.MAX_VALUE_PER_SEGMENT : IPv6Address.MAX_VALUE_PER_SEGMENT;
	}

	protected boolean isChangedByPrefix(Integer bits, boolean smallerOnly) {
		boolean hasBits = (bits != null);
		if(hasBits && (bits < 0 || bits > getBitCount())) {
			throw new PrefixLenException(this, bits);
		}
		if(smallerOnly) {
			if(isPrefixed()) {
				return hasBits && bits < getSegmentPrefixLength();
			}
		} else {
			if(isPrefixed()) {
				return !hasBits || bits != getSegmentPrefixLength().intValue();
			}
		}
		return hasBits;
	}

	protected  S toPrefixedSegment(Integer segmentPrefixLength, AddressSegmentCreator creator) {
		int lower = getSegmentValue();
		int upper = getUpperSegmentValue();
		boolean hasBits = (segmentPrefixLength != null);
		if(lower != upper) {
			//note that the case where our segmentPrefix is less than the requested prefix bits has already been accounted for in isNetworkChangedByPrefix
			//so we are not handling that here
			if(!hasBits) {
				return creator.createSegment(lower, upper, null);
			}
			return creator.createSegment(lower, upper, segmentPrefixLength);
		}
		return hasBits ? creator.createSegment(lower, segmentPrefixLength) : creator.createSegment(lower);
	}

	@Override
	public boolean isPrefixBlock() {
		return (isPrefixed() && getNetwork().getPrefixConfiguration().allPrefixedAddressesAreSubnets()) || super.isPrefixBlock();
	}

	protected boolean isNetworkChangedByPrefix(Integer bits, boolean withPrefixLength) {
		boolean hasBits = (bits != null);
		if(hasBits && (bits < 0 || bits > getBitCount())) {
			throw new PrefixLenException(this, bits);
		}
		withPrefixLength &= hasBits;
		boolean thisHasPrefix = isPrefixed();
		if(withPrefixLength != thisHasPrefix) {
			return true;
		}
		if(!hasBits || bits != getDivisionPrefixLength()) {
			return true;
		}
		return
			//this call differs from the host side.  On the host side, we check that the network portion is 0
			//on the network side, we check that the host side is the full range, not 0.  
			//This means that any resulting network section is the same regardless of whether a prefix is used: we don't need a prefix.
			!containsPrefixBlock(bits);
	}
	
	protected boolean isNetworkChangedByPrefixNonNull(int prefixBitCount) {
		return !isPrefixed() || prefixBitCount != getDivisionPrefixLength() || !containsPrefixBlock(prefixBitCount);
	}
	
	/**
	 * used by constructors of IPAddressSection, see {@link IPAddress#getNetworkSection(int, boolean)}
	 */
	public IPAddressSegment toNetworkSegment(Integer segmentPrefixLength) {
		return toNetworkSegment(segmentPrefixLength, true);
	}
	
	/**
	 * used by getNetworkSection and by constructors of IPAddressSection, see {@link IPAddress#getNetworkSection(int, boolean)}
	 */
	public abstract IPAddressSegment toNetworkSegment(Integer segmentPrefixLength, boolean withPrefixLength);

	protected  S toNetworkSegment(Integer segmentPrefixLength, boolean withPrefixLength, AddressSegmentCreator creator) {
		int newLower = getSegmentValue();
		int newUpper = getUpperSegmentValue();
		boolean hasPrefLen = segmentPrefixLength != null;
		if(hasPrefLen) {
			int mask = getSegmentNetworkMask(segmentPrefixLength);
			newLower &= mask;
			newUpper |= getSegmentHostMask(segmentPrefixLength);
		}
		withPrefixLength = withPrefixLength && hasPrefLen;
		if(newLower != newUpper) {
			//note that the case where our segmentPrefix is less than the requested prefix bits has already been accounted for in isNetworkChangedByPrefix
			//so we are not handling that here
			if(!withPrefixLength) {
				return creator.createSegment(newLower, newUpper, null);
			}
			return creator.createSegment(newLower, newUpper, segmentPrefixLength);
		}
		return withPrefixLength ? creator.createSegment(newLower, segmentPrefixLength) : creator.createSegment(newLower);
	}
	
	/**
	 * used by getHostSection, see {@link IPAddress#getHostSection(int)}
	 */
	public abstract IPAddressSegment toHostSegment(Integer segmentPrefixLength);
	
	protected  S toHostSegment(Integer segmentPrefixLength, AddressSegmentCreator creator) {
		// We need to use Masker:
		// For example, ipv4 0-4, masking with prefix length 7, should become 0-1, not 0-0
		// So you cannot do a straight mask of 0 and 4.
		int mask = (segmentPrefixLength == null) ? 0 : getSegmentHostMask(segmentPrefixLength);
		int lower = getSegmentValue();
		int upper = getUpperSegmentValue();
		Masker masker = maskRange(lower, upper, mask, getMaxValue());
		int newLower = (int) masker.getMaskedLower(lower, mask);
		int newUpper = (int) masker.getMaskedUpper(upper, mask);
		if(newLower != newUpper) {
			return creator.createSegment(newLower, newUpper, null);
		}
		return creator.createSegment(newLower);
	}
	
	protected boolean isHostChangedByPrefix(Integer bits) {
		boolean hasBits = (bits != null);
		if(hasBits && (bits < 0 || bits > getBitCount())) {
			throw new PrefixLenException(this, bits);
		}
		//a host segment has no prefix, so if this remains unchanged it must have no prefix length
		if(isPrefixed()) {
			return true;
		}
		int mask = !hasBits ? 0 : getSegmentHostMask(bits);
		//additionally, the value must match the value for the given network prefix length
		int value = getSegmentValue();
		int upperValue = getUpperSegmentValue();
		return value != (value & mask) || upperValue != (upperValue & mask);
	}
	
	protected boolean isChangedBy(int newValue, int newUpperValue, Integer segmentPrefixLength) throws IncompatibleAddressException {
		int value = getSegmentValue();
		int upperValue = getUpperSegmentValue();
		return value != newValue ||
				upperValue != newUpperValue ||
						(isPrefixed() ? !getSegmentPrefixLength().equals(segmentPrefixLength) : (segmentPrefixLength != null));
	}
	
	protected static Masker maskRange(long value, long upperValue, long maskValue, long maxValue) {
		return AddressDivision.maskRange(value, upperValue, maskValue, maxValue);
	}
	
	public MaskResult maskRange(int maskValue) {
		int value = getSegmentValue();
		int upperValue = getUpperSegmentValue();
		Masker masker = AddressDivision.maskRange(value, upperValue, maskValue, getMaxSegmentValue());
		return new MaskResult(value, upperValue, maskValue, masker);
	}
	
	protected static BitwiseOrer bitwiseOrRange(long value, long upperValue, long maskValue, long maxValue) {
		return AddressDivision.bitwiseOrRange(value, upperValue, maskValue, maxValue);
	}

	public BitwiseOrResult bitwiseOrRange(int maskValue) {
		int value = getSegmentValue();
		int upperValue = getUpperSegmentValue();
		BitwiseOrer orer = AddressDivision.bitwiseOrRange(value, upperValue, maskValue, getMaxSegmentValue());
		return new BitwiseOrResult(value, upperValue, maskValue, orer);
	}
	
	/**
	 * If this segment represents a range of values, returns a segment representing just the lowest value in the range, otherwise returns this.
	 * @return
	 */
	@Override
	public abstract IPAddressSegment getLower();
	
	/**
	 * If this segment represents a range of values, returns a segment representing just the highest value in the range, otherwise returns this.
	 * @return
	 */
	@Override
	public abstract IPAddressSegment getUpper();
	
	protected static  S getLowestOrHighest(S original, AddressSegmentCreator segmentCreator, boolean lowest) {
		boolean isAllSubnets = original.getNetwork().getPrefixConfiguration().allPrefixedAddressesAreSubnets();
		if(!original.isMultiple() && !(isAllSubnets && original.isPrefixed())) {
			return original;
		}
		return segmentCreator.createSegment(lowest ? original.getSegmentValue() : original.getUpperSegmentValue(), 
				isAllSubnets ? null : original.getSegmentPrefixLength());
	}

	@Override
	public abstract Iterable getIterable();

	@Override
	public abstract Iterator iterator();

	@Override
	public abstract AddressComponentSpliterator spliterator();

	@Override
	public abstract Stream stream();

	/**
	 * Iterates through the individual prefix blocks.
	 * 

* If the series has no prefix length, then this is equivalent to {@link #iterator()} */ public abstract Iterator prefixBlockIterator(); /** * Partitions and traverses through the individual prefix blocks of this segment for its prefix length. * * @return */ public abstract AddressComponentSpliterator prefixBlockSpliterator(); /** * Returns a sequential stream of the individual prefix blocks of this segment. For a parallel stream, call {@link Stream#parallel()} on the returned stream. * * @return */ public abstract Stream prefixBlockStream(); /** * Iterates through the individual prefixes. *

* If the series has no prefix length, then this is equivalent to {@link #iterator()} */ public abstract Iterator prefixIterator(); /** * Partitions and traverses through the individual prefixes of this segment for its prefix length. * * @return */ public abstract AddressComponentSpliterator prefixSpliterator(); protected static AddressComponentSpliterator prefixSpliterator( S seg, int segPrefLength, IPAddressCreator creator, Supplier> iteratorProvider) { int bitCount = seg.getBitCount(); int shiftAdjustment = bitCount - segPrefLength; int shiftMask, upperShiftMask; if(shiftAdjustment > 0) { shiftMask = ~0 << shiftAdjustment; upperShiftMask = ~shiftMask; } else { shiftMask = ~0; upperShiftMask = 0; } int originalValue = seg.getSegmentValue(); int originalUpperValue = seg.getUpperSegmentValue(); int originalValuePrefix = originalValue >>> shiftAdjustment; int originalUpperValuePrefix = originalUpperValue >>> shiftAdjustment; Integer segPrefixLength = IPAddressSection.cacheBits(segPrefLength); IntBinaryIteratorProvider subIteratorProvider = (isLowest, isHighest, value, upperValue) -> { if(isLowest || isHighest) { value = isLowest ? originalValue : value << shiftAdjustment; upperValue = isHighest ? originalUpperValue : ((upperValue << shiftAdjustment) | upperShiftMask); return iterator(null, value, upperValue, bitCount, creator, segPrefixLength, true, false); } return iterator(null, value << shiftAdjustment, upperValue << shiftAdjustment, bitCount, creator, segPrefixLength, true, true); }; return createSegmentSpliterator( seg, originalValuePrefix, originalUpperValuePrefix, iteratorProvider, subIteratorProvider, (value, upperValue) -> { value = (value == originalValuePrefix) ? originalValue : value << shiftAdjustment; upperValue = (upperValue == originalUpperValuePrefix) ? originalUpperValue : ((upperValue << shiftAdjustment) | upperShiftMask); return creator.createSegment(value, upperValue, segPrefLength); }); } /** * Returns a sequential stream of the individual prefixes of this segment. For a parallel stream, call {@link Stream#parallel()} on the returned stream. * * @return */ public abstract Stream prefixStream(); /** * Iterates through the individual prefix blocks according to the given segment prefix length. * Any existing prefix length is disregarded. */ public abstract Iterator prefixBlockIterator(int prefixLength); protected static AddressComponentSpliterator prefixBlockSpliterator( S seg, int segPrefLength, IPAddressCreator creator, Supplier> iteratorProvider) { int bitCount = seg.getBitCount(); int shiftAdjustment = bitCount - segPrefLength; int shiftMask, upperShiftMask; if(shiftAdjustment > 0) { shiftMask = ~0 << shiftAdjustment; upperShiftMask = ~shiftMask; } else { shiftMask = ~0; upperShiftMask = 0; } Integer segmentPrefixLength = IPAddressSection.cacheBits(segPrefLength); return createSegmentSpliterator( seg, seg.getSegmentValue() >>> shiftAdjustment, seg.getUpperSegmentValue() >>> shiftAdjustment, iteratorProvider, (isLowest, isHighest, value, upperValue) -> iterator( null, value << shiftAdjustment, (upperValue << shiftAdjustment) | upperShiftMask, bitCount, creator, segmentPrefixLength, true, true), (value, upperValue) -> creator.createSegment( value << shiftAdjustment, (upperValue << shiftAdjustment) | upperShiftMask, segmentPrefixLength)); } /** * Partitions and traverses through the individual prefix blocks for the given prefix length. * * @return */ public abstract AddressComponentSpliterator prefixBlockSpliterator(int prefixLength); /** * Returns a sequential stream of the individual prefix blocks for the given prefix length. For a parallel stream, call {@link Stream#parallel()} on the returned stream. * * @return */ public abstract Stream prefixBlockStream(int prefixLength); public static int getBitCount(IPVersion version) { return version.isIPv4() ? IPv4Address.BITS_PER_SEGMENT : IPv6Address.BITS_PER_SEGMENT; } public static int getByteCount(IPVersion version) { return version.isIPv4() ? IPv4Address.BYTES_PER_SEGMENT : IPv6Address.BYTES_PER_SEGMENT; } public static int getDefaultTextualRadix(IPVersion version) { return version.isIPv4() ? IPv4Address.DEFAULT_TEXTUAL_RADIX : IPv6Address.DEFAULT_TEXTUAL_RADIX; } @Override public boolean matches(int value) { return super.matches(value); } public boolean matchesWithPrefixMask(int value, Integer segmentPrefixLength) { return super.matchesWithPrefixMask(value, segmentPrefixLength); } @Override public boolean matchesWithMask(int value, int mask) { return super.matchesWithMask(value, mask); } @Override public boolean matchesWithMask(int lowerValue, int upperValue, int mask) { return super.matchesWithMask(lowerValue, upperValue, mask); } /** * @return the same value as {@link #getCount()} as an integer */ @Override public int getValueCount() { return getUpperSegmentValue() - getSegmentValue() + 1; } /** * Counts the number of prefixes in this address segment. *

* If this segment has no prefix length, this is equivalent to {@link #getValueCount()} * * @return */ public int getPrefixValueCount() { Integer prefixLength = getSegmentPrefixLength(); if(prefixLength == null) { return (int) getValueCount(); } return getPrefixValueCount(this, prefixLength); } @Override public BigInteger getCount() { return BigInteger.valueOf(getValueCount()); } @Override public BigInteger getPrefixCount(int segmentPrefixLength) { return BigInteger.valueOf(getPrefixValueCount(segmentPrefixLength)); } @Override public int getPrefixValueCount(int segmentPrefixLength) { if(segmentPrefixLength < 0) { throw new PrefixLenException(this, segmentPrefixLength); } int bitCount = getBitCount(); if(bitCount <= segmentPrefixLength) { return getValueCount(); } int shiftAdjustment = bitCount - segmentPrefixLength; return (getUpperSegmentValue() >>> shiftAdjustment) - (getSegmentValue() >>> shiftAdjustment) + 1; } protected int highByte() { return highByte(getSegmentValue()); } protected int lowByte() { return lowByte(getSegmentValue()); } protected static int highByte(int value) { return value >> 8; } protected static int lowByte(int value) { return value & 0xff; } @Override public long getMaxValue() { return getMaxSegmentValue(); } @Override public boolean isMultiple() { return getSegmentValue() != getUpperSegmentValue(); } /** * returns the lower value */ @Override public int getSegmentValue() { return value; } /** * returns the upper value */ @Override public int getUpperSegmentValue() { return upperValue; } /** * returns the lower value as a long, although for individual segments {@link #getSegmentValue()} provides the same value as an int */ @Override public long getDivisionValue() { return getSegmentValue(); } /** * returns the lower upper value as a long, although for individual segments {@link #getUpperSegmentValue()} provides the same value as an int */ @Override public long getUpperDivisionValue() { return getUpperSegmentValue(); } @Override public abstract IPAddressSegment reverseBits(boolean perByte); @Override public abstract IPAddressSegment reverseBytes(); /** * @deprecated use {@link #withoutPrefixLength()} and {@link #toZeroHost()} * @return */ @Deprecated public abstract IPAddressSegment removePrefixLength(); /** * Returns a segment with the same network bits as this segment, * but with the host bits changed to 0. *

* If there is no prefix length associated with this segment, returns an all-zero segment. *

* This is nearly equivalent to doing the mask (see {@link #maskRange(int)}) of this segment * with the network mask for the given prefix length, * but when applying a mask to a range of values you can have a non-sequential result. *

* With this method, if the resulting series has a range of values, * then the resulting series range boundaries will have host values of 0, * but not necessarily all the intervening values. *

* For instance, the 1-byte segment range 4-7 with prefix length 6, * when masked with 252 (the network mask) results in just the single value 4, matching the result of this method. * The 1-byte segment range 4-8 with prefix length 6, * when masked with 252 results in the two non-sequential values, 4 and 8, * but the result of this method with prefix length 6 results in the range 4-8, the same as the original segment. *

* The default behaviour is that the resultant series will have the same prefix length. * The resultant series will not have a prefix length if {@link inet.ipaddr.AddressNetwork#getPrefixConfiguration()} is {@link inet.ipaddr.AddressNetwork.PrefixConfiguration#ALL_PREFIXED_ADDRESSES_ARE_SUBNETS}. * * @return */ public abstract IPAddressSegment toZeroHost(); /** * @deprecated use {@link #toZeroHost()} and {@link #withoutPrefixLength()} * @param zeroed * @return */ @Deprecated public abstract IPAddressSegment removePrefixLength(boolean zeroed); /** * Returns a segment with the same values but without a prefix length. * * @return */ public abstract IPAddressSegment withoutPrefixLength(); protected static S toZeroHost(S original, AddressSegmentCreator creator) { if(original.isPrefixed()) { int lower = original.getSegmentValue(); int upper = original.getUpperSegmentValue(); Integer segmentPrefixLength = original.getSegmentPrefixLength(); int mask = original.getSegmentNetworkMask(segmentPrefixLength); int newLower = lower & mask; int newUpper = upper & mask; boolean allPrefsSubnets = original.getNetwork().getPrefixConfiguration().allPrefixedAddressesAreSubnets(); if(allPrefsSubnets) { return creator.createSegment(newLower, newUpper, null); } if(newLower == lower && newUpper == upper) { return original; } return creator.createSegment(newLower, newUpper, segmentPrefixLength); } else if(original.isZero()) { return original; } return creator.createSegment(0, null); } protected static S removePrefix(S original, boolean zeroed, AddressSegmentCreator creator) { if(original.isPrefixed()) { int lower = original.getSegmentValue(); int upper = original.getUpperSegmentValue(); if(zeroed) { int maskBits = original.getSegmentNetworkMask(original.getSegmentPrefixLength()); long value = original.getDivisionValue(); long upperValue = original.getUpperDivisionValue(); long maxValue = original.getMaxValue(); Masker masker = maskRange(value, upperValue, maskBits, maxValue); if(!masker.isSequential()) { throw new IncompatibleAddressException(original, maskBits, "ipaddress.error.maskMismatch"); } return creator.createSegment((int) masker.getMaskedLower(lower, maskBits), (int) masker.getMaskedUpper(upper, maskBits), null); } return creator.createSegment(lower, upper, null); } return original; } @Override public boolean isBoundedBy(int value) { return getUpperSegmentValue() < value; } public Integer getSegmentPrefixLength() { return getDivisionPrefixLength(); } @Override public int hashCode() { return hash(getSegmentValue(), getUpperSegmentValue(), getBitCount()); } static int hash(int lower, int upper, int bitCount) { return lower | (upper << bitCount); } protected boolean isSameValues(AddressSegment otherSegment) { //note that it is the range of values that matters, the prefix bits do not return getSegmentValue() == otherSegment.getSegmentValue() && getUpperSegmentValue() == otherSegment.getUpperSegmentValue(); } public boolean prefixEquals(IPAddressSegment other) { Integer prefLength = getSegmentPrefixLength(); if(prefLength == null) { return equals(other); } return prefixEquals(other, prefLength); } @Override public boolean prefixEquals(AddressSegment other, int prefixLength) { if(prefixLength < 0) { throw new PrefixLenException(prefixLength); } int shift = getBitCount() - prefixLength; if(shift <= 0) { return isSameValues(other); } return (other.getSegmentValue() >>> shift) == (getSegmentValue() >>> shift) && (other.getUpperSegmentValue() >>> shift) == (getUpperSegmentValue() >>> shift); } /** * Using the prefix length of this segment, or the whole segment if it has no prefix length, * returns whether the prefix bit value ranges contain the same bits of the given segment. * * * @param other * @return */ public boolean prefixContains(IPAddressSegment other) { Integer prefLength = getSegmentPrefixLength(); if(prefLength == null) { return equals(other); } return prefixContains(other, prefLength); } /** * Returns whether the given prefix bit value ranges contain the same bits of the given segment. * * @param other * @param prefixLength * @return */ public boolean prefixContains(IPAddressSegment other, int prefixLength) { if(prefixLength < 0) { throw new PrefixLenException(prefixLength); } int shift = getBitCount() - prefixLength; if(shift <= 0) { return contains(other); } return (other.getSegmentValue() >>> shift) >= (getSegmentValue() >>> shift) && (other.getUpperSegmentValue() >>> shift) <= (getUpperSegmentValue() >>> shift); } /** * * @param other * @return whether this subnet segment contains the given address segment */ protected boolean containsSeg(AddressSegment other) { return other.getSegmentValue() >= getSegmentValue() && other.getUpperSegmentValue() <= getUpperSegmentValue(); } @Override public boolean includesZero() { return getSegmentValue() == 0; } @Override public boolean includesMax() { return getUpperSegmentValue() == getMaxSegmentValue(); } boolean containsPrefixBlock(int lowerVal, int upperVal, int divisionPrefixLen) { return isPrefixBlock(lowerVal, upperVal, divisionPrefixLen); } boolean containsSinglePrefixBlock(int lowerVal, int upperVal, int divisionPrefixLen) { return isSinglePrefixBlock(lowerVal, upperVal, divisionPrefixLen); } @Override protected String getDefaultSegmentWildcardString() { return Address.SEGMENT_WILDCARD_STR; } @Override public String toHexString(boolean with0xPrefix) { return toNormalizedString(with0xPrefix ? IPStringCache.hexPrefixedParams : IPStringCache.hexParams); } @Override public String toNormalizedString() { return toNormalizedString(IPStringCache.canonicalSegmentParams); } public String toNormalizedString(IPStringOptions options) { IPAddressStringWriter params = IPAddressSection.toIPParams(options); StringBuilder builder = new StringBuilder(params.getDivisionStringLength(this)); return params.appendDivision(builder, this).toString(); } protected static int toUnsignedStringLength(int value, int radix) { return AddressDivision.toUnsignedStringLength(value, radix); } protected static StringBuilder toUnsignedString(int value, int radix, StringBuilder appendable) { return toUnsignedStringCased(value, radix, 0, false, appendable); } void setStandardString( CharSequence addressStr, boolean isStandardString, int lowerStringStartIndex, int lowerStringEndIndex, int originalLowerValue) { if(cachedString == null && isStandardString && originalLowerValue == getDivisionValue()) { cachedString = addressStr.subSequence(lowerStringStartIndex, lowerStringEndIndex).toString(); } } void setWildcardString( CharSequence addressStr, boolean isStandardString, int lowerStringStartIndex, int lowerStringEndIndex, int lowerValue) { if(cachedWildcardString == null && isStandardString && lowerValue == getDivisionValue() && lowerValue == getUpperDivisionValue()) { cachedWildcardString = addressStr.subSequence(lowerStringStartIndex, lowerStringEndIndex).toString(); } } void setStandardString( CharSequence addressStr, boolean isStandardString, boolean isStandardRangeString, int lowerStringStartIndex, int lowerStringEndIndex, int upperStringEndIndex, int rangeLower, int rangeUpper) { if(cachedString == null) { if(isSinglePrefixBlock()) { if(isStandardString && rangeLower == getDivisionValue()) { cachedString = addressStr.subSequence(lowerStringStartIndex, lowerStringEndIndex).toString(); } } else if(isFullRange()) { cachedString = IPAddress.SEGMENT_WILDCARD_STR; } else if(isStandardRangeString && rangeLower == getDivisionValue()) { long upper = getUpperDivisionValue(); if(isPrefixed()) { upper &= getDivisionNetworkMask(getDivisionPrefixLength()); } if(rangeUpper == upper) { cachedString = addressStr.subSequence(lowerStringStartIndex, upperStringEndIndex).toString(); } } } } void setWildcardString( CharSequence addressStr, boolean isStandardRangeString, int lowerStringStartIndex, int upperStringEndIndex, int rangeLower, int rangeUpper) { if(cachedWildcardString == null) { if(isFullRange()) { cachedWildcardString = IPAddress.SEGMENT_WILDCARD_STR; } else if(isStandardRangeString && rangeLower == getDivisionValue() && rangeUpper == getUpperDivisionValue()) { cachedWildcardString = addressStr.subSequence(lowerStringStartIndex, upperStringEndIndex).toString(); } } } }