From ee5ebe05572bf83f3cb31ffd3ce79495ae698ba3 Mon Sep 17 00:00:00 2001
From: Andreas Kloeckner <inform@tiker.net>
Date: Sun, 29 Jan 2017 23:46:08 -0600
Subject: [PATCH] Fix O(n^2) behavior in name generation by remembering
 previously successful counter

---
 pytools/__init__.py | 19 ++++++++++++++++++-
 1 file changed, 18 insertions(+), 1 deletion(-)

diff --git a/pytools/__init__.py b/pytools/__init__.py
index a02855c..0755496 100644
--- a/pytools/__init__.py
+++ b/pytools/__init__.py
@@ -1750,6 +1750,18 @@ def generate_unique_names(prefix):
         try_num += 1
 
 
+def generate_numbered_unique_names(prefix, num=None):
+    orig_num = num
+    num = 0
+    if orig_num is None:
+        yield (num, prefix)
+
+    while True:
+        name = "%s_%d" % (prefix, num)
+        num += 1
+        yield (num, name)
+
+
 generate_unique_possibilities = MovedFunctionDeprecationWrapper(
         generate_unique_names)
 
@@ -1758,6 +1770,7 @@ class UniqueNameGenerator:
     def __init__(self, existing_names=set(), forced_prefix=""):
         self.existing_names = existing_names.copy()
         self.forced_prefix = forced_prefix
+        self.prefix_to_counter = {}
 
     def is_name_conflicting(self, name):
         return name in self.existing_names
@@ -1777,10 +1790,14 @@ class UniqueNameGenerator:
     def __call__(self, based_on="id"):
         based_on = self.forced_prefix + based_on
 
-        for var_name in generate_unique_names(based_on):
+        counter = self.prefix_to_counter.get(based_on, None)
+
+        for counter, var_name in generate_numbered_unique_names(based_on, counter):
             if not self.is_name_conflicting(var_name):
                 break
 
+        self.prefix_to_counter[based_on] = counter
+
         var_name = intern(var_name)
 
         self.existing_names.add(var_name)
-- 
GitLab