Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 1e71c53

Browse files
committed
Issue #20826: Optimize ipaddress.collapse_addresses().
1 parent 824db30 commit 1e71c53

2 files changed

Lines changed: 28 additions & 27 deletions

File tree

Lib/ipaddress.py

Lines changed: 26 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,7 @@ def summarize_address_range(first, last):
253253
break
254254

255255

256-
def _collapse_addresses_recursive(addresses):
256+
def _collapse_addresses_internal(addresses):
257257
"""Loops through the addresses, collapsing concurrent netblocks.
258258
259259
Example:
@@ -263,7 +263,7 @@ def _collapse_addresses_recursive(addresses):
263263
ip3 = IPv4Network('192.0.2.128/26')
264264
ip4 = IPv4Network('192.0.2.192/26')
265265
266-
_collapse_addresses_recursive([ip1, ip2, ip3, ip4]) ->
266+
_collapse_addresses_internal([ip1, ip2, ip3, ip4]) ->
267267
[IPv4Network('192.0.2.0/24')]
268268
269269
This shouldn't be called directly; it is called via
@@ -277,28 +277,29 @@ def _collapse_addresses_recursive(addresses):
277277
passed.
278278
279279
"""
280-
while True:
281-
last_addr = None
282-
ret_array = []
283-
optimized = False
284-
285-
for cur_addr in addresses:
286-
if not ret_array:
287-
last_addr = cur_addr
288-
ret_array.append(cur_addr)
289-
elif (cur_addr.network_address >= last_addr.network_address and
290-
cur_addr.broadcast_address <= last_addr.broadcast_address):
291-
optimized = True
292-
elif cur_addr == list(last_addr.supernet().subnets())[1]:
293-
ret_array[-1] = last_addr = last_addr.supernet()
294-
optimized = True
295-
else:
296-
last_addr = cur_addr
297-
ret_array.append(cur_addr)
298-
299-
addresses = ret_array
300-
if not optimized:
301-
return addresses
280+
# First merge
281+
to_merge = list(addresses)
282+
subnets = {}
283+
while to_merge:
284+
net = to_merge.pop()
285+
supernet = net.supernet()
286+
existing = subnets.get(supernet)
287+
if existing is None:
288+
subnets[supernet] = net
289+
elif existing != net:
290+
# Merge consecutive subnets
291+
del subnets[supernet]
292+
to_merge.append(supernet)
293+
# Then iterate over resulting networks, skipping subsumed subnets
294+
last = None
295+
for net in sorted(subnets.values()):
296+
if last is not None:
297+
# Since they are sorted, last.network_address <= net.network_address
298+
# is a given.
299+
if last.broadcast_address >= net.broadcast_address:
300+
continue
301+
yield net
302+
last = net
302303

303304

304305
def collapse_addresses(addresses):
@@ -347,15 +348,13 @@ def collapse_addresses(addresses):
347348

348349
# sort and dedup
349350
ips = sorted(set(ips))
350-
nets = sorted(set(nets))
351351

352352
while i < len(ips):
353353
(first, last) = _find_address_range(ips[i:])
354354
i = ips.index(last) + 1
355355
addrs.extend(summarize_address_range(first, last))
356356

357-
return iter(_collapse_addresses_recursive(sorted(
358-
addrs + nets, key=_BaseNetwork._get_networks_key)))
357+
return _collapse_addresses_internal(addrs + nets)
359358

360359

361360
def get_mixed_type_key(obj):

Misc/NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@ Core and Builtins
8484
Library
8585
-------
8686

87+
- Issue #20826: Optimize ipaddress.collapse_addresses().
88+
8789
- Issue #21487: Optimize ipaddress.summarize_address_range() and
8890
ipaddress.{IPv4Network,IPv6Network}.subnets().
8991

0 commit comments

Comments
 (0)