import * as bigInt from "big-integer" ; import { AbstractIPNum , IPv4 , IPv6 , isIPv4 } from "./IPNumber" ; import { IPv4Prefix , IPv6Prefix } from "./Prefix" ; import { cidrPrefixToMaskBinaryString , intLog2 , leftPadWithZeroBit , matchingBitCount , parseBinaryStringToBigInteger } from "./BinaryUtils" ; import { Validator } from "./Validator" ; import { IPNumType } from "./IPNumType" ; export type IP < T > = T extends IPv4CidrRange ? IPv4 : IPv6 ; /**
 * Represents a continuous segment of either IPv4 or IPv6 numbers
 * without adhering to classless inter-domain routing scheme
 * for allocating IP addresses.
 */ export class RangedSet < T extends AbstractIPNum > implements Iterable < AbstractIPNum > { readonly bitValue : bigInt . BigInteger ; private readonly currentValue : T ; private readonly first : T ; private readonly last : T ; /**
     * Convenience method for constructing an instance of  RangedSet from a
     * single IP number.
     *
     *  param ip static fromSingleIP < T extends AbstractIPNum > ( ip ) { return new RangedSet ( ip , ip ) ; } /**
     * Convenience method for constructing an instance of  RangedSet from an
     * instance of either  IPv4CidrRange or  IPv6CidrRange param cidrRange an instance of  RangedSet static fromCidrRange < U extends IPv6CidrRange | IPv4CidrRange > ( cidrRange ) { return new RangedSet ( cidrRange . getFirst ( ) as IP < U > , cidrRange . getLast ( ) as IP < U > ) ; } /**
     * Convenience method for constructing an instance of  RangedSet from
     * a range string in the form of firstIp-lastIp
     *
     *  param rangeString static fromRangeString ( rangeString ) { let ips = rangeString . split ( "-" ) . map ( ip => ip . trim ( ) ) ; if ( ips . length !== 2 ) { throw new Error ( "Argument should be in the format firstip-lastip" ) ; } let [ firstIPString , lastIPString ] = ips ; let [ isValidFirstIPv4 , ] = Validator . isValidIPv4String ( firstIPString ) ; let [ isValidSecondIPv4 , ] = Validator . isValidIPv4String ( lastIPString ) ; let [ isValidFirstIPv6 , ] = Validator . isValidIPv6String ( firstIPString ) ; let [ isValidLastIPv6 , ] = Validator . isValidIPv6String ( lastIPString ) ; if ( isValidFirstIPv4 && isValidSecondIPv4 ) { return new RangedSet ( IPv4 . fromDecimalDottedString ( firstIPString ) , IPv4 . fromDecimalDottedString ( lastIPString ) ) ; } else if ( isValidFirstIPv6 && isValidLastIPv6 ) { return new RangedSet ( IPv6 . fromHexadecimalString ( firstIPString ) , IPv6 . fromHexadecimalString ( lastIPString ) ) ; } else { throw new Error ( "First IP and Last IP should be valid and same type" ) ; } } /**
     * Constructor for an instance of  RangedSet from an
     * instance of either  IPv4CidrRange or  IPv6CidrRange *
     * Throws an exception if first IP number is not less than given last IP number
     *
     *  param first param last constructor ( first , last ) { this . first = first ; this . last = last ; if ( first . isGreaterThan ( last ) ) { throw new Error ( `${ first . toString ( ) } should be lower than ${ last . toString ( ) }` ) ; } this . currentValue = first ; this . bitValue = bigInt ( first . bitSize ) ; } /**
     * Returns the first IP number in the range
     */ getFirst ( ) { return this . first ; } /**
     * Returns the last IP number in the range
     */ getLast ( ) { return this . last ; } /**
     * Returns the size, which is the number of IP numbers in the range.
     */ getSize ( ) { return this . last . getValue ( ) . minus ( this . first . getValue ( ) ) . plus ( bigInt . one ) ; } /**
     * Converts to a string representation of the range in the form of:
     * <first-ip>-<last-ip>
     */ toRangeString ( ) { return `${ this . getFirst ( ) }-${ this . getLast ( ) }` ; } param otherRange public inside ( otherRange ) { return otherRange . contains ( this ) ; } param otherRange public contains ( otherRange ) { let thisFirst = this . getFirst ( ) ; let thisLast = this . getLast ( ) ; let otherFirst = otherRange . getFirst ( ) ; let otherLast = otherRange . getLast ( ) ; return ( thisFirst . isLessThanOrEquals ( otherFirst ) && thisLast . isGreaterThanOrEquals ( otherLast ) ) ; } param otherRange public isEquals ( otherRange ) { return this . getFirst ( ) . isEquals ( otherRange . getFirst ( ) ) && this . getLast ( ) . isEquals ( otherRange . getLast ( ) ) ; } ; param otherRange public isLessThan ( otherRange ) { if ( this . isEquals ( otherRange ) ) { return false ; } else { if ( this . getFirst ( ) . isEquals ( otherRange . getFirst ( ) ) ) { return this . getSize ( ) . lesser ( otherRange . getSize ( ) ) ; } return this . getFirst ( ) . isLessThan ( otherRange . getFirst ( ) ) ; } } param otherRange public isGreaterThan ( otherRange ) { if ( this . isEquals ( otherRange ) ) { return false ; } else { if ( this . getFirst ( ) . isEquals ( otherRange . getFirst ( ) ) ) { return this . getSize ( ) . greater ( otherRange . getSize ( ) ) ; } return this . getFirst ( ) . isGreaterThan ( otherRange . getFirst ( ) ) ; } } param otherRange public isOverlapping ( otherRange ) { let thisFirst = this . getFirst ( ) ; let thisLast = this . getLast ( ) ; let otherFirst = otherRange . getFirst ( ) ; let otherLast = otherRange . getLast ( ) ; return ( thisLast . isGreaterThan ( otherFirst ) && thisLast . isLessThanOrEquals ( otherLast ) && thisFirst . isLessThan ( otherFirst ) || otherLast . isGreaterThan ( thisFirst ) && otherLast . isLessThanOrEquals ( thisLast ) && otherFirst . isLessThan ( thisFirst ) ) ; } /**
     * Check if this range can be converted to a CIDR range.
     */ public isCidrAble ( ) { if ( this . getSize ( ) . eq ( bigInt . one ) ) { return true ; } try { let prefix = intLog2 ( this . getSize ( ) ) ; let netmask = parseBinaryStringToBigInteger ( cidrPrefixToMaskBinaryString ( prefix , isIPv4 ( this . currentValue ) ? IPNumType . IPv4 : IPNumType . IPv6 ) ) ; return this . first . getValue ( ) . eq ( netmask . and ( this . first . getValue ( ) ) ) ; } catch ( e ) { return false ; } } /**
     * Converts an instance of range to an instance of CIDR range
     */ public toCidrRange ( ) { if ( isIPv4 ( this . currentValue ) ) { return this . toIPv4CidrRange ( ) ; } else { return this . toIPv6CidrRange ( ) ; } } ; param otherRange public isConsecutive ( otherRange ) { let thisFirst = this . getFirst ( ) ; let thisLast = this . getLast ( ) ; let otherFirst = otherRange . getFirst ( ) ; let otherLast = otherRange . getLast ( ) ; return ( thisLast . hasNext ( ) && thisLast . nextIPNumber ( ) . isEquals ( otherFirst ) || otherLast . hasNext ( ) && otherLast . nextIPNumber ( ) . isEquals ( thisFirst ) ) ; } param otherRange public union ( otherRange ) { if ( this . isEquals ( otherRange ) ) { return new RangedSet ( otherRange . getFirst ( ) , otherRange . getLast ( ) ) ; } if ( this . isOverlapping ( otherRange ) ) { if ( this . getFirst ( ) . isLessThan ( otherRange . getFirst ( ) ) ) { return new RangedSet ( this . getFirst ( ) , otherRange . getLast ( ) ) ; } else { return new RangedSet ( otherRange . getFirst ( ) , this . getLast ( ) ) ; } } if ( this . contains ( otherRange ) ) { return new RangedSet ( this . getFirst ( ) , this . getLast ( ) ) ; } else if ( otherRange . contains ( this ) ) { return new RangedSet ( otherRange . getFirst ( ) , otherRange . getLast ( ) ) ; } throw new Error ( "Ranges do not overlap nor are equal" ) ; } param otherRange public prepend ( otherRange ) { if ( otherRange . getLast ( ) . nextIPNumber ( ) . isEquals ( this . getFirst ( ) ) ) { return new RangedSet ( otherRange . getFirst ( ) , this . getLast ( ) ) ; } else { throw new Error ( "Range to prepend must be adjacent" ) ; } } param otherRange public append ( otherRange ) { if ( this . getLast ( ) . nextIPNumber ( ) . isEquals ( otherRange . getFirst ( ) ) ) { return new RangedSet ( this . getFirst ( ) , otherRange . getLast ( ) ) ; } else { throw new Error ( "Range to append must be adjacent" ) ; } } public subtract ( otherRange ) { if ( ! this . isOverlapping ( otherRange ) ) { throw new Error ( "Cannot subtract ranges that are not overlapping" ) ; } if ( ! this . isLessThan ( otherRange ) ) { throw new Error ( "Cannot subtract a larger range from this range" ) ; } return new RangedSet ( this . getFirst ( ) , otherRange . getLast ( ) ) ; } param offset param size public takeSubRange ( offset , size ) { if ( offset . plus ( size ) . gt ( this . getSize ( ) ) ) { throw new RangeError ( "Requested range is greater than what can be taken" ) ; } if ( size . eq ( bigInt ( 0 ) ) ) { throw new Error ( "Sub range cannot be zero" ) ; } let valueOfFirstIp = this . getFirst ( ) . value . plus ( offset ) ; let firstIp = isIPv4 ( this . getFirst ( ) ) ? IPv4 . fromBigInteger ( valueOfFirstIp ) : IPv6 . fromBigInteger ( valueOfFirstIp ) ; let valueOfLastIp = firstIp . value . plus ( size . minus ( bigInt . one ) ) ; let lastIp = isIPv4 ( firstIp ) ? IPv4 . fromBigInteger ( valueOfLastIp ) : IPv6 . fromBigInteger ( valueOfLastIp ) ; return new RangedSet ( firstIp , lastIp ) ; } param range public difference ( range ) { if ( range . getSize ( ) . gt ( this . getSize ( ) ) ) { throw new Error ( "Range is greater than range to be subtracted from" ) ; } if ( ! this . contains ( range ) ) { throw new Error ( "Range to subtract is not contained in this range" ) ; } let reminders = [ ] ; try { reminders . push ( new RangedSet ( this . getFirst ( ) , range . getFirst ( ) . previousIPNumber ( ) ) ) ; } catch ( e ) { } try { reminders . push ( new RangedSet ( range . getLast ( ) . nextIPNumber ( ) , this . getLast ( ) ) ) ; } catch ( e ) { } return reminders ; } public * take ( count ? ) { let computed = this . getFirst ( ) ; let returnCount = count === undefined ? this . getSize ( ) . valueOf ( ) : count ; while ( returnCount > 0 ) { returnCount -- ; yield computed ; computed = computed . nextIPNumber ( ) ; } } * [ Symbol . iterator ] ( ) { yield * this . take ( ) ; } private toIPv4CidrRange ( ) { let candidateRange = new IPv4CidrRange ( IPv4 . fromBigInteger ( this . getFirst ( ) . getValue ( ) ) , IPv4Prefix . fromRangeSize ( this . getSize ( ) ) ) ; if ( candidateRange . getFirst ( ) . isEquals ( this . getFirst ( ) ) ) { return candidateRange ; } else { throw new Error ( "Range cannot be converted to CIDR" ) ; } } private toIPv6CidrRange ( ) { let candidateRange = new IPv6CidrRange ( IPv6 . fromBigInteger ( this . getFirst ( ) . getValue ( ) ) , IPv6Prefix . fromRangeSize ( this . getSize ( ) ) ) ; if ( candidateRange . getFirst ( ) . isEquals ( this . getFirst ( ) ) ) { return candidateRange ; } else { throw new Error ( "Range cannot be converted to CIDR" ) ; } } } /**
 * Provides the implementation of functionality that are common to  IPv4CidrRange and  IPv6CidrRange export abstract class AbstractIPRange < T extends AbstractIPNum , P extends IPv4Prefix | IPv6Prefix > implements Iterable < AbstractIPNum > { abstract readonly bitValue : bigInt . BigInteger ; protected abstract newInstance ( num , prefix ) ; abstract getFirst ( ) ; abstract getLast ( ) ; abstract getPrefix ( ) ; abstract getSize ( ) ; abstract toCidrString ( ) ; public hasNextRange ( ) { let sizeOfCurrentRange = this . getSize ( ) ; return bigInt ( 2 ) . pow ( this . bitValue ) . minus ( sizeOfCurrentRange ) . greaterOrEquals ( this . getFirst ( ) . getValue ( ) . plus ( sizeOfCurrentRange ) ) ; } public hasPreviousRange ( ) { return this . getSize ( ) . lesserOrEquals ( this . getFirst ( ) . getValue ( ) ) ; } public toRangeSet ( ) { return new RangedSet ( this . getFirst ( ) , this . getLast ( ) ) ; } public inside ( otherRange ) { return this . toRangeSet ( ) . inside ( otherRange . toRangeSet ( ) ) ; } public contains ( otherRange ) { return this . toRangeSet ( ) . contains ( otherRange . toRangeSet ( ) ) ; } public toRangeString ( ) { return this . toRangeSet ( ) . toRangeString ( ) ; } public isOverlapping ( otherRange ) { return this . toRangeSet ( ) . isOverlapping ( otherRange . toRangeSet ( ) ) ; } public isConsecutive ( otherRange ) { return this . toRangeSet ( ) . isConsecutive ( otherRange . toRangeSet ( ) ) ; } public isCidrMergeable ( otherRange ) { let count = matchingBitCount ( this . getFirst ( ) . toBinaryString ( ) , otherRange . getFirst ( ) . toBinaryString ( ) ) ; if ( this . getPrefix ( ) . value - count !== 1 ) { return false ; } return this . isConsecutive ( otherRange ) && this . getSize ( ) . equals ( otherRange . getSize ( ) ) && this . getFirst ( ) . getValue ( ) . and ( count ) . eq ( otherRange . getFirst ( ) . getValue ( ) . and ( count ) ) ; } public isMergeable ( otherRange ) { return this . isCidrMergeable ( otherRange ) || this . contains ( otherRange ) || this . inside ( otherRange ) ; } public isEquals ( otherRange ) { return this . toRangeSet ( ) . isEquals ( otherRange . toRangeSet ( ) ) ; } public merge ( otherRange ) { if ( ! this . isCidrMergeable ( otherRange ) ) { throw new Error ( `Cannot merge. Ranges (${ this . toRangeString ( ) },${ otherRange . toRangeString ( ) }) are not consecutive and/or of same size` ) ; } return this . newInstance ( this . getFirst ( ) , this . getPrefix ( ) . merge ( ) ) ; } param count public * takeStream ( count ? ) { return this . toRangeSet ( ) . take ( count ) ; } * [ Symbol . iterator ] ( ) { yield * this . toRangeSet ( ) ; } } see https export class IPv4CidrRange extends AbstractIPRange < IPv4 , IPv4Prefix > { readonly bitValue : bigInt . BigInteger = bigInt ( 32 ) ; param { string } rangeIncidrNotation returns { IPv4CidrRange } static fromCidr ( rangeIncidrNotation ) { let [ isValid , errorMessages ] = Validator . isValidIPv4CidrNotation ( rangeIncidrNotation ) ; if ( ! isValid ) { let messages = errorMessages . filter ( message => { return message !== '' ; } ) ; throw new Error ( messages . join ( ' and ' ) ) ; } let cidrComponents = rangeIncidrNotation . split ( "/" ) ; let ipString = cidrComponents [ 0 ] ; let prefix = parseInt ( cidrComponents [ 1 ] ) ; return new IPv4CidrRange ( IPv4 . fromDecimalDottedString ( ipString ) , IPv4Prefix . fromNumber ( prefix ) ) ; } param { IPv4 } ipv4 param { IPv4Prefix } cidrPrefix constructor ( private readonly ipv4 , readonly cidrPrefix ) { super ( ) ; } returns { bigInt . BigInteger } public getSize ( ) { return this . cidrPrefix . toRangeSize ( ) ; } /**
     * Method that returns the IPv4 range in CIDR (Classless Inter-Domain Routing) notation.
     *
     * See  https for more information
     * on the Classless Inter-Domain Routing notation
     *
     *  returns { string } public toCidrString ( ) { let first = this . getFirst ( ) ; return `${ first . toString ( ) }/${ this . cidrPrefix . toString ( ) }` ; } returns { string } public toRangeString ( ) { return super . toRangeString ( ) ; } returns { IPv4 } public getFirst ( ) { return IPv4 . fromBigInteger ( this . ipv4 . getValue ( ) . and ( this . cidrPrefix . toMask ( ) . getValue ( ) ) ) ; } returns { IPv4 } public getLast ( ) { return last ( this , this . ipv4 ) as IPv4 ; } protected newInstance ( num , prefix ) { return new IPv4CidrRange ( num , prefix ) ; } public getPrefix ( ) { return this . cidrPrefix ; } param { IPv4CidrRange } otherRange returns { boolean } public isConsecutive ( otherRange ) { return super . isConsecutive ( otherRange ) ; } param { IPv4CidrRange } otherRange returns { boolean } public contains ( otherRange ) { return super . contains ( otherRange ) ; } param { IPv4CidrRange } otherRange returns { boolean } public inside ( otherRange ) { return super . inside ( otherRange ) ; } param { IPv4CidrRange } otherRange returns { boolean } public isOverlapping ( otherRange ) { return super . isOverlapping ( otherRange ) ; } param { number } count returns { Array < IPv4 > } public take ( count ) { let ipv4s = [ this . getFirst ( ) ] ; let iteratingIPv4 = this . getFirst ( ) ; if ( bigInt ( count ) . greater ( this . getSize ( ) ) ) { let errMessage = Validator . takeOutOfRangeSizeMessage . replace ( "$count" , count . toString ( ) ) . replace ( "$size" , this . getSize ( ) . toString ( ) ) ; throw new Error ( errMessage ) ; } for ( var counter = 0 ; counter < count . minus ( 1 ) . valueOf ( ) ; counter ++ ) { ipv4s . push ( iteratingIPv4 . nextIPNumber ( ) ) ; iteratingIPv4 = iteratingIPv4 . nextIPNumber ( ) ; } return ipv4s ; } returns { Array < IPv4CidrRange > } An array of two  IPv4CidrRange public split ( ) { let prefixToSplit = this . cidrPrefix . getValue ( ) ; if ( prefixToSplit === 32 ) { throw new Error ( "Cannot split an IP range with a single IP number" ) ; } let splitCidr = IPv4Prefix . fromNumber ( prefixToSplit + 1 ) ; let firstIPOfFirstRange = this . getFirst ( ) ; let firstRange = new IPv4CidrRange ( firstIPOfFirstRange , splitCidr ) ; let firstIPOfSecondRange = firstRange . getLast ( ) . nextIPNumber ( ) ; let secondRange = new IPv4CidrRange ( firstIPOfSecondRange , splitCidr ) ; return [ firstRange , secondRange ] ; } param prefix returns { Array < IPv4CidrRange > } An array of two  IPv4CidrRange public splitInto ( prefix ) { let splitCount = prefix . getValue ( ) - this . cidrPrefix . getValue ( ) ; if ( splitCount < 0 ) { throw new Error ( "Prefix to split into is larger than source prefix" ) ; } else if ( splitCount === 0 ) { return [ new IPv4CidrRange ( this . getFirst ( ) , prefix ) ] ; } else if ( splitCount === 1 ) { return this . split ( ) ; } else { let results = this . split ( ) ; while ( splitCount > 1 ) { results = results . flatMap ( result => result . split ( ) ) ; splitCount = splitCount - 1 ; } return results ; } } /**
     * Returns true if there is an adjacent IPv4 cidr range of exactly the same size next to this range
     */ public hasNextRange ( ) { return super . hasNextRange ( ) ; } /**
     * Returns true if there is an adjacent IPv4 cidr range of exactly the same size previous to this range
     */ public hasPreviousRange ( ) { return super . hasPreviousRange ( ) ; } /**
     * Return the next IPv6 cidr range, or undefined if no next range
     */ public nextRange ( ) { if ( this . hasNextRange ( ) ) { let sizeOfCurrentRange = this . getSize ( ) ; let startOfNextRange = this . getFirst ( ) . getValue ( ) . plus ( sizeOfCurrentRange ) ; return new IPv4CidrRange ( new IPv4 ( startOfNextRange ) , this . cidrPrefix ) ; } return ; } /**
     * Return the previous IPv6 cidr range, or undefined if no next range
     */ public previousRange ( ) { if ( this . hasPreviousRange ( ) ) { let sizeOfCurrentRange = this . getSize ( ) ; let startOfPreviousRange = this . getFirst ( ) . getValue ( ) . minus ( sizeOfCurrentRange ) ; return new IPv4CidrRange ( new IPv4 ( startOfPreviousRange ) , this . cidrPrefix ) ; } return ; } } see https export class IPv6CidrRange extends AbstractIPRange < IPv6 , IPv6Prefix > { readonly bitValue : bigInt . BigInteger = bigInt ( 128 ) ; param { string } rangeInCidrNotation returns { IPv6CidrRange } static fromCidr ( rangeInCidrNotation ) { let [ isValid , message ] = Validator . isValidIPv6CidrNotation ( rangeInCidrNotation ) ; if ( ! isValid ) { throw new Error ( message . filter ( msg => { return msg !== '' ; } ) . toString ( ) ) ; } let cidrComponents = rangeInCidrNotation . split ( "/" ) ; let ipString = cidrComponents [ 0 ] ; let prefix = parseInt ( cidrComponents [ 1 ] ) ; return new IPv6CidrRange ( IPv6 . fromHexadecimalString ( ipString ) , IPv6Prefix . fromNumber ( prefix ) ) ; } ; param { IPv6 } ipv6 param { IPv6Prefix } cidrPrefix constructor ( private readonly ipv6 , readonly cidrPrefix ) { super ( ) ; } returns { bigInt . BigInteger } public getSize ( ) { return this . cidrPrefix . toRangeSize ( ) ; } /**
     * Method that returns the IPv6 range in CIDR (Classless Inter-Domain Routing) notation.
     *
     * See  https for more information
     * on the Classless Inter-Domain Routing notation
     *
     *  returns { string } public toCidrString ( ) { let first = this . getFirst ( ) ; return `${ first . toString ( ) }/${ this . cidrPrefix . toString ( ) }` ; } returns { string } public toRangeString ( ) { return super . toRangeString ( ) ; } returns { IPv6 } public getFirst ( ) { return IPv6 . fromBigInteger ( this . ipv6 . getValue ( ) . and ( this . cidrPrefix . toMask ( ) . getValue ( ) ) ) ; } returns { IPv6 } public getLast ( ) { return last ( this , this . ipv6 ) as IPv6 ; } protected newInstance ( num , prefix ) { return new IPv6CidrRange ( num , prefix ) ; } public getPrefix ( ) { return this . cidrPrefix ; } param { IPv6CidrRange } otherRange returns { boolean } public isConsecutive ( otherRange ) { return super . isConsecutive ( otherRange ) ; } param { IPv6CidrRange } otherRange returns { boolean } public contains ( otherRange ) { return super . contains ( otherRange ) ; } param { IPv6CidrRange } otherRange returns { boolean } public inside ( otherRange ) { return super . inside ( otherRange ) ; } param { IPv6CidrRange } otherRange returns { boolean } public isOverlapping ( otherRange ) { return super . isOverlapping ( otherRange ) ; } param { number } count returns { Array < IPv6 > } public take ( count ) { let iPv6s = [ this . getFirst ( ) ] ; let iteratingIPv6 = this . getFirst ( ) ; if ( count . greater ( this . getSize ( ) ) ) { throw new Error ( `${ count . toString ( ) } is greater than ${ this . getSize ( ) . toString ( ) }, the size of the range` ) ; } for ( var counter = 0 ; counter < count . minus ( 1 ) . valueOf ( ) ; counter ++ ) { iPv6s . push ( iteratingIPv6 . nextIPNumber ( ) ) ; iteratingIPv6 = iteratingIPv6 . nextIPNumber ( ) ; } return iPv6s ; } returns { Array < IPv6CidrRange > } An array of two  IPv6CidrRange public split ( ) { let prefixToSplit = this . cidrPrefix . getValue ( ) ; if ( prefixToSplit === 128 ) { throw new Error ( "Cannot split an IP range with a single IP number" ) ; } let splitCidr = IPv6Prefix . fromNumber ( prefixToSplit + 1 ) ; let firstIPOfFirstRange = this . getFirst ( ) ; let firstRange = new IPv6CidrRange ( firstIPOfFirstRange , splitCidr ) ; let firstIPOfSecondRange = firstRange . getLast ( ) . nextIPNumber ( ) ; let secondRange = new IPv6CidrRange ( firstIPOfSecondRange , splitCidr ) ; return [ firstRange , secondRange ] ; } param prefix returns { Array < IPv6CidrRange > } An array of two  IPv6CidrRange public splitInto ( prefix ) { let splitCount = prefix . getValue ( ) - this . cidrPrefix . getValue ( ) ; if ( splitCount < 0 ) { throw new Error ( "Prefix to split into is larger than source prefix" ) ; } else if ( splitCount === 0 ) { return [ new IPv6CidrRange ( this . getFirst ( ) , prefix ) ] ; } else if ( splitCount === 1 ) { return this . split ( ) ; } else { let results = this . split ( ) ; while ( splitCount > 1 ) { results = results . flatMap ( result => result . split ( ) ) ; splitCount = splitCount - 1 ; } return results ; } } /**
     * Returns true if there is an adjacent IPv6 cidr range of exactly the same size next to this range
     */ public hasNextRange ( ) { return super . hasNextRange ( ) ; } /**
     * Returns true if there is an adjacent IPv6 cidr range of exactly the same size previous to this range
     */ public hasPreviousRange ( ) { return super . hasPreviousRange ( ) ; } /**
     * Return the next IPv6 cidr range, or undefined if no next range
     */ public nextRange ( ) { if ( this . hasNextRange ( ) ) { let sizeOfCurrentRange = this . getSize ( ) ; let startOfNextRange = this . getFirst ( ) . getValue ( ) . plus ( sizeOfCurrentRange ) ; return new IPv6CidrRange ( new IPv6 ( startOfNextRange ) , this . cidrPrefix ) ; } return ; } /**
     * Return the previous IPv6 cidr range, or undefined if no next range
     */ public previousRange ( ) { if ( this . hasPreviousRange ( ) ) { let sizeOfCurrentRange = this . getSize ( ) ; let startOfPreviousRange = this . getFirst ( ) . getValue ( ) . minus ( sizeOfCurrentRange ) ; return new IPv6CidrRange ( new IPv6 ( startOfPreviousRange ) , this . cidrPrefix ) ; } return ; } } let last = ( range , ip ) : IPv6 | IPv4 => { let bitValue = range . bitValue . valueOf ( ) ; let maskSize = bigInt ( "1" . repeat ( bitValue ) , 2 ) ; let maskAsBigInteger = range . cidrPrefix . toMask ( ) . getValue ( ) ; let invertedMask = leftPadWithZeroBit ( maskAsBigInteger . xor ( maskSize ) . toString ( 2 ) , bitValue ) ; if ( isIPv4CidrRange ( range ) ) { return IPv4 . fromBigInteger ( ip . getValue ( ) . or ( parseBinaryStringToBigInteger ( invertedMask ) ) ) ; } else { return IPv6 . fromBigInteger ( ip . getValue ( ) . or ( parseBinaryStringToBigInteger ( invertedMask ) ) ) ; } } ; export function isIPv4CidrRange < T > ( ip ) { return ip . bitValue . valueOf ( ) === 32 ; }