inet.ipaddr.format.AddressDivision Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of ipaddress Show documentation
Show all versions of ipaddress Show documentation
Library for handling IP addresses, both IPv4 and IPv6
/*
* Copyright 2017 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.format;
import java.math.BigInteger;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.Objects;
import inet.ipaddr.Address;
import inet.ipaddr.AddressNetwork.AddressSegmentCreator;
import inet.ipaddr.AddressSegment;
import inet.ipaddr.IncompatibleAddressException;
import inet.ipaddr.IPAddress;
/**
* A division of an address.
*
* @author sfoley
*
*/
public abstract class AddressDivision extends AddressDivisionBase implements Comparable {
private static final long serialVersionUID = 4L;
protected AddressDivision() {}
@Override
protected byte[] getBytesImpl(boolean low) {
int bitCount = getBitCount();
byte bytes[] = new byte[(bitCount + 7) >> 3];
int byteIndex = bytes.length - 1, bitIndex = 8;
long segmentValue = low ? getLowerValue() : getUpperValue();
while(true) {
bytes[byteIndex] |= segmentValue << (8 - bitIndex);
segmentValue >>= bitIndex;
if(bitCount <= bitIndex) {
return bytes;
}
bitCount -= bitIndex;
bitIndex = 8;
byteIndex--;
}
}
/**
* @return whether this segment represents multiple values
*/
@Override
public boolean isMultiple() {
return getLowerValue() != getUpperValue();
}
protected int getMinPrefixLengthForBlock() {
int result = getBitCount();
int lowerZeros = Long.numberOfTrailingZeros(getLowerValue());
if(lowerZeros != 0) {
int upperOnes = Long.numberOfTrailingZeros(~getUpperValue());
if(upperOnes != 0) {
int prefixedBitCount = Math.min(lowerZeros, upperOnes);
result -= prefixedBitCount;
}
}
return result;
}
@Override
protected String getDefaultSegmentWildcardString() {
return Address.SEGMENT_WILDCARD_STR;
}
@Override
protected String getDefaultRangeSeparatorString() {
return Address.RANGE_SEPARATOR_STR;
}
public long getMaxValue() {
return ~(~0L << getBitCount());
}
@Override
public boolean isZero() {
return !isMultiple() && includesZero();
}
@Override
public boolean includesZero() {
return getLowerValue() == 0L;
}
@Override
public boolean isMax() {
return !isMultiple() && includesMax();
}
@Override
public boolean includesMax() {
return getUpperValue() == getMaxValue();
}
public abstract long getLowerValue();
public abstract long getUpperValue();
public long getDivisionValueCount() {
return getUpperValue() - getLowerValue() + 1;
}
public long getDivisionPrefixCount(int divisionPrefixLength) {
int shiftAdjustment = getBitCount() - divisionPrefixLength;
return (getUpperValue() >>> shiftAdjustment) - (getLowerValue() >>> shiftAdjustment) + 1;
}
@Override
public BigInteger getCount() {
return BigInteger.valueOf(getDivisionValueCount());
}
static boolean testRange(long lowerValue, long upperValue, long finalUpperValue, long networkMask, long hostMask) {
return lowerValue == (lowerValue & networkMask)
&& finalUpperValue == (upperValue | hostMask);
}
/**
* Returns whether the division range includes the block of values for its prefix length
*/
boolean isPrefixBlock(long divisionValue, long upperValue, int divisionPrefixLen) {
if(divisionPrefixLen == 0) {
return isFullRange();
}
long ones = ~0L;
long divisionBitMask = ~(ones << getBitCount());
long divisionPrefixMask = ones << (getBitCount() - divisionPrefixLen);
long divisionNonPrefixMask = ~divisionPrefixMask;
return testRange(divisionValue,
upperValue,
upperValue,
divisionPrefixMask & divisionBitMask,
divisionNonPrefixMask);
}
/**
*
* @param divisionValue
* @param divisionPrefixLen
* @return whether the given range of segmentValue to upperValue is equivalent to the range of segmentValue with the prefix of divisionPrefixLen
*/
boolean isSinglePrefixBlock(long divisionValue, long upperValue, int divisionPrefixLen) {
long ones = ~0L;
long divisionBitMask = ~(ones << getBitCount());
long divisionPrefixMask = ones << (getBitCount() - divisionPrefixLen);
long divisionNonPrefixMask = ~divisionPrefixMask;
return testRange(divisionValue,
divisionValue,
upperValue,
divisionPrefixMask & divisionBitMask,
divisionNonPrefixMask);
}
/**
* Returns true if the possible values of this division fall below the given value.
*/
@Override
public boolean isBoundedBy(int value) {
return getUpperValue() < value;
}
public boolean matches(long value) {
return !isMultiple() && value == getLowerValue();
}
public boolean matchesWithMask(long value, long mask) {
if(isMultiple()) {
//we want to ensure that any of the bits that can change from value to upperValue is masked out (zeroed) by the mask.
//In other words, when masked we need all values represented by this segment to become just a single value
long diffBits = getLowerValue() ^ getUpperValue();
int leadingZeros = Long.numberOfLeadingZeros(diffBits);
//the bits that can change are all bits following the first leadingZero bits
//all the bits that follow must be zeroed out by the mask
long fullMask = ~0L >>> leadingZeros;
if((fullMask & mask) != 0L) {
return false;
} //else we know that the mask zeros out all the bits that can change from value to upperValue, so now we just compare with either one
}
return value == (getLowerValue() & mask);
}
/**
* returns whether masking with the given mask results in a valid contiguous range for this segment,
* and if it does, if it matches the range obtained when masking the given values with the same mask.
*
* @param lowerValue
* @param upperValue
* @param mask
* @return
*/
public boolean matchesWithMask(long lowerValue, long upperValue, long mask) {
if(lowerValue == upperValue) {
return matchesWithMask(lowerValue, mask);
}
if(!isMultiple()) {
//we know lowerValue and upperValue are not the same, so impossible to match those two values with a single value
return false;
}
long thisValue = getLowerValue();
long thisUpperValue = getUpperValue();
if(!isMaskCompatibleWithRange(thisValue, thisUpperValue, mask, getMaxValue())) {
return false;
}
return lowerValue == (thisValue & mask) && upperValue == (thisUpperValue & mask);
}
protected abstract boolean isSameValues(AddressDivision other);
@Override
public boolean isFullRange() {
return includesZero() && includesMax();
}
@Override
public int compareTo(AddressDivision other) {
return Address.DEFAULT_ADDRESS_COMPARATOR.compare(this, other);
}
//when divisionPrefixLen is null, isAutoSubnets has no effect
protected static boolean isMaskCompatibleWithRange(long value, long upperValue, long maskValue, long maxValue) {
if(value == upperValue || maskValue == maxValue || maskValue == 0) {
return true;
}
//algorithm:
//here we find the highest bit that is part of the range, highestDifferingBitInRange (ie changes from lower to upper)
//then we find the highest bit in the mask that is 1 that is the same or below highestDifferingBitInRange (if such a bit exists)
//this gives us the highest bit that is part of the masked range (ie changes from lower to upper after applying the mask)
//if this latter bit exists, then any bit below it in the mask must be 1 to include the entire range.
long differing = value ^ upperValue;
boolean foundDiffering = (differing != 0);
boolean differingIsLowestBit = (differing == 1);
if(foundDiffering && !differingIsLowestBit) {
int highestDifferingBitInRange = Long.numberOfLeadingZeros(differing);
long maskMask = ~0L >>> highestDifferingBitInRange;
long differingMasked = maskValue & maskMask;
foundDiffering = (differingMasked != 0);
differingIsLowestBit = (differingMasked == 1);
if(foundDiffering && !differingIsLowestBit) {
//anything below highestDifferingBitMasked in the mask must be ones
//Also, if we have masked out any 1 bit in the original, then anything that we do not mask out that follows must be all 1s
int highestDifferingBitMasked = Long.numberOfLeadingZeros(differingMasked);
long hostMask = ~0L >>> (highestDifferingBitMasked + 1);//for the first mask bit that is 1, all bits that follow must also be 1
if((maskValue & hostMask) != hostMask) { //check if all ones below
return false;
}
if(highestDifferingBitMasked > highestDifferingBitInRange) {
//We have masked out a 1 bit, so we need to check that all bits in upper value that we do not mask out are also 1 bits, otherwise we end up missing values in the masked range
//This check is unnecessary for prefix-length subnets, only non-standard ranges might fail this check.
//For instance, if we have range 0000 to 1010
//and we mask upper and lower with 0111
//we get 0000 to 0010, but 0111 was in original range, and the mask of that value retains that value
//so that value needs to be in final range, and it's not.
//What went wrong is that we masked out the top bit, and any other bit that is not masked out must be 1.
//To work, our original range needed to be 0000 to 1111, with the three 1s following the first masked-out 1
long hostMaskUpper = ~0L >>> highestDifferingBitMasked;
if((upperValue & hostMaskUpper) != hostMaskUpper) {
return false;
}
}
}
}
return true;
}
protected static boolean isBitwiseOrCompatibleWithRange(long value, long upperValue, long maskValue, long maxValue) {
if(value == upperValue || maskValue == maxValue || maskValue == 0) {
return true;
}
//algorithm:
//here we find the highest bit that is part of the range, highestDifferingBitInRange (ie changes from lower to upper)
//then we find the highest bit in the mask that is 0 that is the same or below highestDifferingBitInRange (if such a bit exists)
//this gives us the highest bit that is part of the masked range (ie changes from lower to upper after applying the mask)
//if this latter bit exists, then any bit below it in the mask must be 0 to include the entire range.
long differing = value ^ upperValue;
boolean foundDiffering = (differing != 0);
boolean differingIsLowestBit = (differing == 1);
if(foundDiffering && !differingIsLowestBit) {
int highestDifferingBitInRange = Long.numberOfLeadingZeros(differing);
long maskMask = ~0L >>> highestDifferingBitInRange;
long differingMasked = maskValue & maskMask;
foundDiffering = (differingMasked != maskMask);
differingIsLowestBit = ((differingMasked | 1) == maskMask);
if(foundDiffering && !differingIsLowestBit) {
//anything below highestDifferingBitMasked in the mask must be zeros
//Also, if we or'ed out any 0 bit in the original with a 1 in the mask, then anything that we do not mask out that follows must be all 0s
int highestDifferingBitMasked = Long.numberOfLeadingZeros(~differingMasked & maskMask);
long hostMask = ~0L >>> (highestDifferingBitMasked + 1);
if((maskValue & hostMask) != 0) { //check if all zeros below
return false;
}
if(highestDifferingBitMasked > highestDifferingBitInRange) {
//we have or-ed out a 0 bit, so we need to check that all bits in lower value that we do not or out are also 0 bits, otherwise we end up missing values in the masked range
//this is always true for prefix subnets, only non-standard ranges might fail here
long hostMaskLower = ~0L >>> highestDifferingBitMasked;
if((value & hostMaskLower) != 0) {
return false;
}
}
}
}
return true;
}
public boolean hasUppercaseVariations(int radix, boolean lowerOnly) {
if(radix <= 1) {
throw new IllegalArgumentException();
}
if(radix <= 10) {
return false;
}
boolean isPowerOfTwo;
int shift = 0;
long mask = 0;
switch(radix) {
case 0x10://fast path for base 16
isPowerOfTwo = true;
shift = 4; //log2(base)
mask = 0xf; //2^shift - 1
break;
default:
isPowerOfTwo = (radix & (radix - 1)) == 0;
if(isPowerOfTwo) {
shift = Integer.numberOfTrailingZeros(radix);
mask = ~(~0L << shift); //allBitSize must be 6 digits at most for this shift to work per the java spec (so it must be less than 2^6 = 64)
}
}
boolean handledUpper = false;
long value = getLowerValue();
do {
while(value > 0) {
long checkVal = isPowerOfTwo ? (mask & value) : (value % radix);
if(checkVal >= 0xa) {
return true;
}
if(isPowerOfTwo) {
value >>>= shift;
} else {
value /= radix;
}
}
if(handledUpper || lowerOnly) {
break;
}
value = getUpperValue();
handledUpper = true;
} while(true);
return false;
}
@Override
public int getDigitCount(int radix) {
if(!isMultiple() && radix == getDefaultTextualRadix()) {//optimization - just get the string, which is cached, which speeds up further calls to this or getString()
return getWildcardString().length();
}
return getDigitCount(getUpperValue(), radix);
}
@Override
public int getMaxDigitCount(int radix) {
int defaultRadix = getDefaultTextualRadix();
if(radix == defaultRadix) {
return getMaxDigitCount();
}
return getMaxDigitCount(radix, getBitCount(), getMaxValue());
}
@Override
protected int adjustLowerLeadingZeroCount(int leadingZeroCount, int radix) {
return adjustLeadingZeroCount(leadingZeroCount, getLowerValue(), radix);
}
@Override
protected int adjustUpperLeadingZeroCount(int leadingZeroCount, int radix) {
return adjustLeadingZeroCount(leadingZeroCount, getUpperValue(), radix);
}
private int adjustLeadingZeroCount(int leadingZeroCount, long value, int radix) {
if(leadingZeroCount < 0) {
int width = getDigitCount(value, radix);
return Math.max(0, getMaxDigitCount(radix) - width);
}
return leadingZeroCount;
}
@Override
protected int getLowerStringLength(int radix) {
return toUnsignedStringLength(getLowerValue(), radix);
}
@Override
protected int getUpperStringLength(int radix) {
return toUnsignedStringLength(getUpperValue(), radix);
}
@Override
protected void getLowerString(int radix, boolean uppercase, StringBuilder appendable) {
toUnsignedString(getLowerValue(), radix, 0, uppercase, uppercase ? UPPERCASE_DIGITS : DIGITS, appendable);
}
@Override
protected void getUpperString(int radix, boolean uppercase, StringBuilder appendable) {
toUnsignedString(getUpperValue(), radix, 0, uppercase, uppercase ? UPPERCASE_DIGITS : DIGITS, appendable);
}
@Override
protected void getUpperStringMasked(int radix, boolean uppercase, StringBuilder appendable) {
getUpperString(radix, uppercase, appendable);
}
@Override
protected void getLowerString(int radix, int rangeDigits, boolean uppercase, StringBuilder appendable) {
toUnsignedString(getLowerValue(), radix, rangeDigits, uppercase, uppercase ? UPPERCASE_DIGITS : DIGITS, appendable);
}
@Override
protected void getSplitLowerString(int radix, int choppedDigits, boolean uppercase,
char splitDigitSeparator, boolean reverseSplitDigits, String stringPrefix, StringBuilder appendable) {
toSplitUnsignedString(getLowerValue(), radix, choppedDigits, uppercase, splitDigitSeparator, reverseSplitDigits, stringPrefix, appendable);
}
@Override
protected void getSplitRangeString(String rangeSeparator, String wildcard, int radix, boolean uppercase,
char splitDigitSeparator, boolean reverseSplitDigits, String stringPrefix, StringBuilder appendable) {
toUnsignedSplitRangeString(
getLowerValue(),
getUpperValue(),
rangeSeparator,
wildcard,
radix,
uppercase,
splitDigitSeparator,
reverseSplitDigits,
stringPrefix,
appendable);
}
@Override
protected int getSplitRangeStringLength(String rangeSeparator, String wildcard, int leadingZeroCount, int radix, boolean uppercase,
char splitDigitSeparator, boolean reverseSplitDigits, String stringPrefix) {
return toUnsignedSplitRangeStringLength(
getLowerValue(),
getUpperValue(),
rangeSeparator,
wildcard,
leadingZeroCount,
radix,
uppercase,
splitDigitSeparator,
reverseSplitDigits,
stringPrefix);
}
@Override
protected String getDefaultString() {
return toDefaultString(getLowerValue(), getDefaultTextualRadix());
}
@Override
protected String getDefaultRangeString() {
return getDefaultRangeString(getLowerValue(), getUpperValue(), getDefaultTextualRadix());
}
protected String getDefaultRangeString(long val1, long val2, int radix) {
int len1, len2, value1, value2, quotient, remainder; //we iterate on //value == quotient * radix + remainder
if(radix == 10) {
if(val2 < 10) {
len2 = 1;
} else if(val2 < 100) {
len2 = 2;
} else if(val2 < 1000) {
len2 = 3;
} else {
return buildDefaultRangeString(radix);
}
value2 = (int) val2;
if(val1 < 10) {
len1 = 1;
} else if(val1 < 100) {
len1 = 2;
} else if(val1 < 1000) {
len1 = 3;
} else {
return buildDefaultRangeString(radix);
}
value1 = (int) val1;
len2 += len1 + 1;
char chars[] = new char[len2];
chars[len1] = IPAddress.RANGE_SEPARATOR;
char dig[] = DIGITS;
do {
//value == quotient * 10 + remainder
quotient = (value1 * 0xcccd) >>> 19; //floor of n/10 is floor of ((0xcccd * n / (2 ^ 16)) / (2 ^ 3))
remainder = value1 - ((quotient << 3) + (quotient << 1)); //multiplication by 2 added to multiplication by 2 ^ 3 is multiplication by 2 + 8 = 10
chars[--len1] = dig[remainder];
value1 = quotient;
} while(value1 != 0);
do {
quotient = (value2 * 0xcccd) >>> 19;
remainder = value2 - ((quotient << 3) + (quotient << 1));
chars[--len2] = dig[remainder];
value2 = quotient;
} while(value2 != 0);
return new String(chars);
}
if(radix == 16) {
if(val2 < 0x10) {
len2 = 1;
} else if(val2 < 0x100) {
len2 = 2;
} else if(val2 < 0x1000) {
len2 = 3;
} else if(val2 < 0x10000) {
len2 = 4;
} else {
return buildDefaultRangeString(radix);
}
value2 = (int) val2;
if(val1 < 0x10) {
len1 = 1;
} else if(val1 < 0x100) {
len1 = 2;
} else if(val1 < 0x1000) {
len1 = 3;
} else if(val1 < 0x10000) {
len1 = 4;
} else {
return buildDefaultRangeString(radix);
}
value1 = (int) val1;
len2 += len1 + 1;
char chars[] = new char[len2];
chars[len1] = IPAddress.RANGE_SEPARATOR;
char dig[] = DIGITS;
do {//value1 == quotient * 16 + remainder
quotient = value1 >>> 4;
remainder = value1 - (quotient << 4);
chars[--len1] = dig[remainder];
value1 = quotient;
} while(value1 != 0);
do {
quotient = value2 >>> 4;
remainder = value2 - (quotient << 4);
chars[--len2] = dig[remainder];
value2 = quotient;
} while(value2 != 0);
return new String(chars);
}
return buildDefaultRangeString(radix);
}
private String buildDefaultRangeString(int radix) {
StringBuilder builder = new StringBuilder(20);
getRangeString(IPAddress.RANGE_SEPARATOR_STR, 0, 0, "", radix, false, false, builder);
return builder.toString();
}
protected static String toDefaultString(long val, int radix) {
//0 and 1 are common segment values, and additionally they are the same regardless of radix (even binary)
//so we have a fast path for them
if(val == 0L) {
return "0";
}
if(val == 1L) {
return "1";
}
int len, quotient, remainder, value; //we iterate on //value == quotient * radix + remainder
if(radix == 10) {
if(val < 10) {
return String.valueOf(DIGITS, (int) val, 1);
} else if(val < 100) {
len = 2;
value = (int) val;
} else if(val < 1000) {
len = 3;
value = (int) val;
} else {
return Long.toString(val, radix);
}
char chars[] = new char[len];
char dig[] = DIGITS;
do {
//value == quotient * 10 + remainder
quotient = (value * 0xcccd) >>> 19; //floor of n/10 is floor of ((0xcccd * n / (2 ^ 16)) / (2 ^ 3))
remainder = value - ((quotient << 3) + (quotient << 1)); //multiplication by 2 added to multiplication by 2 ^ 3 is multiplication by 2 + 8 = 10
chars[--len] = dig[remainder];
value = quotient;
} while(value != 0);
return new String(chars);
}
if(radix == 16) {
if(val < 0x10) {
return String.valueOf(DIGITS, (int) val, 1);
} else if(val < 0x100) {
len = 2;
value = (int) val;
} else if(val < 0x1000) {
len = 3;
value = (int) val;
} else if(val < 0x10000) {
if(val == 0xffff) {
return "ffff";
}
value = (int) val;
len = 4;
} else {
return Long.toString(val, radix);
}
char chars[] = new char[len];
char dig[] = DIGITS;
do {//value2 == quotient * 16 + remainder
quotient = value >>> 4;
remainder = value - (quotient << 4);
chars[--len] = dig[remainder];
value = quotient;
} while(value != 0);
return new String(chars);
}
return Long.toString(val, radix);
}
private static boolean toUnsignedStringFast(int value, int radix, int choppedDigits, boolean uppercase, char dig[], StringBuilder appendable) {
if(toUnsignedStringFast(value, radix, uppercase, dig, appendable)) {
if(choppedDigits > 0) {
appendable.setLength(appendable.length() - choppedDigits);
}
return true;
}
return false;
}
private static boolean toUnsignedStringFast(int value, int radix, boolean uppercase, char dig[], StringBuilder appendable) {
if(value <= 1) {//for values larger than 1, result can be different with different radix (radix is 2 and up)
if(value == 0) {
appendable.append('0');
} else {
appendable.append('1');
}
return true;
}
int quotient, remainder; //we iterate on //value == quotient * radix + remainder
if(radix == 10) {
//this needs value2 <= 0xffff (ie 16 bits or less)
if(value < 10) {
appendable.append(dig[value]);
return true;
} else if(value < 100) {
appendable.append(" ");
} else if(value < 1000) {
if(value == 127) {
appendable.append("127");
return true;
}
if(value == 255) {
appendable.append("255");
return true;
}
appendable.append(" ");
} else if(value < 10000) {
appendable.append(" ");
} else {
appendable.append(" ");
}
int index = appendable.length();
do {
//value == quotient * 10 + remainder
quotient = (value * 0xcccd) >>> 19; //floor of n/10 is floor of ((0xcccd * n / 2 ^ 16) / 2 ^ 3)
remainder = value - ((quotient << 3) + (quotient << 1)); //multiplication by 2 added to multiplication by 2 ^ 3 is multiplication by 2 + 8 = 10
appendable.setCharAt(--index, dig[remainder]);
value = quotient;
} while(value != 0);
return true;
}
if(radix == 16) {
if(value < 0xa) {
appendable.append(dig[value]);
return true;
} else if(value < 0x10) {
appendable.append(dig[value]);
return true;
} else if(value < 0x100) {
appendable.append(" ");
} else if(value < 0x1000) {
appendable.append(" ");
} else {
if(value == 0xffff) {
appendable.append(uppercase ? "FFFF" : "ffff");
return true;
}
appendable.append(" ");
}
int index = appendable.length();
do {//value2 == quotient * 16 + remainder
quotient = value >>> 4;
remainder = value - (quotient << 4);
appendable.setCharAt(--index, dig[remainder]);
value = quotient;
} while(value != 0);
return true;
}
if(radix == 8) {
if(value < 010) {
appendable.append(dig[value]);
return true;
} else if(value < 0100) {
appendable.append(" ");
} else if(value < 01000) {
appendable.append(" ");
} else if(value < 010000) {
appendable.append(" ");
} else if(value < 0100000) {
appendable.append(" ");
} else {
appendable.append(" ");
}
int index = appendable.length();
do {//value2 == quotient * 16 + remainder
quotient = value >>> 3;
remainder = value - (quotient << 3);
appendable.setCharAt(--index, dig[remainder]);
value = quotient;
} while(value != 0);
return true;
}
if(radix == 2) {
//count the number of digits
//note that we already know value != 0 and that value <= 0xffff
//and we use both of those facts
int digitCount = 15;
int val = value;
if (val >>> 8 == 0) {
digitCount -= 8;
} else {
val >>>= 8;
}
if (val >>> 4 == 0) {
digitCount -= 4;
} else {
val >>>= 4;
}
if (val >>> 2 == 0) {
digitCount -= 2;
} else {
val >>>= 2;
}
//at this point, if (val & 2) != 0 we have undercounted the digit count by 1
//either way, we start with the first digit '1' and adjust the digit count accordingly
if((val & 2) == 0) {
--digitCount;
}
appendable.append('1');
while(digitCount > 0) {
char c = dig[(value >>> --digitCount) & 1];
appendable.append(c);
}
return true;
}
return false;
}
protected static StringBuilder toUnsignedString(long value, int radix, int choppedDigits, boolean uppercase, char dig[], StringBuilder appendable) {
if(value > 0xffff || !toUnsignedStringFast((int) value, radix, choppedDigits, uppercase, dig, appendable)) {
toUnsignedString(value, radix, choppedDigits, dig, appendable);
}
return appendable;
}
private static int toUnsignedSplitRangeStringLength(
long lower,
long upper,
String rangeSeparator,
String wildcard,
int leadingZerosCount,
int radix,
boolean uppercase,
char splitDigitSeparator,
boolean reverseSplitDigits,
String stringPrefix) {
int digitsLength = -1;//we will count one too many split digit separators in here
int stringPrefixLength = stringPrefix.length();
do {
int upperDigit = (int) (upper % radix);
int lowerDigit = (int) (lower % radix);
boolean isFull = (lowerDigit == 0) && (upperDigit == radix - 1);
if(isFull) {
digitsLength += wildcard.length() + 1;
} else {
//if not full range, they must not be the same either, otherwise they would be illegal for split range.
//this is because we know whenever entering the loop that upper != lower, and we know this also means the least significant digits must differ.
digitsLength += (stringPrefixLength << 1) + 4 /* 1 for each digit, 1 for range separator, 1 for split digit separator */;
}
upper /= radix;
lower /= radix;
} while(upper != lower);
int remaining = (upper == 0) ? 0 : toUnsignedStringLength(upper, radix);
remaining += leadingZerosCount;
if(remaining > 0) {
digitsLength += remaining * (stringPrefixLength + 2 /* one for each splitDigitSeparator, 1 for each digit */);
}
return digitsLength;
}
protected static int toUnsignedStringLength(long value, int radix) {
int result;
if(value > 0xffff || (result = toUnsignedStringLengthFast((int) value, radix)) < 0) {
result = toUnsignedStringLengthSlow(value, radix);
}
return result;
}
private static int toUnsignedStringLengthSlow(long value, int radix) {
int count = 1;
boolean useInts = value <= Integer.MAX_VALUE;
int value2 = useInts ? (int) value : radix;
while(value2 >= radix) {
if(useInts) {
value2 /= radix;
} else {
value /= radix;
if(value <= Integer.MAX_VALUE) {
useInts = true;
value2 = (int) value;
}
}
++count;
}
return count;
}
protected static int toUnsignedStringLengthFast(int value, int radix) {
if(value <= 1) {//for values larger than 1, result can be different with different radix (radix is 2 and up)
return 1;
}
if(radix == 10) {
//this needs value <= 0xffff (ie 16 bits or less) which is a prereq to calling this method
if(value < 10) {
return 1;
} else if(value < 100) {
return 2;
} else if(value < 1000) {
return 3;
} else if(value < 10000) {
return 4;
}
return 5;
}
if(radix == 16) {
//this needs value <= 0xffff (ie 16 bits or less)
if(value < 0x10) {
return 1;
} else if(value < 0x100) {
return 2;
} else if(value < 0x1000) {
return 3;
}
return 4;
}
if(radix == 8) {
//this needs value <= 0xffff (ie 16 bits or less)
if(value < 010) {
return 1;
} else if(value < 0100) {
return 2;
} else if(value < 01000) {
return 3;
} else if(value < 010000) {
return 4;
} else if(value < 0100000) {
return 5;
}
return 6;
}
if(radix == 2) {
//count the number of digits
//note that we already know value != 0 and that value <= 0xffff
//and we use both of those facts
int digitCount = 15;
int val = value;
if (val >>> 8 == 0) {
digitCount -= 8;
} else {
val >>>= 8;
}
if (val >>> 4 == 0) {
digitCount -= 4;
} else {
val >>>= 4;
}
if (val >>> 2 == 0) {
digitCount -= 2;
} else {
val >>>= 2;
}
//at this point, if (val & 2) != 0 we have undercounted the digit count by 1
if((val & 2) != 0) {
++digitCount;
}
return digitCount;
}
return -1;
}
private static void toUnsignedString(
long value,
int radix,
int choppedDigits,
char dig[],
StringBuilder appendable) {
int front = appendable.length();
appendDigits(value, radix, choppedDigits, dig, appendable);
int back = appendable.length() - 1;
while(front < back) {
char frontChar = appendable.charAt(front);
appendable.setCharAt(front++, appendable.charAt(back));
appendable.setCharAt(back--, frontChar);
}
}
private static void toSplitUnsignedString(
long value,
int radix,
int choppedDigits,
boolean uppercase,
char splitDigitSeparator,
boolean reverseSplitDigits,
String stringPrefix,
StringBuilder appendable) {
int front = appendable.length();
appendDigits(value, radix, choppedDigits, uppercase, splitDigitSeparator, stringPrefix, appendable);
if(!reverseSplitDigits) {
int back = appendable.length() - 1;
int stringPrefixLen = stringPrefix.length();
front += stringPrefixLen;
while(front < back) {
char frontChar = appendable.charAt(front);
appendable.setCharAt(front, appendable.charAt(back));
appendable.setCharAt(back, frontChar);
front += 2;
back -= 2;
front += stringPrefixLen;
back -= stringPrefixLen;
}
}
}
private static void toUnsignedSplitRangeString(
long lower,
long upper,
String rangeSeparator,
String wildcard,
int radix,
boolean uppercase,
char splitDigitSeparator,
boolean reverseSplitDigits,
String stringPrefix,
StringBuilder appendable) {
//A split can be invalid. Consider xxx.456-789.
//The number 691, which is in the range 456-789, is not in the range 4-7.5-8.6-9
//In such cases we throw IncompatibleAddressException
//To avoid such cases, we must have lower digits covering the full range, for example 400-799 in which lower digits are both 0-9 ranges.
//If we have 401-799 then 500 will not be included when splitting.
//If we have 400-798 then 599 will not be included when splitting.
//If we have 410-799 then 500 will not be included when splitting.
//If we have 400-789 then 599 will not be included when splitting.
int front = appendable.length();
appendDigits(lower, upper, rangeSeparator, wildcard, radix, uppercase, splitDigitSeparator, reverseSplitDigits, stringPrefix, appendable);
if(!reverseSplitDigits) {
int back = appendable.length() - 1;
while(front < back) {
char frontChar = appendable.charAt(front);
appendable.setCharAt(front++, appendable.charAt(back));
appendable.setCharAt(back--, frontChar);
}
}
}
private static void appendDigits(
long value,
int radix,
int choppedDigits,
char dig[],
StringBuilder appendable) {
boolean useInts = value <= Integer.MAX_VALUE;
int value2 = useInts ? (int) value : radix;
int index;
while(value2 >= radix) {
if(useInts) {
int val2 = value2;
value2 /= radix;
if(choppedDigits > 0) {
choppedDigits--;
continue;
}
index = val2 % radix;
} else {
long val = value;
value /= radix;
if(value <= Integer.MAX_VALUE) {
useInts = true;
value2 = (int) value;
}
if(choppedDigits > 0) {
choppedDigits--;
continue;
}
index = (int) (val % radix);
}
appendable.append(dig[index]);
}
if(choppedDigits == 0) {
appendable.append(dig[value2]);
}
}
private static void appendDigits(
long value,
int radix,
int choppedDigits,
boolean uppercase,
char splitDigitSeparator,
String stringPrefix,
StringBuilder appendable) {
boolean useInts = value <= Integer.MAX_VALUE;
int value2 = useInts ? (int) value : radix;
char dig[] = uppercase ? UPPERCASE_DIGITS : DIGITS;
int index;
int prefLen = stringPrefix.length();
while(value2 >= radix) {
if(useInts) {
int val = value2;
value2 /= radix;
if(choppedDigits > 0) {
choppedDigits--;
continue;
}
index = val % radix;
} else {
long val = value;
value /= radix;
if(value <= Integer.MAX_VALUE) {
useInts = true;
value2 = (int) value;
}
if(choppedDigits > 0) {
choppedDigits--;
continue;
}
index = (int) (val % radix);
}
if(prefLen > 0) {
appendable.append(stringPrefix);
}
appendable.append(dig[index]);
appendable.append(splitDigitSeparator);
}
if(choppedDigits == 0) {
if(prefLen > 0) {
appendable.append(stringPrefix);
}
appendable.append(dig[value2]);
}
}
private static void appendDigits(
long lower,
long upper,
String rangeSeparator,
String wildcard,
int radix,
boolean uppercase,
char splitDigitSeparator,
boolean reverseSplitDigits,
String stringPrefix,
StringBuilder appendable) {
char dig[] = uppercase ? UPPERCASE_DIGITS : DIGITS;
boolean previousWasFullRange = true;
boolean useInts = upper <= Integer.MAX_VALUE;
int upperInt, lowerInt;
if(useInts) {
upperInt = (int) upper;
lowerInt = (int) lower;
} else {
upperInt = lowerInt = radix;
}
int prefLen = stringPrefix.length();
while(true) {
int upperDigit, lowerDigit;
if(useInts) {
int ud = upperInt;
upperDigit = upperInt % radix;
upperInt /= radix;
if(ud == lowerInt) {
lowerInt = upperInt;
lowerDigit = upperDigit;
} else {
lowerDigit = lowerInt % radix;
lowerInt /= radix;
}
} else {
long ud = upper;
upperDigit = (int) (upper % radix);
upper /= radix;
if(ud == lower) {
lower = upper;
lowerDigit = upperDigit;
} else {
lowerDigit = (int) (lower % radix);
lower /= radix;
}
if(upper <= Integer.MAX_VALUE) {
useInts = true;
upperInt = (int) upper;
lowerInt = (int) lower;
}
}
if(lowerDigit == upperDigit) {
previousWasFullRange = false;
if(reverseSplitDigits) {
if(prefLen > 0) {
appendable.append(stringPrefix);
}
appendable.append(dig[lowerDigit]);
} else {
//in this case, whatever we do here will be completely reversed following this method call
appendable.append(dig[lowerDigit]);
for(int k = prefLen - 1; k >= 0; k--) {
appendable.append(stringPrefix.charAt(k));
}
}
} else {
if(!previousWasFullRange) {
throw new IncompatibleAddressException(lower, upper, "ipaddress.error.splitMismatch");
}
previousWasFullRange = (lowerDigit == 0) && (upperDigit == radix - 1);
if(previousWasFullRange && wildcard != null) {
if(reverseSplitDigits) {
appendable.append(wildcard);
} else {
//in this case, whatever we do here will be completely reversed following this method call
for(int k = wildcard.length() - 1; k >= 0; k--) {
appendable.append(wildcard.charAt(k));
}
}
} else {
if(reverseSplitDigits) {
if(prefLen > 0) {
appendable.append(stringPrefix);
}
appendable.append(dig[lowerDigit]);
appendable.append(rangeSeparator);
appendable.append(dig[upperDigit]);
} else {
//in this case, whatever we do here will be completely reversed following this method call
appendable.append(dig[upperDigit]);
appendable.append(rangeSeparator);
appendable.append(dig[lowerDigit]);
for(int k = prefLen - 1; k >= 0; k--) {
appendable.append(stringPrefix.charAt(k));
}
}
}
}
if(upperInt == 0) {
break;
}
appendable.append(splitDigitSeparator);
}
}
@Override
protected int getRangeDigitCount(int radix) {
if(!isMultiple()) {
return 0;
}
if(radix == getDefaultTextualRadix()) {
return getRangeDigitCountImpl();
}
return calculateRangeDigitCount(radix, getLowerValue(), getUpperValue(), getMaxValue());
}
protected int getRangeDigitCountImpl() {
return calculateRangeDigitCount(getDefaultTextualRadix(), getLowerValue(), getUpperValue(), getMaxValue());
}
private static int calculateRangeDigitCount(int radix, long value, long upperValue, long maxValue) {
int factor = radix;
int numDigits = 1;
while(true) {
long lowerRemainder = value % factor;
if(lowerRemainder == 0) {
//Consider in ipv4 the segment 24_
//what does this mean? It means 240 to 249 (not 240 to 245)
//Consider 25_. It means 250-255.
//so the last digit ranges between 0-5 or 0-9 depending on whether the front matches the max possible front of 25.
//If the front matches, the back ranges from 0 to the highest value of 255.
//if the front does not match, the back must range across all values for the radix (0-9)
long max = (maxValue / factor == upperValue / factor) ? maxValue % factor : factor - 1;
long upperRemainder = upperValue % factor;
if(upperRemainder == max) {
//whatever range there is must be accounted entirely by range digits, otherwise the range digits is 0
//so here we check if that is the case
if(upperValue - upperRemainder == value) {
return numDigits;
} else {
numDigits++;
factor *= radix;
continue;
}
}
}
return 0;
}
}
protected static int reverseBits(byte b) {
int x = b;
x = ((x & 0xaa) >>> 1) | ((x & 0x55) << 1);
x = ((x & 0xcc) >>> 2) | ((x & 0x33) << 2);
x = (0xff & ((x >>> 4) | (x << 4)));
return x;
}
protected static int reverseBits(short b) {
int x = b;
x = ((x & 0xaaaa) >>> 1) | ((x & 0x5555) << 1);
x = ((x & 0xcccc) >>> 2) | ((x & 0x3333) << 2);
x = ((x & 0xf0f0) >>> 4) | ((x & 0x0f0f) << 4);
return 0xffff & ((x >>> 8) | (x << 8));
}
protected static int reverseBits(int i) {
int x = i;
x = ((x & 0xaaaaaaaa) >>> 1) | ((x & 0x55555555) << 1);
x = ((x & 0xcccccccc) >>> 2) | ((x & 0x33333333) << 2);
x = ((x & 0xf0f0f0f0) >>> 4) | ((x & 0x0f0f0f0f) << 4);
x = ((x & 0xff00ff00) >>> 8) | ((x & 0x00ff00ff) << 8);
return (x >>> 16) | (x << 16);
}
protected static Iterator iterator(
S original,
AddressSegmentCreator creator,
boolean returnThisSegment,
Integer networkIteratorSegmentPrefixLength) {
boolean useShiftAdjustment = networkIteratorSegmentPrefixLength != null;
int shiftAdjustment, shiftMask, upperShiftMask;
int lower = original.getLowerSegmentValue();
int upper = original.getUpperSegmentValue();
if(useShiftAdjustment) {
shiftAdjustment = original.getBitCount() - networkIteratorSegmentPrefixLength;
shiftMask = ~0 << shiftAdjustment;
upperShiftMask = ~shiftMask;
if(returnThisSegment) {
int newLow = shiftMask & lower;
int newUp = upper | upperShiftMask;
if(lower != newLow || upper != newUp) {
returnThisSegment = false;
lower = newLow;
upper = newUp;
}
}
} else {
shiftAdjustment = shiftMask = upperShiftMask = 0;
}
boolean returnThis = returnThisSegment;
int lowerValue = lower;
int upperValue = upper;
if(!original.isMultiple()) {
return new Iterator() {
boolean done;
@Override
public boolean hasNext() {
return !done;
}
@Override
public S next() {
if(!hasNext()) {
throw new NoSuchElementException();
}
done = true;
//Even though a segment represents a single value, it still might have a prefix extending to the end of the segment
//Iterators must return non-prefixed segments.
//This is required by the IPAddressSection iterator which uses an array of segment iterators.
//If the segments at the end with prefixes of 0 iterate through all values with no prefix,
//then so must the preceding segment with a non-zero prefix,
//even if that non-zero prefix extends to the end of the segment.
if(!returnThis) {
S result = creator.createSegment(lowerValue, upperValue, networkIteratorSegmentPrefixLength);
return result;
}
return original;
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
};
}
return new Iterator() {
boolean done;
int current = lowerValue, last = upperValue; {
if(useShiftAdjustment) {
current >>>= shiftAdjustment;
last >>>= shiftAdjustment;
}
}
@Override
public boolean hasNext() {
return !done;
}
@Override
public S next() {
if(done) {
throw new NoSuchElementException();
}
S result;
if(useShiftAdjustment) {
int low = current << shiftAdjustment;
result = creator.createSegment(low, low | upperShiftMask, networkIteratorSegmentPrefixLength);
} else {
result = creator.createSegment(current);
}
done = ++current > last;
return result;
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
};
}
protected static S setPrefixedSegment(
S original,
Integer oldSegmentPrefixLength,
Integer newSegmentPrefixLength,
boolean zeroed,
AddressSegmentCreator creator) {
if(Objects.equals(oldSegmentPrefixLength, newSegmentPrefixLength)) {
return original;
}
int newLower, newUpper;
if(zeroed) {
int prefixMask;
int bitCount = original.getBitCount();
int allOnes = ~0;
if(oldSegmentPrefixLength != null) {
if(newSegmentPrefixLength == null) {
prefixMask = allOnes << (bitCount - oldSegmentPrefixLength);
} else if(oldSegmentPrefixLength > newSegmentPrefixLength) {
prefixMask = allOnes << (bitCount - newSegmentPrefixLength);
prefixMask |= ~(allOnes << (bitCount - oldSegmentPrefixLength));
} else {
prefixMask = allOnes << (bitCount - oldSegmentPrefixLength);
prefixMask |= ~(allOnes << (bitCount - newSegmentPrefixLength));
}
} else {
//we know newSegmentPrefixLength != null
prefixMask = allOnes << (bitCount - newSegmentPrefixLength);
}
newLower = original.getLowerSegmentValue() & prefixMask;
newUpper = original.getUpperSegmentValue() & prefixMask;
} else {
newLower = original.getLowerSegmentValue();
newUpper = original.getUpperSegmentValue();
}
return creator.createSegment(newLower, newUpper, newSegmentPrefixLength);
}
protected static boolean isReversibleRange(S segment) {
//consider the case of reversing the bits or a range
//Any range that can be successfully reversed must span all bits (otherwise after flipping you'd have a range in which the lower bit is constant, which is impossible in any contiguous range)
//So that means at least one value has 0xxxx and another has 1xxxx (using 5 bits for our example). This means you must have the values 01111 and 10000 since the range is contiguous.
//But reversing a range twice results in the original again, meaning the reversed must also be reversible, so the reversed also has 01111 and 10000.
//So this means both the original and the reversed also have those two patterns flipped, which are 00001 and 11110.
//So this means both ranges must span from at most 1 to at least 11110.
//However, the two remaining values, 0 and 11111, are optional, as they are boundary value and remain themselves when reversed, and hence have no effect on whether the reversed range is contiguous.
//So the only reversible ranges are 0-11111, 0-11110, 1-11110, and 1-11111.
//-----------------------
//Consider the case of reversing the bytes of a range.
//Any range that can be successfully reversed must span all bits
//(otherwise after flipping you'd have a range in which a lower bit is constant, which is impossible in any contiguous range)
//So that means at least one value has 0xxxxx and another has 1xxxxx (we use 6 bits for our example, and we assume each byte has 3 bits).
//This means you must have the values 011111 and 100000 since the range is contiguous.
//But reversing a range twice results in the original again, meaning the reversed must also be reversible, so the reversed also has 011111 and 100000.
//So this means both the original and the reversed also have those two patterns flipped, which are 111011 and 000100.
//So the range must have 000100, 011111, 100000, 111011, so it must be at least 000100 to 111011.
//So what if the range does not have 000001? then the reversed range cannot have 001000, the reversed address. But we know it spans 000100 to 111011.
//So the original must have 000001.
//What if it does not have 111110? Then the reversed cannot have 110111. But we know it ranges from 000100 to 111011. So the original must have 111110.
//But once again, the two remaining values are optional, so we have the same potential ranges: 0-111111, 0-111110, 1-111110, and 1-111111
return segment.getLowerSegmentValue() <= 1 && segment.getUpperSegmentValue() >= segment.getMaxSegmentValue() - 1;
}
}