]> granicus.if.org Git - python/commitdiff
Issue #23266: Restore the performance of ipaddress.collapse_addresses() whith
authorSerhiy Storchaka <storchaka@gmail.com>
Sun, 18 Jan 2015 22:41:32 +0000 (00:41 +0200)
committerSerhiy Storchaka <storchaka@gmail.com>
Sun, 18 Jan 2015 22:41:32 +0000 (00:41 +0200)
duplicated addresses and simplify the code.

Lib/ipaddress.py
Lib/test/test_ipaddress.py

index ce6bf0c877583449ba98b47eb4a036742672e439..2ba98d8926619bbdacf7ae44c9ecb4fe2d495b0e 100644 (file)
@@ -164,25 +164,23 @@ def _split_optional_netmask(address):
 
 
 def _find_address_range(addresses):
-    """Find a sequence of IPv#Address.
+    """Find a sequence of sorted deduplicated IPv#Address.
 
     Args:
         addresses: a list of IPv#Address objects.
 
-    Returns:
-        A tuple containing the first and last IP addresses in the sequence,
-        and the number of distinct IP addresses in the sequence.
+    Yields:
+        A tuple containing the first and last IP addresses in the sequence.
 
     """
-    first = last = addresses[0]
-    i = 1
-    for ip in addresses[1:]:
-        if ip._ip == last._ip + 1:
-            last = ip
-            i += 1
-        else:
-            break
-    return (first, last, i)
+    it = iter(addresses)
+    first = last = next(it)
+    for ip in it:
+        if ip._ip != last._ip + 1:
+            yield first, last
+            first = ip
+        last = ip
+    yield first, last
 
 
 def _count_righthand_zero_bits(number, bits):
@@ -323,7 +321,6 @@ def collapse_addresses(addresses):
         TypeError: If passed a list of mixed version objects.
 
     """
-    i = 0
     addrs = []
     ips = []
     nets = []
@@ -349,14 +346,13 @@ def collapse_addresses(addresses):
                                  ip, nets[-1]))
             nets.append(ip)
 
-    # sort
-    ips = sorted(ips)
+    # sort and dedup
+    ips = sorted(set(ips))
 
     # find consecutive address ranges in the sorted sequence and summarize them
-    while i < len(ips):
-        (first, last, items) = _find_address_range(ips[i:])
-        i = items + i
-        addrs.extend(summarize_address_range(first, last))
+    if ips:
+        for first, last in _find_address_range(ips):
+            addrs.extend(summarize_address_range(first, last))
 
     return _collapse_addresses_internal(addrs + nets)
 
index 95518af23df5ce98286f719bb36ed035fd2e580e..5ec2cd45fe87475c46a2201fe5dbac0d7b655bff 100644 (file)
@@ -790,11 +790,15 @@ class IpaddrUnitTest(unittest.TestCase):
                           2 ** ipaddress.IPV6LENGTH)
 
     def testInternals(self):
-        first, last, nitems = ipaddress._find_address_range([
-            ipaddress.IPv4Address('10.10.10.10'),
-            ipaddress.IPv4Address('10.10.10.12')])
-        self.assertEqual(first, last)
-        self.assertEqual(nitems, 1)
+        ip1 = ipaddress.IPv4Address('10.10.10.10')
+        ip2 = ipaddress.IPv4Address('10.10.10.11')
+        ip3 = ipaddress.IPv4Address('10.10.10.12')
+        self.assertEqual(list(ipaddress._find_address_range([ip1])),
+                         [(ip1, ip1)])
+        self.assertEqual(list(ipaddress._find_address_range([ip1, ip3])),
+                         [(ip1, ip1), (ip3, ip3)])
+        self.assertEqual(list(ipaddress._find_address_range([ip1, ip2, ip3])),
+                         [(ip1, ip3)])
         self.assertEqual(128, ipaddress._count_righthand_zero_bits(0, 128))
         self.assertEqual("IPv4Network('1.2.3.0/24')", repr(self.ipv4_network))