add merge_nodes function
This commit is contained in:
@@ -6,6 +6,7 @@ from vpn_manager.cidr4_merge.cidr4_merger import (
|
|||||||
cidr4_to_node,
|
cidr4_to_node,
|
||||||
find_parent,
|
find_parent,
|
||||||
make_cidr4,
|
make_cidr4,
|
||||||
|
merge_nodes,
|
||||||
merge_two_nodes,
|
merge_two_nodes,
|
||||||
sort_nodes,
|
sort_nodes,
|
||||||
)
|
)
|
||||||
@@ -89,20 +90,54 @@ def test_find_parent__with_exception():
|
|||||||
|
|
||||||
|
|
||||||
def test_calc_dip():
|
def test_calc_dip():
|
||||||
assert calc_dip(32, 32) == 0
|
assert calc_dip(32, 32, 31) == 0
|
||||||
assert calc_dip(32, 31) == 2
|
assert calc_dip(32, 32, 30) == 2
|
||||||
assert calc_dip(32, 30) == 4
|
assert calc_dip(32, 32, 29) == 6
|
||||||
assert calc_dip(31, 30) == 2
|
assert calc_dip(32, 30, 29) == 3
|
||||||
assert calc_dip(30, 29) == 4
|
assert calc_dip(32, 31, 29) == 5
|
||||||
assert calc_dip(29, 31) == 6
|
assert calc_dip(32, 31, 29) == 5
|
||||||
assert calc_dip(26, 26) == 0
|
|
||||||
assert calc_dip(3, 2) == 2**30 - 2**29
|
assert calc_dip(2, 2, 1) == 0
|
||||||
assert calc_dip(3, 1) == 2**31 - 2**29
|
assert calc_dip(2, 2, 0) == 2**31
|
||||||
|
assert calc_dip(3, 3, 1) == 2**30
|
||||||
|
|
||||||
|
|
||||||
def test_merge_two_nodes():
|
def test_merge_two_nodes():
|
||||||
assert merge_two_nodes((0, 32), (1, 32)) == ((0, 31), 0)
|
assert merge_two_nodes((0, 32), (1, 32)) == ((0, 31), 0)
|
||||||
assert merge_two_nodes((0, 32), (2, 32)) == ((0, 30), 4)
|
assert merge_two_nodes((0, 32), (2, 32)) == ((0, 30), 2)
|
||||||
assert merge_two_nodes((0, 32), (5, 32)) == ((0, 29), 8)
|
assert merge_two_nodes((0, 32), (5, 32)) == ((0, 29), 6)
|
||||||
assert merge_two_nodes((3, 32), (4, 32)) == ((0, 29), 8)
|
assert merge_two_nodes((3, 32), (4, 32)) == ((0, 29), 6)
|
||||||
assert merge_two_nodes((0, 32), (4, 30)) == ((0, 29), 4)
|
assert merge_two_nodes((0, 32), (4, 30)) == ((0, 29), 3)
|
||||||
|
assert merge_two_nodes((0, 32), (6, 31)) == ((0, 29), 5)
|
||||||
|
|
||||||
|
|
||||||
|
def test_merge_nodes():
|
||||||
|
assert merge_nodes(
|
||||||
|
[
|
||||||
|
(0, 32),
|
||||||
|
(3, 32),
|
||||||
|
(4, 32),
|
||||||
|
],
|
||||||
|
2,
|
||||||
|
) == ([(0, 30), (4, 32)], 2)
|
||||||
|
|
||||||
|
# т.е. сейчас алгоритм работает так, что он может оставить соседей
|
||||||
|
assert merge_nodes(
|
||||||
|
[
|
||||||
|
(0, 32),
|
||||||
|
(3, 32),
|
||||||
|
(4, 32),
|
||||||
|
(7, 32),
|
||||||
|
],
|
||||||
|
2,
|
||||||
|
) == ([(0, 30), (4, 30)], 4)
|
||||||
|
|
||||||
|
assert merge_nodes(
|
||||||
|
[
|
||||||
|
(0, 32),
|
||||||
|
(3, 32),
|
||||||
|
(4, 32),
|
||||||
|
(7, 32),
|
||||||
|
],
|
||||||
|
1,
|
||||||
|
) == ([(0, 29)], 4)
|
||||||
|
|||||||
@@ -42,13 +42,17 @@ def find_parent(a: Node, b: Node) -> Node:
|
|||||||
return parent_node
|
return parent_node
|
||||||
|
|
||||||
|
|
||||||
def calc_dip(mask_len_a: int, mask_len_b: int) -> int:
|
def calc_dip(mask_len_a: int, mask_len_b: int, mask_len_p: int) -> int:
|
||||||
# a = 2 ** (32 - mask_len_a) if mask_len_a != 32 else 0
|
mask_len = mask_len_p + 1
|
||||||
# b = 2 ** (32 - mask_len_b) if mask_len_b != 32 else 0
|
dip_a = 0
|
||||||
a = 1 << (32 - mask_len_a) if mask_len_a != 32 else 0
|
while mask_len_a > mask_len:
|
||||||
b = 1 << (32 - mask_len_b) if mask_len_b != 32 else 0
|
dip_a += 2 ** (32 - mask_len_a)
|
||||||
dip = abs(a - b)
|
mask_len_a -= 1
|
||||||
return dip
|
dip_b = 0
|
||||||
|
while mask_len_b > mask_len:
|
||||||
|
dip_b += 2 ** (32 - mask_len_b)
|
||||||
|
mask_len_b -= 1
|
||||||
|
return dip_a + dip_b
|
||||||
|
|
||||||
|
|
||||||
def merge_two_nodes(node_a: Node, node_b: Node) -> tuple[Node, int]:
|
def merge_two_nodes(node_a: Node, node_b: Node) -> tuple[Node, int]:
|
||||||
@@ -56,9 +60,7 @@ def merge_two_nodes(node_a: Node, node_b: Node) -> tuple[Node, int]:
|
|||||||
ip_b, mask_len_b = node_b
|
ip_b, mask_len_b = node_b
|
||||||
parent_node = find_parent(node_a, node_b)
|
parent_node = find_parent(node_a, node_b)
|
||||||
_, mask_len_p = parent_node
|
_, mask_len_p = parent_node
|
||||||
dip_a = calc_dip(mask_len_a, mask_len_p + 1)
|
dip = calc_dip(mask_len_a, mask_len_b, mask_len_p)
|
||||||
dip_b = calc_dip(mask_len_b, mask_len_p + 1)
|
|
||||||
dip = dip_a + dip_b
|
|
||||||
return parent_node, dip
|
return parent_node, dip
|
||||||
|
|
||||||
|
|
||||||
@@ -68,18 +70,22 @@ def make_cidr4(ip, mask_len) -> str:
|
|||||||
return f"{ip_address}/{mask_len}"
|
return f"{ip_address}/{mask_len}"
|
||||||
|
|
||||||
|
|
||||||
def merge_nodes(
|
def merge_nodes(nodes: list[Node], required_len: int) -> tuple[list[Node], int]:
|
||||||
nodes_to_merge: list[Node], required_len: int
|
|
||||||
) -> tuple[list[Node], int]:
|
|
||||||
nodes = [x for x in nodes_to_merge]
|
|
||||||
sum_dip = 0
|
sum_dip = 0
|
||||||
# Преобразовать список нод в список туплов: родитель (ip, mask len), кол-во добавляемых адресов d_ip
|
while len(nodes) > required_len:
|
||||||
# найти подходящего родителя (с минимальным значением d_ip) и индекс
|
min_tuple = None, (None, float("inf"))
|
||||||
# затем мержить два узла:
|
for i, (a, b) in enumerate(zip(nodes, nodes[1:])):
|
||||||
# - т.е. удалить элемент с индексом i
|
parent_node, dip = merge_two_nodes(a, b)
|
||||||
# - еще раз удалить элемент с индексом i
|
if dip < min_tuple[1][1]:
|
||||||
# - добавить родителя перед элементом с индексом i
|
min_tuple = i, (parent_node, dip)
|
||||||
# повторить пока не достигнем нужного кол-ва узлов
|
idx, (parent_node, dip) = min_tuple
|
||||||
|
nodes = nodes[:idx] + [parent_node] + nodes[idx + 2 :]
|
||||||
|
sum_dip += dip
|
||||||
|
|
||||||
|
# for i, (a, b) in enumerate(zip(nodes, nodes[1:])):
|
||||||
|
# parent_node, dip = merge_two_nodes(a, b)
|
||||||
|
# assert parent_node != a
|
||||||
|
# assert parent_node != b
|
||||||
|
|
||||||
return nodes, sum_dip
|
return nodes, sum_dip
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user