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

inet.ipaddr.format.standard.AddressDivision Maven / Gradle / Ivy

There is a newer version: 5.5.1
Show newest version
/*
 * 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.format.standard;

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.IPAddress;
import inet.ipaddr.IncompatibleAddressException;
import inet.ipaddr.format.AddressDivisionBase;
import inet.ipaddr.format.validate.ParsedIPAddress;
import inet.ipaddr.format.validate.ParsedIPAddress.BitwiseOrer;
import inet.ipaddr.format.validate.ParsedIPAddress.Masker;

/**
 * A division of an address.
 * 
 * @author sfoley
 *
 */
public abstract class AddressDivision extends AddressDivisionBase {

	private static final long serialVersionUID = 4L;

	protected AddressDivision() {}

	@Override
	protected byte[] getBytesImpl(boolean low) {
		int bitCount = getBitCount();
		byte bytes[] = new byte[getByteCount()];
		int byteIndex = bytes.length - 1;
		long segmentValue = low ? getDivisionValue() : getUpperDivisionValue();
		while(true) {
			bytes[byteIndex] |= segmentValue;
			segmentValue >>= 8;
			if(bitCount <= 8) {
				return bytes;
			}
			bitCount -= 8;
			byteIndex--;
		}
	}
	
	/**
	 * @return whether this segment represents multiple values
	 */
	@Override
	public boolean isMultiple() {
		return getDivisionValue() != getUpperDivisionValue();
	}

	@Override
	public int getMinPrefixLengthForBlock() {
		int result = getBitCount();
		if(!isMultiple()) {
			return result;
		} else if(isFullRange()) {
			return 0;
		}
		int lowerZeros = Long.numberOfTrailingZeros(getDivisionValue());
		if(lowerZeros != 0) {
			int upperOnes = Long.numberOfTrailingZeros(~getUpperDivisionValue());
			if(upperOnes != 0) {
				int prefixedBitCount = Math.min(lowerZeros, upperOnes);
				result -= prefixedBitCount;
			}
		}
		return result;
	}

	@Override
	public Integer getPrefixLengthForSingleBlock() {
		int divPrefix = getMinPrefixLengthForBlock();
		long lowerValue = getDivisionValue();
		long upperValue = getUpperDivisionValue();
		int bitCount = getBitCount();
		if(divPrefix == bitCount) {
			if(lowerValue == upperValue) {
				return AddressDivisionGrouping.cacheBits(divPrefix);
			}
		} else {
			int shift = bitCount - divPrefix;
			if(lowerValue >>> shift == upperValue >>> shift) {
				return AddressDivisionGrouping.cacheBits(divPrefix);
			}
		}
		return null;
	}
	
