refactoring: represent binary ip as a string of length 32

This commit is contained in:
Павел
2025-01-08 22:29:17 +03:00
parent ddcb043caa
commit 604861aa80
+34 -25
View File
@@ -1,6 +1,8 @@
from copy import deepcopy from copy import deepcopy
from ipaddress import IPv4Address from ipaddress import IPv4Address
from typing import List, Tuple from typing import List, Tuple
from itertools import groupby
from collections import defaultdict
def get_data(input_file): def get_data(input_file):
@@ -15,43 +17,45 @@ def cidr4_to_binary(cidr4: str) -> str:
ipv4 = IPv4Address(ip_str) ipv4 = IPv4Address(ip_str)
binary_ip = bin(int(ipv4))[2:] binary_ip = bin(int(ipv4))[2:]
binary_ip = binary_ip.zfill(32) binary_ip = binary_ip.zfill(32)
binary = binary_ip[:vlsm] binary = binary_ip[:vlsm] + "0" * (32 - vlsm)
return binary return binary
def binary_to_cidr4(binary: str) -> str: def binary_to_cidr4(binary: str) -> str:
vlsm = len(binary) vlsm = binary.rfind("1") + 1 if "1" in binary else 0
binary_ip = binary + "0" * (32 - vlsm) int_ip = int(binary, 2)
int_ip = int(binary_ip, 2)
ip = IPv4Address(int_ip) ip = IPv4Address(int_ip)
return f"{ip}/{vlsm}" return f"{ip}/{vlsm}"
def reduce_binary(binary: str) -> str: def reduce_binary(binary: str) -> str:
if len(binary) == 0: assert len(binary) == 32
return "" vlsm = binary.rfind("1")
new_binary = binary[:-1] if vlsm == -1:
if "1" not in new_binary: return binary
return "" return binary[:vlsm] + "0" + binary[vlsm + 1 :]
return new_binary
def rough_merge_binaries(binaries: List[str], req_len: int) -> List[str]: def rough_merge_binaries(binaries: List[str], req_len: int) -> List[str]:
ips = set(deepcopy(binaries)) ips = set(deepcopy(binaries))
non_reducible_ips = set() non_reducible_ips = set()
reduction_limit_reached = False reduction_limit_reached = False
max_vlsm = float("inf")
while ( while (
len(ips) > 0 len(ips) > 0
and len(ips) + len(non_reducible_ips) > req_len and len(ips) + len(non_reducible_ips) > req_len
and not reduction_limit_reached and not reduction_limit_reached
and max_vlsm != -1
): ):
max_vlsm = len(max(ips, key=lambda x: len(x))) ip_with_max_vlsm = max(ips, key=lambda x: x.rfind("1"))
max_vlsm = ip_with_max_vlsm.rfind("1")
print(f"{max_vlsm=}")
reduced_ips = set() reduced_ips = set()
merged_ips = set() merged_ips = set()
for ip in ips: for ip in ips:
if len(ip) == max_vlsm: if ip.rfind("1") == max_vlsm:
reduced_ip = reduce_binary(ip) reduced_ip = reduce_binary(ip)
if len(reduced_ip) > 0: if "1" in reduced_ip:
reduced_ips.add(reduced_ip) reduced_ips.add(reduced_ip)
else: else:
non_reducible_ips.add(ip) non_reducible_ips.add(ip)
@@ -62,6 +66,7 @@ def rough_merge_binaries(binaries: List[str], req_len: int) -> List[str]:
ips = merged_ips ips = merged_ips
else: else:
reduction_limit_reached = True reduction_limit_reached = True
print(f"{len(ips)=}")
ips.update(non_reducible_ips) ips.update(non_reducible_ips)
return sorted(ips) return sorted(ips)
@@ -73,6 +78,7 @@ def main():
data = get_data(file) data = get_data(file)
bin_ips = list(map(cidr4_to_binary, data)) bin_ips = list(map(cidr4_to_binary, data))
rough_merged_bin_ips = rough_merge_binaries(bin_ips, required_len) rough_merged_bin_ips = rough_merge_binaries(bin_ips, required_len)
print(f"{len(rough_merged_bin_ips)=}") print(f"{len(rough_merged_bin_ips)=}")
for ip in rough_merged_bin_ips: for ip in rough_merged_bin_ips:
@@ -80,19 +86,22 @@ def main():
if __name__ == "__main__": if __name__ == "__main__":
assert cidr4_to_binary("4.78.139.0/24") == "000001000100111010001011" assert cidr4_to_binary("4.78.139.0/24") == "00000100010011101000101100000000"
assert cidr4_to_binary("128.0.0.0/1") == "1" assert cidr4_to_binary("128.0.0.0/1") == "10000000000000000000000000000000"
assert cidr4_to_binary("0.0.0.0/0") == "" assert cidr4_to_binary("0.0.0.0/0") == "0" * 32
assert cidr4_to_binary("0.8.0.0/13") == "00000000000010000000000000000000"
assert binary_to_cidr4("000001000100111010001011") == "4.78.139.0/24" assert binary_to_cidr4("00000100010011101000101100000000") == "4.78.139.0/24"
assert binary_to_cidr4("1") == "128.0.0.0/1" assert binary_to_cidr4("10000000000000000000000000000000") == "128.0.0.0/1"
assert binary_to_cidr4("") == "0.0.0.0/0" assert binary_to_cidr4("00000000000000000000000000000000") == "0.0.0.0/0"
assert binary_to_cidr4("00000000000010000000000000000000") == "0.8.0.0/13"
assert reduce_binary("000001000100111010001011") == "00000100010011101000101" assert (
assert reduce_binary("1") == "" reduce_binary("00000100010011101000101100000000")
assert reduce_binary("0") == "" == "00000100010011101000101000000000"
assert reduce_binary("") == "" )
assert reduce_binary("0001") == "" assert reduce_binary("10000000000000000000000000000000") == "0" * 32
assert reduce_binary("0000") == "" assert reduce_binary("0" * 32) == "0" * 32
assert reduce_binary("00000000000010000000000000000000") == "0" * 32
main() main()