inet.ipaddr.format.AddressItem Maven / Gradle / Ivy
Show all versions of ipaddress Show documentation
/*
* 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;
import java.io.Serializable;
import java.math.BigInteger;
import inet.ipaddr.Address;
import inet.ipaddr.PrefixLenException;
import inet.ipaddr.format.standard.AddressDivisionGrouping;
import inet.ipaddr.format.string.AddressStringDivisionSeries;
/**
* Represents any part of an address, whether divided into the standard arrangement of AddressComponent objects, or whether an alternative arrangement using AddressDivision objects.
*
* The basic difference between the AddressComponent hierarchy and the AddressDivision hierarchy is that
* AddressComponent hierarchy uses
*
- standardized/typical arrangement (ie for ipv4, 4 equal segments of 1 byte each, for ipv6, 8 equal segments of 2 bytes each, for mac, 6 or 8 equal segments of 1 byte each)
* - equal size segments
* - segments divided along byte boundaries
*
* AddressDivision allows alternative arrangements, such as inet_aton style of presenting ipv4 in fewer divisions,
* or base 85 for ipv6 which does not even use a base that is a power of 2 (and hence so subdivisions possibly using bit boundaries),
* or the aaa-bbb-ccc-ddd mac format with which segments are not divided along byte boundaries
*
* Parsing creates objects in the AddressComponent hierarchy, which can then be used to create alternative arrangements using {@link AddressDivisionGrouping} or {@link AddressStringDivisionSeries}
*
* @author sfoley
*
*/
public interface AddressItem extends Comparable, Serializable {
/**
* Uses {@link Address#DEFAULT_ADDRESS_COMPARATOR}, an instance of {@link inet.ipaddr.AddressComparator.CountComparator}, to compare any two address items.
*/
@Override
default int compareTo(AddressItem other) {
return Address.DEFAULT_ADDRESS_COMPARATOR.compare(this, other);
}
/**
* The count of possible distinct values for this AddressComponent. If not multiple, this is 1.
* Note that an AddressDivisionSeries with no divisions or AddressSection with no segments has a single value of 0.
*
* For instance, if this is the ip address series subnet 0::/64, then the count is 2 to the power of 64.
*
* If this is a the segment 3-7, then the count is 5.
*
* @return
*/
default BigInteger getCount() {
return getUpperValue().subtract(getValue()).add(BigInteger.ONE);
}
/**
* The count of the number of distinct values within the prefix part of the address item, the bits that appear within the prefix length.
*
* @param prefixLength
* @return
*/
default BigInteger getPrefixCount(int prefixLength) {
if(prefixLength < 0) {
throw new PrefixLenException(this, prefixLength);
}
int bitCount = getBitCount();
if(bitCount <= prefixLength) {
return getCount();
}
int shiftAdjustment = bitCount - prefixLength;
BigInteger lower = getValue(), upper = getUpperValue();
return upper.shiftRight(shiftAdjustment).subtract(lower.shiftRight(shiftAdjustment)).add(BigInteger.ONE);
}
/**
* Provides the number of bits comprising this address item
*
* @return the number of bits
*/
int getBitCount();
/**
* Provides the number of bytes required for this address item, rounding up if the bit count is not a multiple of 8
*
* @return the number of bytes
*/
default int getByteCount() {
return (getBitCount() + (Byte.SIZE - 1)) >>> 3;
}
/**
* Whether this represents multiple potential values (eg a prefixed address or a segment representing a range of values)
*/
default boolean isMultiple() {
return !getCount().equals(BigInteger.ONE);
}
/**
*
* @return the bytes of the lowest address item represented by this address item
*/
byte[] getBytes();
/**
* Copies the bytes of the lowest address item represented by this address item into the supplied array,
* and returns that array.
*
* If the supplied array is null or of insufficient size, a new array is created and returned.
*
* @return the bytes of the lowest address represented by this address item.
*/
byte[] getBytes(byte bytes[]);
/**
* Copies the bytes of the lowest address item represented by this address item into the supplied array starting at the given index,
* and returns that array.
*
* If the supplied array is null or of insufficient size, a new array is created and returned, with the rest of the array contents the same as the original.
*
* @return the bytes of the lowest address represented by this address item.
*/
byte[] getBytes(byte bytes[], int index);
/**
*
* @return the bytes of the largest address item represented by this address item
*/
byte[] getUpperBytes();
/**
* Copies the bytes of the largest address item represented by this address item into the supplied array,
* and returns that array.
*
* If the supplied array is null or of insufficient size, a new array is created and returned, with the rest of the array contents the same as the original.
*
* @return the bytes of the largest address represented by this address item.
*/
byte[] getUpperBytes(byte bytes[]);
/**
* Copies the bytes of the largest address item represented by this address item into the supplied array at the given index,
* and returns that array.
*
* If the supplied array is null or of insufficient size, a new array is created and returned.
*
* @return the bytes of the largest address represented by this address item.
*/
byte[] getUpperBytes(byte bytes[], int index);
/**
* Returns the lowest value represented by this address item, the lowest value included in the range of values
*
* @return the lowest value represented by this address item
*/
BigInteger getValue();
/**
* Returns the highest value represented by this address item, the highest value included in the range of values
*
* @return the highest value represented by this address item
*/
BigInteger getUpperValue();
/**
* Returns whether this item matches the value of zero
*
* @return whether this item matches the value of zero
*/
boolean isZero();
/**
* Returns whether this item includes the value of zero within its range
*
* @return whether this item includes the value of zero within its range
*/
boolean includesZero();
/**
* Returns whether this item matches the maximum possible value for the address type or version
*
* @return whether this item matches the maximum possible value
*/
boolean isMax();
/**
* Returns whether this item includes the maximum possible value for the address type or version within its range
*
* @return whether this item includes the maximum possible value within its range
*/
boolean includesMax();
/**
* whether this address item represents all possible values attainable by an address item of this type
*
* @return whether this address item represents all possible values attainable by an address item of this type,
* or in other words, both includesZero() and includesMax() return true
*/
default boolean isFullRange() {
return includesZero() && includesMax();
}
/**
* Returns whether the values of this series contains the prefix block for the given prefix length.
*
* Use {@link #getMinPrefixLengthForBlock()} to determine the smallest prefix length for which this method returns true.
*
* @param divisionPrefixLen
* @throws PrefixLenException if prefixLength exceeds the bit count or is negative
* @return
*/
default boolean containsPrefixBlock(int divisionPrefixLen) {
if(divisionPrefixLen == 0) {
return isFullRange();
}
BigInteger upper = getUpperValue();
return AddressDivisionBase.testRange(getValue(), upper, upper, getBitCount(), divisionPrefixLen);
}
/**
* Returns whether the values of this series contains a single prefix block for the given prefix length.
*
* Use {@link #getPrefixLengthForSingleBlock()} to determine whether there is a prefix length for which this method returns true.
*
* @param divisionPrefixLen
* @throws PrefixLenException if prefixLength exceeds the bit count or is negative
* @return
*/
default boolean containsSinglePrefixBlock(int divisionPrefixLen) {
if(divisionPrefixLen == 0) {
return isFullRange();
}
BigInteger lower = getValue(), upper = getUpperValue();
return AddressDivisionBase.testRange(lower, lower, upper, getBitCount(), divisionPrefixLen);
}
/**
* Returns the smallest prefix length possible such that this item includes the block of all values for that prefix length.
*
* If the entire range can be dictated this way, then this method returns the same value as {@link #getPrefixLengthForSingleBlock()}.
* Otherwise, this method will return the minimal possible prefix that can be paired with this address, while {@link #getPrefixLengthForSingleBlock()} will return null.
*
* In cases where the final bit is constant so there is no such block, this returns the bit count.
*
* @return the prefix length
*/
default int getMinPrefixLengthForBlock() {
int result = getBitCount();
BigInteger lower = getValue(), upper = getUpperValue();
if(!lower.equals(upper)) {
int longBits = Long.SIZE;
do {
long low = lower.longValue();
int lowerZeros = Long.numberOfTrailingZeros(low);
if(lowerZeros == 0) {
break;
}
long up = upper.longValue();
int upperOnes = Long.numberOfTrailingZeros(~up);
if(upperOnes == 0) {
break;
}
int prefixedBitCount = Math.min(lowerZeros, upperOnes);
result -= prefixedBitCount;
if(prefixedBitCount < longBits) {
break;
}
lower = lower.shiftRight(longBits);
upper = upper.shiftRight(longBits);
} while(!upper.equals(BigInteger.ZERO));
}
return result;
}
/**
* Returns a prefix length for which the range of this item matches the block of all values for that prefix length.
*
* If the range can be dictated this way, then this method returns the same value as {@link #getMinPrefixLengthForBlock()}.
*
* If no such prefix length exists, returns null.
*
* If this item represents a single value, this returns the bit count.
*
* @return the prefix length or null
*/
default Integer getPrefixLengthForSingleBlock() {
int divPrefix = getMinPrefixLengthForBlock();
BigInteger lower = getValue(), upper = getUpperValue();
int bitCount = getBitCount();
if(divPrefix == bitCount) {
if(lower.equals(upper)) {
return AddressDivisionGroupingBase.cacheBits(divPrefix);
}
} else {
int shift = bitCount - divPrefix;
if(lower.shiftRight(shift).equals(upper.shiftRight(shift))) {
return AddressDivisionGroupingBase.cacheBits(divPrefix);
}
}
return null;
}
/**
* Returns the total number of values when ranging across the given number of host bits.
* This is the reverse of {@link #getBitsForCount(long)}.
*
* A bitCount of zero or less returns zero.
*
* @param bitCount
*/
public static BigInteger getBlockSize(int bitCount) {
return BigInteger.ONE.shiftLeft(bitCount);
}
/**
* BitsForCount returns the number of bits required outside the prefix length
* for a single prefix block to span at least as many addresses as the given count.
* Mathematically, it is the ceiling of the base 2 logarithm of the given count.
* A count of zero or less than zero returns null.
*
* See {@link #getBlockSize(int)} for the reverse direction.
*
* @param count
*/
public static Integer getBitsForCount(long count) {
if(count <= 0) {
return null;
}
int logBase2 = (Long.SIZE - 1) - Long.numberOfLeadingZeros(count);
if((~(-1L << logBase2) & count) != 0) {
logBase2++;
}
return logBase2;
}
}