	@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 getDivisionValue() == 0L;
	}
	
	@Override
	public boolean isMax() {
		return !isMultiple() && includesMax();
	}
	
	@Override
	public boolean includesMax() {
		return getUpperDivisionValue() == getMaxValue();
	}
	
	public abstract long getDivisionValue();
	
	public abstract long getUpperDivisionValue();
	
	@Override
	public int hashCode() {
		int res = hashCode;
		if(res == 0) {
			hashCode = res = createHashCode(getDivisionValue(), getUpperDivisionValue());
		}
		return res;
	}
	
	@Override
	public BigInteger getValue() {
		return BigInteger.valueOf(getDivisionValue());
	}
	
	@Override
	public BigInteger getUpperValue() {
		return BigInteger.valueOf(getUpperDivisionValue());
	}
	
	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
	 */
	protected boolean isPrefixBlock(long divisionValue, long upperValue, int divisionPrefixLen) {
		if(divisionPrefixLen == 0) {
			return divisionValue == 0 && upperValue == getMaxValue();
		}
		int bitCount = getBitCount();
		long ones = ~0L;
		long divisionBitMask = ~(ones << bitCount);
		long divisionPrefixMask = ones << (bitCount - 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 
	 */
	protected boolean isSinglePrefixBlock(long divisionValue, long upperValue, int divisionPrefixLen) {
		long ones = ~0L;
		int bitCount = getBitCount();
		long divisionBitMask = ~(ones << bitCount);
		long divisionPrefixMask = ones << (bitCount - 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 getUpperDivisionValue() < value;
	}
	
	public boolean matches(long value) {
		return !isMultiple() && value == getDivisionValue();
	}
	
	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 = getDivisionValue() ^ getUpperDivisionValue();
			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 == (getDivisionValue() & 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 = getDivisionValue();
		long thisUpperValue = getUpperDivisionValue();
		Masker masker = maskRange(thisValue, thisUpperValue, mask, getMaxValue());
		if(!masker.isSequential()) {
			return false;
		}
		return lowerValue == masker.getMaskedLower(thisValue, mask) && upperValue == masker.getMaskedUpper(thisUpperValue, mask);
	}
	
	@Override
	protected boolean isSameValues(AddressDivisionBase other) {
		if(other instanceof AddressDivision) {
			AddressDivision otherDivision = (AddressDivision) other;
			return getDivisionValue() == otherDivision.getDivisionValue() &&
					getUpperDivisionValue() == otherDivision.getUpperDivisionValue();
		}
		return false;
	}
	
	@Override
	public boolean equals(Object o) {
		if(o == this) {
			return true;
		}
		if(o instanceof AddressDivision) {
			// we call isSameValues on the other object to defer to subclasses overriding that method in object o
			// in particular, if the other is IPv4/6/MAC/AddressSection, then we call the overridden isSameGrouping
			// in those classes which check for IPv4/6/MAC type/version.
			// Also, those other classes override equals to ensure flip doesn't go the other way
			AddressDivision other = (AddressDivision) o;
			return getBitCount() == other.getBitCount() && other.isSameValues(this);
		}
		return false;
	}
	
	
	/**
	 * Represents the result of masking a sequential range of values
	 * 
	 * @author seancfoley
	 *
	 */
	public static class MaskResult {
		private final long value, upperValue, maskValue;
		private final Masker masker;

		public MaskResult(long value, long upperValue, long maskValue, Masker masker) {
			this.value = value;
			this.upperValue = upperValue;
			this.maskValue = maskValue;
			this.masker = masker;
		}
		
		/**
		 * The lowest masked value, which is not necessarily the lowest value masked
		 * @return
		 */
		public long getMaskedLower() {
			return masker.getMaskedLower(value, maskValue);
		}
		
		/**
		 * The highest masked value, which is not necessarily the highest value masked
		 * @return
		 */
		public long getMaskedUpper() {
			return masker.getMaskedUpper(upperValue, maskValue);
		}
		
		/**
		 * Whether masking all values in the range results in a sequential set of values
		 * @return
		 */
		public boolean isSequential() {
			return masker.isSequential();
		}
	}
	
	/**
	 * Check that the range resulting from the mask is contiguous, otherwise it cannot be represented by a division or segment instance.
	 * 
	 * For instance, for the range 0 to 3 (bits are 00 to 11), if we mask all 4 numbers from 0 to 3 with 2 (ie bits are 10), 
	 * then we are left with 1 and 3.  2 is not included.  So we cannot represent 1 and 3 as a contiguous range.
	 * 
	 * The underlying rule is that mask bits that are 0 must be above the resulting range in each segment.
	 * 
	 * Any bit in the mask that is 0 must not fall below any bit in the masked segment range that is different between low and high.
	 * 
	 * Any network mask must eliminate the entire division range or keep the entire range.  Any host mask is fine.
	 * 
	 * @param maskValue
	 * @return
	 */
	public boolean isMaskCompatibleWithRange(int maskValue) {
		long value = getDivisionValue();
		long upperValue = getUpperDivisionValue();
		long maxValue = getMaxValue();
		return maskRange(value, upperValue, maskValue, maxValue).isSequential();
	}

	protected static Masker maskRange(long value, long upperValue, long maskValue, long maxValue) {
		return ParsedIPAddress.maskRange(value, upperValue, maskValue, maxValue);
	}

	/**
	 * 
	 * Returns an object that provides the masked values for a range,
	 * which for subnets is an aggregation of all masked individual addresses in the subnet.
	 * See {@link #bitwiseOrRange(long, long, long)}
	 * 
	 * @param value
	 * @param upperValue
	 * @param maskValue
	 * @return an instance that provides the result of masking the values.  With individual addresses, the result is simply value & maskValue.
	 *   But with subnets, returns an object providing lower and upper results along with whether the resulting set of values is sequential.
	 */
	public static MaskResult maskRange(long value, long upperValue, long maskValue) {
		Masker masker = ParsedIPAddress.maskRange(value, upperValue, maskValue);
		return new MaskResult(value, upperValue, maskValue, masker);
	}
	
	
	/**
	 * Represents the result of a bitwise or of a sequential range of values
	 * 
	 * @author seancfoley
	 *
	 */
	public static class BitwiseOrResult {
		private final long value, upperValue, maskValue;
		private final BitwiseOrer masker;

		public BitwiseOrResult(long value, long upperValue, long maskValue, BitwiseOrer masker) {
			this.value = value;
			this.upperValue = upperValue;
			this.maskValue = maskValue;
			this.masker = masker;
		}
		
		/**
		 * The lowest ored value, which is not necessarily the lowest value ored
		 * @return
		 */
		public long getOredLower() {
			return masker.getOredLower(value, maskValue);
		}
		
		/**
		 * The highest ored value, which is not necessarily the highest value ored
		 * @return
		 */
		public long getOredUpper() {
			return masker.getOredUpper(upperValue, maskValue);
		}
		
		/**
		 * Whether masking all values in the range results in a sequential set of values
		 * @return
		 */
		public boolean isSequential() {
			return masker.isSequential();
		}
	}
	
	
	/**
	 * Similar to masking, checks that the range resulting from the bitwise "or" operation is sequential.
	 * 
	 * @param maskValue
	 * @return
	 */
	public boolean isBitwiseOrCompatibleWithRange(int maskValue) {
		if(!isMultiple()) {
			return true;
		}
		long value = getDivisionValue();
		long upperValue = getUpperDivisionValue();
		long maxValue = getMaxValue();
		return bitwiseOrRange(value, upperValue, maskValue, maxValue) != null;
	}
	
	protected static BitwiseOrer bitwiseOrRange(long value, long upperValue, long maskValue, long maxValue) {
		return ParsedIPAddress.bitwiseOrRange(value, upperValue, maskValue, maxValue);
	}
	
	/**
	 * Applies bitwise or to a range of values.   Returns an object that provides the ored values for a range,
	 * which for subnets is an aggregation of all ored individual addresses in the subnet.
	 * See {@link #maskRange(long, long, long)}
	 * 
	 * @param maskValue
	 * @return
	 */
	public static BitwiseOrResult bitwiseOrRange(long value, long upperValue, long maskValue) {
		BitwiseOrer masker = ParsedIPAddress.bitwiseOrRange(value, upperValue, maskValue);
		return new BitwiseOrResult(value, upperValue, maskValue, masker);
	}
	
	public boolean hasUppercaseVariations(int radix, boolean lowerOnly) {
		if(radix < MIN_RADIX) {
			throw new IllegalArgumentException();
		} else 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); //shift 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 = getDivisionValue();
		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 = getUpperDivisionValue();
			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(getUpperDivisionValue(), 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, getDivisionValue(), radix);
	}
	
	@Override
	protected int adjustUpperLeadingZeroCount(int leadingZeroCount, int radix) {
		return adjustLeadingZeroCount(leadingZeroCount, getUpperDivisionValue(), 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 String getWildcardString() {
		return super.getWildcardString();
	}
	
	@Override
	protected int getLowerStringLength(int radix) {
		return toUnsignedStringLength(getDivisionValue(), radix);
	}
	
	@Override
	protected int getUpperStringLength(int radix) {
		return toUnsignedStringLength(getUpperDivisionValue(), radix);
	}

	@Override
	protected void getLowerString(int radix, boolean uppercase, StringBuilder appendable) {
		toUnsignedStringCased(getDivisionValue(), radix, 0, uppercase, appendable);
	}
	
	@Override
	protected void getUpperString(int radix, boolean uppercase, StringBuilder appendable) {
		toUnsignedStringCased(getUpperDivisionValue(), radix, 0, uppercase, 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) {
		toUnsignedStringCased(getDivisionValue(), radix, rangeDigits, uppercase, appendable);
	}
	
	@Override
	protected void getSplitLowerString(int radix, int choppedDigits, boolean uppercase, 
			char splitDigitSeparator, boolean reverseSplitDigits, String stringPrefix, StringBuilder appendable) {
		toSplitUnsignedString(getDivisionValue(), 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(
			getDivisionValue(),
			getUpperDivisionValue(),
			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(
			getDivisionValue(),
			getUpperDivisionValue(),
			rangeSeparator,
			wildcard,
			leadingZeroCount,
			radix,
			uppercase, 
			splitDigitSeparator,
			reverseSplitDigits,
			stringPrefix);
	}

	@Override
	protected String getDefaultLowerString() {
		return toDefaultString(getDivisionValue(), getDefaultTextualRadix());
	}
	
	@Override
	protected String getDefaultRangeString() {
		return getDefaultRangeString(getDivisionValue(), getUpperDivisionValue(), 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);
		} else 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) {
		if(radix < MIN_RADIX || radix > MAX_RADIX || val < 0) {
			throw new IllegalArgumentException();
		}
		//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";
		} else 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);
		} else 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 int toUnsignedSplitRangeStringLength(
			long lower,
			long upper,
			String rangeSeparator,
			String wildcard,
			int leadingZerosCount,
			int radix,
			boolean uppercase, 
			char splitDigitSeparator,
			boolean reverseSplitDigits,
			String stringPrefix) {
		if(radix < MIN_RADIX || radix > MAX_RADIX) {
			throw new IllegalArgumentException();
		}
		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 BigInteger getRadixPower(BigInteger radix, int power) {
		return AddressDivisionBase.getRadixPower(radix, power);
	}

	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,
			boolean uppercase, 
			char splitDigitSeparator,
			String stringPrefix,
			StringBuilder appendable) {
		if(radix < MIN_RADIX || radix > MAX_RADIX) {
			throw new IllegalArgumentException();
		}
		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) {
		if(radix < MIN_RADIX || radix > MAX_RADIX) {
			throw new IllegalArgumentException();
		}
		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;
		} else if(radix == getDefaultTextualRadix()) {
			return getRangeDigitCountImpl();
		} else if(radix < MIN_RADIX || radix > MAX_RADIX) {
			throw new IllegalArgumentException();
		}
		return calculateRangeDigitCount(radix, getDivisionValue(), getUpperDivisionValue(), getMaxValue());
	}
	
	protected int getRangeDigitCountImpl() {
		return calculateRangeDigitCount(getDefaultTextualRadix(), getDivisionValue(), getUpperDivisionValue(), 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  int getPrefixValueCount(S segment, int segmentPrefixLength) {
		int shiftAdjustment = segment.getBitCount() - segmentPrefixLength;
		return (segment.getUpperSegmentValue() >>> shiftAdjustment) - (segment.getSegmentValue() >>> shiftAdjustment) + 1;
	}

	protected static  Iterator identityIterator(S original) {
		return new Iterator() {
			boolean done;
			
			@Override
			public boolean hasNext() {
				return !done;
			}
	
		   @Override
			public S next() {
		    	if(!hasNext()) {
		    		throw new NoSuchElementException();
		    	}
		    	done = true;
		    	return original;
	    	}
	
		    @Override
			public void remove() {
		    	throw new UnsupportedOperationException();
		    }
		};
	}

	protected static  Iterator iterator(
			S original,
			AddressSegmentCreator creator,
			Integer segmentPrefixLength,
			boolean isPrefixIterator,
			boolean isBlockIterator) {
		return iterator(
				original,
				original.getSegmentValue(),
				original.getUpperSegmentValue(),
				original.getBitCount(),
				creator,
				segmentPrefixLength,
				isPrefixIterator,
				isBlockIterator);
	}

	protected static  Iterator iterator(
			S original,
			int originalLower,
			int originalUpper,
			int bitCount,
			AddressSegmentCreator creator,
			Integer segmentPrefixLength,
			boolean isPrefixIterator,
			boolean isBlockIterator) {
		int shiftAdjustment, shiftMask, upperShiftMask;
		if(isPrefixIterator) {
			shiftAdjustment = bitCount - segmentPrefixLength;
			shiftMask = ~0 << shiftAdjustment;
			upperShiftMask = ~shiftMask;
		} else {
			shiftAdjustment = shiftMask = upperShiftMask = 0;
		}
		if(original != null && !original.isMultiple()) {
			return new Iterator() {
				boolean done;
				
				@Override
				public boolean hasNext() {
					return !done;
				}
		
			   @Override
				public S next() {
			    	if(!hasNext()) {
			    		throw new NoSuchElementException();
			    	}
			    	done = true;
			    	if(isBlockIterator) {
			    		return creator.createSegment(
			    				originalLower & shiftMask,
			    				originalUpper | upperShiftMask,
			    				segmentPrefixLength);
			    	}
			    	return original;
			    }
		
			    @Override
				public void remove() {
			    	throw new UnsupportedOperationException();
			    }
			};
		}
		if(isPrefixIterator) {
			if(isBlockIterator) {
				return new Iterator() {
					private boolean notDone = true;
					private int current = originalLower, last = originalUpper; {
						current >>>= shiftAdjustment;
						last >>>= shiftAdjustment;
					}
					
					@Override
					public boolean hasNext() {
						return notDone;
					}
				
				    @Override
					public S next() {
				    	if(!notDone) {
				    		throw new NoSuchElementException();
				    	}
				    	int cur = current;
			    		int blockLow = cur << shiftAdjustment;
			    		S result = creator.createSegment(blockLow, blockLow | upperShiftMask, segmentPrefixLength);
		    			if(++cur > last) {
		    				notDone = false;
		    			} else {
		    				current = cur;
		    			}
				    	return result;
				    }
				
				    @Override
					public void remove() {
				    	throw new UnsupportedOperationException();
				    }
				};
			}
			return new Iterator() {
				private boolean notDone = true, notFirst;
				private int current = originalLower, last = originalUpper; {
					current >>>= shiftAdjustment;
					last >>>= shiftAdjustment;
				}
				
				@Override
				public boolean hasNext() {
					return notDone;
				}
			
			    @Override
				public S next() {
			    	if(!notDone) {
			    		throw new NoSuchElementException();
			    	}
			    	int cur = current;
		    		int blockLow = cur << shiftAdjustment;
		    		int blockHigh = blockLow | upperShiftMask;
		    		current = ++cur;
		    		int low, high;
		    		if(notFirst) {
		    			low = blockLow;
		    		} else {
		    			low = originalLower;
		    			notFirst = true;
		    		}
		    		boolean notDne = cur <= last;
		    		if(notDne) {
		    			high = blockHigh;
		    		} else {
		    			high = originalUpper;
		    			notDone = false;
		    		}
		    		return creator.createSegment(low, high, segmentPrefixLength);
			    }
			
			    @Override
				public void remove() {
			    	throw new UnsupportedOperationException();
			    }
			};
		}
		return new Iterator() {
			private boolean notDone = true;
			private int current = originalLower, last = originalUpper;
			
			@Override
			public boolean hasNext() {
				return notDone;
			}
		
		    @Override
			public S next() {
		    	if(!notDone) {
		    		throw new NoSuchElementException();
		    	}
		    	S result = creator.createSegment(current, segmentPrefixLength);
		    	notDone = ++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);
			}
			int value = original.getSegmentValue();
			int upperValue = original.getUpperSegmentValue();
			long maxValue = ~(~0L << original.getBitCount());
			Masker masker = maskRange(value, upperValue, prefixMask, maxValue);
			if(!masker.isSequential()) {
				throw new IncompatibleAddressException(original, "ipaddress.error.maskMismatch");
			}
			newLower = (int) masker.getMaskedLower(value, prefixMask);
			newUpper = (int) masker.getMaskedUpper(upperValue, prefixMask);
		} else {
			newLower = original.getSegmentValue();
			newUpper = original.getUpperSegmentValue();
		}
		return creator.createSegment(newLower, newUpper, newSegmentPrefixLength);
	}
	
	// Consider the case of reversing the bits of 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 each of the bytes of a range.
	//
	// You can apply your argument to the top multiple byte.
	// which means it is 0 or 1 to 254 or 255.
	// Suppose there is another byte to follow
	// If you take the upper byte range, and you hold it constant, then reversing the next byte applies the same argument to that byte.  
	// And so the lower byte must span from at most 1 to at least 11111110.
	// This argument holds when holding the upper byte constant at any value.
	// So the lower byte must span from at most 1 to at least 111111110 for any value.
	// So you have x 00000001-x 111111110 and y 00000001-y 111111110 and so on.
	
	// But all the bytes form a range, so you must also have the values in-between.
	// So that means you have 1 00000001 to 1 111111110 to 10 111111110 to 11 111111110 all the way to x 11111110, where x is at least 11111110.
	// In all cases, the upper byte lower value is at most 1, and 1 < 10000000.
	// That means you always have 10000000 00000000.
	// So you have the reverse as well (as argued above, for any value we also have the reverse).
	// So you always have 00000001 00000000.
	//
	// In other words, if the upper byte has lower 0, then the full bytes lower must be at most 0 00000001
	// Otherwise, when the upper byte has lower 1, the the full bytes lower is at most 1 00000000.
	//
	// In other words, if any upper byte has lower value 1, then all lower values to follow are 0.
	// If all upper bytes have lower value 0, then the next byte is permitted to have lower value 1.
	// In summary, any upper byte having lower of 1 forces the remaining lower values to be 0.
	// WHen the upper bytes are all zero, and thus the lower is at most 0 0 0 0 1, 
	// then the only remaining lower value is 0 0 0 0 0.  This reverses to itself, so it is optional.
	//
	// The same argument applies to upper boundaries.
	//
	// You need to check each byte in order.  Single valued do not matter.  First time you hit multi-valued byte x,
	// It must have lower value 0 or 1.  It must have upper value max or max - 1.
	// The following byte must be multiple of course.  
	// If the lower value of x is 0, then the next byte can have lower value 0 or 1.
	// Otherwise, the next byte and all bytes to follow must have lower value 0.
	// Same applies to the upper boundary. 
	// So you keep track as you go whether lower value can be 1 (if not then 0), and whether upper value can be max - 1 (if not then max).
	
		
	//-----------------------
	// 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 bytes in each 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 byte-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, the byte-reversed address.
	// But we know it ranges from 000100 to 111011.  So the original must have 111110.
	// So it must range from 000001 to 111110.  The only remaining values in question are 000000 and 111111.
	// But once again, the two remaining values are optional, because they byte-reverse to themselves.
	// So for the byte-reverse case, we have the same potential ranges as in the bit-reverse case: 0-111111, 0-111110, 1-111110, and 1-111111
	
	protected static  boolean isReversibleRangePerByte(S seg) {
		int byteCount = seg.getByteCount();
		int bitCount = seg.getBitCount();
		int val = seg.getSegmentValue();
		int upperVal = seg.getUpperSegmentValue();
		for(int i = 1; i <= byteCount; i++) {
			int bitShift = i << 3;
			int shift = bitCount - bitShift;
			int byteVal = 0xff & (val >> shift);
			int upperByteVal = 0xff & (upperVal >> shift);
			if(byteVal != upperByteVal) {
				if(byteVal > 1 || upperByteVal < 254) {
					return false;
				}
				if(++i <= byteCount) {
					boolean lowerIsZero = byteVal == 1;
					boolean upperIsMax = upperByteVal == 254;
					do {
						bitShift = i<<3;
						shift = bitCount - bitShift;
						byteVal = 0xff & (val >> shift);
						upperByteVal = 0xff & (upperVal >> shift);
						if(lowerIsZero) {
							if(byteVal != 0) {
								return false;
							}
						} else {
							if(byteVal > 1) {
								return false;
							}
							lowerIsZero = byteVal == 1;
						}
						if(upperIsMax) {
							if(upperByteVal != 255) {
								return false;
							}
						} else {
							if(upperByteVal < 254) {
								return false;
							}
							upperIsMax = upperByteVal == 254;
						}
						i++;
					} while(i <= byteCount);
				}
				return true;
			}
		}
		return true;
	}
	
	protected static  boolean isReversibleRange(S segment) {
		return segment.getSegmentValue() <= 1 && segment.getUpperSegmentValue() >= segment.getMaxSegmentValue() - 1;
	}
}