///|
pub struct Ipv4Summary {
networks : Array[Ipv4Network]
} derive(Debug)
///|
pub fn Ipv4Summary::from_ranges(
ranges : Array[Ipv4Range],
) -> Result[Ipv4Summary, CidrError] {
let result = Array::new()
for range in ranges {
append_range_summary(result, range)
}
Ok({ networks: normalize_summary_networks(result) })
}
///|
pub fn Ipv4Summary::from_addresses(
addresses : Array[Ipv4Address],
) -> Ipv4Summary {
let networks = Array::new()
for address in addresses {
networks.push(Ipv4Network::new(address, 32).unwrap())
}
{ networks: normalize_summary_networks(networks) }
}
///|
pub fn Ipv4Summary::from_networks(networks : Array[Ipv4Network]) -> Ipv4Summary {
let sorted = networks.copy()
{ networks: normalize_summary_networks(sorted) }
}
///|
pub fn Ipv4Summary::networks(self : Ipv4Summary) -> Array[Ipv4Network] {
self.networks.copy()
}
///|
pub fn Ipv4Summary::len(self : Ipv4Summary) -> Int {
self.networks.length()
}
///|
pub fn Ipv4Summary::contains(self : Ipv4Summary, address : Ipv4Address) -> Bool {
for network in self.networks {
if network.contains(address) {
return true
}
}
false
}
///|
pub fn Ipv4Summary::to_string(self : Ipv4Summary) -> String {
let mut text = ""
let mut index = 0
for network in self.networks {
if index > 0 {
text = text + ", "
}
text = text + network.to_string()
index = index + 1
}
text
}
///|
fn normalize_summary_networks(
networks : Array[Ipv4Network],
) -> Array[Ipv4Network] {
let normalized = Ipv4NetworkSet::from_array(networks).to_array()
sort_networks(normalized)
collapse_adjacent_networks(normalized)
}
///|
fn append_range_summary(result : Array[Ipv4Network], range : Ipv4Range) -> Unit {
let mut current = range.start().to_uint()
let end = range.end().to_uint()
if current == 0U && end == 4294967295U {
result.push(Ipv4Network::new(Ipv4Address::zero(), 0).unwrap())
return
}
while current <= end {
let max_size = largest_aligned_block(current)
let remaining = end - current + 1U
let block_size = clamp_block_size(max_size, remaining)
let prefix = prefix_from_block_size(block_size)
result.push(
Ipv4Network::new(Ipv4Address::from_uint(current), prefix).unwrap(),
)
if block_size > 4294967295U - current {
return
}
current = current + block_size
}
}
///|
fn largest_aligned_block(value : UInt) -> UInt {
if value == 0U {
2147483648U
} else {
let mut size = 1U
while (value & size) == 0U && size < 2147483648U {
size = size << 1
}
size
}
}
///|
fn clamp_block_size(size : UInt, remaining : UInt) -> UInt {
let mut block = size
while block > remaining {
block = block >> 1
}
block
}
///|
fn prefix_from_block_size(size : UInt) -> Int {
let mut bits = 0
let mut value = size
while value > 1U {
bits = bits + 1
value = value >> 1
}
32 - bits
}
///|
fn collapse_adjacent_networks(input : Array[Ipv4Network]) -> Array[Ipv4Network] {
let current = input.copy()
let mut changed = true
while changed {
changed = false
let next = Array::new()
let mut index = 0
while index < current.length() {
if index + 1 < current.length() {
match try_merge_pair(current[index], current[index + 1]) {
Some(merged) => {
next.push(merged)
index = index + 2
changed = true
}
None => {
next.push(current[index])
index = index + 1
}
}
} else {
next.push(current[index])
index = index + 1
}
}
current.clear()
for item in next {
current.push(item)
}
sort_networks(current)
}
current
}
///|
fn try_merge_pair(left : Ipv4Network, right : Ipv4Network) -> Ipv4Network? {
if left.prefix() != right.prefix() ||
!left.is_adjacent_to(right) ||
left.prefix() == 0 {
None
} else {
let parent = left.parent().unwrap()
if parent.contains_network(left) && parent.contains_network(right) {
Some(parent)
} else {
None
}
}
}