Skip to content

Commit

Permalink
Introduced AbstractIpRange to share common logic between IPv4Range an…
Browse files Browse the repository at this point in the history
…d IPv6Range
  • Loading branch information
dadepo committed Aug 26, 2018
1 parent 25bed96 commit 7e9f321
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 97 deletions.
73 changes: 73 additions & 0 deletions src/AbstractIpRange.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import * as bigInt from "big-integer";
import {Prefix} from "./Prefix";
import {IPv6} from "./IPv6";
import {IPv6Range} from "./IPv6Range";
import {IPv4Range} from "./IPv4Range";
import {IPv4} from "./IPv4";

/**
* Provides the implementation of functionality that are common to {@link IPRange}s
*/

export abstract class AbstractIpRange {

abstract readonly bitValue: bigInt.BigInteger;
abstract readonly cidrPrefix: Prefix;
abstract getFirst(): IPv6 | IPv4
abstract getLast(): IPv6 | IPv4

public getSize(): bigInt.BigInteger {
/**
* Using bitwise shit operation this will be
* 1 << (this.bitValue - this.prefix.getValue())
* Since left shift a number by x is equivalent to multiplying the number by the power x raised to 2
* 2 << 4 = 2 * (2 raised to 4)
*/
return bigInt(2).pow(this.bitValue.minus(bigInt(this.cidrPrefix.getValue())));
}

public inside(otherRange: IPv6Range | IPv4Range): boolean {
let thisFirst: IPv6 | IPv4 = this.getFirst();
let thisLast: IPv6 | IPv4 = this.getLast();
let otherFirst: IPv6 | IPv4 = otherRange.getFirst();
let otherLast: IPv6 | IPv4 = otherRange.getLast();

return (otherFirst.isLessThanOrEquals(thisFirst) && otherLast.isGreaterThanOrEquals(thisLast));
}

public contains(otherRange: IPv6Range | IPv4Range): boolean {
let thisFirst: IPv6 | IPv4 = this.getFirst();
let thisLast: IPv6 | IPv4 = this.getLast();
let otherFirst: IPv6 | IPv4 = otherRange.getFirst();
let otherLast: IPv6 | IPv4 = otherRange.getLast();

return (thisFirst.isLessThanOrEquals(otherFirst) && thisLast.isGreaterThanOrEquals(otherLast));
}

public isOverlapping(otherRange: IPv6Range | IPv4Range): boolean {
let thisFirst: IPv6 | IPv4 = this.getFirst();
let thisLast: IPv6 | IPv4 = this.getLast();
let otherFirst: IPv6 | IPv4 = otherRange.getFirst();
let otherLast: IPv6 | IPv4 = otherRange.getLast();

return (
thisLast.isGreaterThan(otherFirst) && thisLast.isLessThanOrEquals(otherLast) && thisFirst.isLessThan(otherFirst)
||
otherLast.isGreaterThan(thisFirst) && otherLast.isLessThanOrEquals(thisLast) && otherFirst.isLessThan(otherFirst)
);
}

public isConsecutive(otherRange: IPv6Range | IPv4Range): boolean {
let thisFirst: IPv6 | IPv4 = this.getFirst();
let thisLast: IPv6 | IPv4 = this.getLast();
let otherFirst: IPv6 | IPv4 = otherRange.getFirst();
let otherLast: IPv6 | IPv4 = otherRange.getLast();

return (
thisLast.hasNext() && thisLast.nextIPNumber().isEquals(otherFirst)
||
otherLast.hasNext() && otherLast.nextIPNumber().isEquals(thisFirst)
)
}

}
56 changes: 10 additions & 46 deletions src/IPv4Range.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,16 @@ import {parseBinaryStringToBigInteger} from "./BinaryUtils";
import {Validator} from "./Validator";
import * as bigInt from "big-integer";
import {IPRange} from "./interface/IPRange";
import {AbstractIpRange} from "./AbstractIpRange";

