@@ -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
304305def 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
361360def get_mixed_type_key (obj ):
0 commit comments