/**
* Represents a continuous segment of IPv4 numbers following the
* classless inter-domain routing scheme for allocating IP addresses.
*
* @see https://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing
*/
export class IPv4Range implements IPRange, IterableIterator<IPv4> {
private readonly bitValue: bigInt.BigInteger = bigInt(32);
export class IPv4Range extends AbstractIpRange implements IPRange, IterableIterator<IPv4> {
readonly bitValue: bigInt.BigInteger = bigInt(32);
private internalCounterValue: IPv4;

/**
Expand All @@ -22,7 +23,6 @@ export class IPv4Range implements IPRange, IterableIterator<IPv4> {
* @param {string} rangeIncidrNotation the range of the IPv4 number in CIDR notation
* @returns {IPv4Range} the IPv4Range
*/
// TODO introduce an abstract class to share some of the logic between IPv4Range and IPv6Range
static fromCidr(rangeIncidrNotation:string):IPv4Range {
let [isValid, errorMessages] = Validator.isValidIPv4CidrNotation(rangeIncidrNotation);
if (!isValid) {
Expand All @@ -46,7 +46,8 @@ export class IPv4Range implements IPRange, IterableIterator<IPv4> {
* @param {IPv4Prefix} cidrPrefix the prefix which is a representation of the number of bits used to mask the
* given IP number in other to create the range
*/
constructor(private readonly ipv4: IPv4, private readonly cidrPrefix: IPv4Prefix) {
constructor(private readonly ipv4: IPv4, readonly cidrPrefix: IPv4Prefix) {
super();
this.internalCounterValue = this.getFirst();
}

Expand All @@ -56,13 +57,7 @@ export class IPv4Range implements IPRange, IterableIterator<IPv4> {
* @returns {bigInt.BigInteger} the amount of IPv4 numbers in the range
*/
public getSize(): bigInt.BigInteger {
/**
* Using bitwise shit operation this will be
* 1 << (this.bitValue - this.prefix.getValue())
* Since left shift a number by x is equivalent to multiplying the number by the power x raised to 2
* 2 << 4 = 2 * (2 raised to 4)
*/
return bigInt(2).pow(this.bitValue.minus(bigInt(this.cidrPrefix.getValue())));
return super.getSize();
}

/**
Expand Down Expand Up @@ -118,18 +113,8 @@ export class IPv4Range implements IPRange, IterableIterator<IPv4> {
* @param {IPv4Range} otherRange the other IPv4 range to compare with
* @returns {boolean} true if the two IPv4 ranges are consecutive, false otherwise
*/
// TODO move this to the IPRange interface?
public isConsecutive(otherRange: IPv4Range): boolean {
let thisFirst: IPv4 = this.getFirst();
let thisLast: IPv4 = this.getLast();
let otherFirst: IPv4 = otherRange.getFirst();
let otherLast: IPv4 = otherRange.getLast();

return (
thisLast.hasNext() && thisLast.nextIPNumber().isEquals(otherFirst)
||
otherLast.hasNext() && otherLast.nextIPNumber().isEquals(thisFirst)
)
return super.isConsecutive(otherRange);
}

/**
Expand All @@ -140,14 +125,8 @@ export class IPv4Range implements IPRange, IterableIterator<IPv4> {
* @param {IPv4Range} otherRange the other IPv4 range
* @returns {boolean} true if the other Ipv4 range is a subset. False otherwise.
*/
// TODO move this to the IPRange interface?
public contains(otherRange: IPv4Range): boolean {
let thisFirst: IPv4 = this.getFirst();
let thisLast: IPv4 = this.getLast();
let otherFirst: IPv4 = otherRange.getFirst();
let otherLast: IPv4 = otherRange.getLast();

return (thisFirst.isLessThanOrEquals(otherFirst) && thisLast.isGreaterThanOrEquals(otherLast));
return super.contains(otherRange);
}

/**
Expand All @@ -159,31 +138,16 @@ export class IPv4Range implements IPRange, IterableIterator<IPv4> {
* @returns {boolean} true if the other Ipv4 range is a container range. False otherwise.
*/
public inside(otherRange: IPv4Range): boolean {
let thisFirst: IPv4 = this.getFirst();
let thisLast: IPv4 = this.getLast();
let otherFirst: IPv4 = otherRange.getFirst();
let otherLast: IPv4 = otherRange.getLast();

return (otherFirst.isLessThanOrEquals(thisFirst) && otherLast.isGreaterThanOrEquals(thisLast));
return super.inside(otherRange);
}

/**
* Checks if two IPv4 ranges overlap
* @param {IPv4Range} otherRange the other IPv4 range
* @returns {boolean} true if the ranges overlap, false otherwise
*/
// TODO or confirm than normal ranges cannot overlap
public isOverlapping(otherRange: IPv4Range): boolean {
let thisFirst: IPv4 = this.getFirst();
let thisLast: IPv4 = this.getLast();
let otherFirst: IPv4 = otherRange.getFirst();
let otherLast: IPv4 = otherRange.getLast();

return (
thisLast.isGreaterThan(otherFirst) && thisLast.isLessThanOrEquals(otherLast) && thisFirst.isLessThan(otherFirst)
||
otherLast.isGreaterThan(thisFirst) && otherLast.isLessThanOrEquals(thisLast) && otherFirst.isLessThan(otherFirst)
);
return super.isOverlapping(otherRange);
}

/**
Expand Down
59 changes: 11 additions & 48 deletions src/IPv6Range.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,16 @@ import {leftPadWithZeroBit} from "./BinaryUtils";
import {parseBinaryStringToBigInteger} from "./BinaryUtils";
import {Validator} from "./Validator";
import {IPRange} from "./interface/IPRange";
import {AbstractIpRange} from "./AbstractIpRange";

/**
* Represents a continuous segment of IPv6 number following the
* classless inter-domain routing scheme for allocating IP addresses.
*
* @see https://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing
*/
// TODO introduce an abstract class to share some of the logic between IPv4Range and IPv6Range
export class IPv6Range implements IPRange, IterableIterator<IPv6> {
private readonly bitValue: bigInt.BigInteger = bigInt(128);
export class IPv6Range extends AbstractIpRange implements IPRange, IterableIterator<IPv6> {
readonly bitValue: bigInt.BigInteger = bigInt(128);
private internalCounterValue: IPv6;

/**
Expand All @@ -41,12 +41,13 @@ export class IPv6Range implements IPRange, IterableIterator<IPv6> {
* The arguments taken by the constructor is inspired by the CIDR notation which basically consists of the IP
* number and the prefix.
*
* @param {IPv6} IPv6 the IP number used to construct the range. By convention this is the first IP number in
* @param {IPv6} ipv6 the IP number used to construct the range. By convention this is the first IP number in
* the range, but it could also be any IP number within the range
* @param {IPv6Prefix} cidrPrefix the prefix which is a representation of the number of bits used to mask the
* given IPv6 number in other to create the range
*/
constructor(private readonly ipv6: IPv6, private readonly cidrPrefix: IPv6Prefix) {
constructor(private readonly ipv6: IPv6, readonly cidrPrefix: IPv6Prefix) {
super();
this.internalCounterValue = this.getFirst();
}

Expand All @@ -56,13 +57,7 @@ export class IPv6Range implements IPRange, IterableIterator<IPv6> {
* @returns {bigInt.BigInteger} the amount of IPv6 numbers in the range
*/
public getSize(): bigInt.BigInteger {
/**
* Using bitwise shit operation this will be
* 1 << (this.bitValue - this.prefix.getValue())
* Since left shift a number by x is equivalent to multiplying the number by the power x raised to 2
* 2 << 4 = 2 * (2 raised to 4)
*/
return bigInt(2).pow(this.bitValue.minus(bigInt(this.cidrPrefix.getValue())));
return super.getSize();
}

/**
Expand Down Expand Up @@ -117,18 +112,8 @@ export class IPv6Range implements IPRange, IterableIterator<IPv6> {
* @param {IPv6Range} otherRange the other IPv6 range to compare with
* @returns {boolean} true if the two IPv6 ranges are consecutive, false otherwise
*/
// TODO move this to the IPRange interface?
public isConsecutive(otherRange: IPv6Range): boolean {
let thisFirst: IPv6 = this.getFirst();
let thisLast: IPv6 = this.getLast();
let otherFirst: IPv6 = otherRange.getFirst();
let otherLast: IPv6 = otherRange.getLast();

return (
thisLast.hasNext() && thisLast.nextIPNumber().isEquals(otherFirst)
||
otherLast.hasNext() && otherLast.nextIPNumber().isEquals(thisFirst)
)
return super.isConsecutive(otherRange);
}

/**
Expand All @@ -139,14 +124,8 @@ export class IPv6Range implements IPRange, IterableIterator<IPv6> {
* @param {IPv6Range} otherRange the other IPv6 range
* @returns {boolean} true if the other Ipv6 range is a subset. False otherwise.
*/
// TODO move this to the IPRange interface?
public contains(otherRange: IPv6Range): boolean {
let thisFirst: IPv6 = this.getFirst();
let thisLast: IPv6 = this.getLast();
let otherFirst: IPv6 = otherRange.getFirst();
let otherLast: IPv6 = otherRange.getLast();

return (thisFirst.isLessThanOrEquals(otherFirst) && thisLast.isGreaterThanOrEquals(otherLast));
return super.contains(otherRange);
}

/**
Expand All @@ -157,33 +136,17 @@ export class IPv6Range implements IPRange, IterableIterator<IPv6> {
* @param {IPv6Range} otherRange he other IPv6 range
* @returns {boolean} true if the other Ipv6 range is a container range. False otherwise.
*/
// TODO move this to the IPRange interface?
public inside(otherRange: IPv6Range): boolean {
let thisFirst: IPv6 = this.getFirst();
let thisLast: IPv6 = this.getLast();
let otherFirst: IPv6 = otherRange.getFirst();
let otherLast: IPv6 = otherRange.getLast();

return (otherFirst.isLessThanOrEquals(thisFirst) && otherLast.isGreaterThanOrEquals(thisLast));
return super.inside(otherRange);
}

/**
* Checks if two IPv6 ranges overlap
* @param {IPv6Range} otherRange the other IPv6 range
* @returns {boolean} true if the ranges overlap, false otherwise
*/
// TODO or confirm than normal ranges cannot overlap
public isOverlapping(otherRange: IPv6Range): boolean {
let thisFirst: IPv6 = this.getFirst();
let thisLast: IPv6 = this.getLast();
let otherFirst: IPv6 = otherRange.getFirst();
let otherLast: IPv6 = otherRange.getLast();

return (
thisLast.isGreaterThan(otherFirst) && thisLast.isLessThanOrEquals(otherLast) && thisFirst.isLessThan(otherFirst)
||
otherLast.isGreaterThan(thisFirst) && otherLast.isLessThanOrEquals(thisLast) && otherFirst.isLessThan(otherFirst)
);
return super.isOverlapping(otherRange);
}

/**
Expand Down
12 changes: 9 additions & 3 deletions src/Prefix.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@ import {IPv6SubnetMask} from "./SubnetMask";
import {binaryStringToHexadecimalString} from "./HexadecimalUtils";
import {Hexadecatet} from "./Hexadecatet";


interface Prefix {
value: number;
getValue(): number;
}

/**
* Represents the prefix portion in the CIDR notation for representing IP ranges
*
Expand All @@ -14,7 +20,7 @@ import {Hexadecatet} from "./Hexadecatet";
*
* {@see https://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing} for more information on CIDR
*/
class IPv4Prefix {
class IPv4Prefix implements Prefix {
/**
* The decimal value of the 8bit number representing the prefix
*/
Expand Down Expand Up @@ -89,7 +95,7 @@ class IPv4Prefix {
*
* {@see https://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing} for more information on CIDR
*/
class IPv6Prefix {
class IPv6Prefix implements Prefix {
/**
* The decimal value of the 16bit number representing the prefix
*/
Expand Down Expand Up @@ -160,4 +166,4 @@ class IPv6Prefix {
}
}

export {IPv4Prefix, IPv6Prefix}
export {Prefix, IPv4Prefix, IPv6Prefix}

0 comments on commit 7e9f321

Please sign in to comment.