[Zope-Checkins] CVS: Zope/lib/python/Products/ZCatalog - Catalog.py:1.98.6.3 Lazy.py:1.7.6.2

Casey Duncan casey@zope.com
Wed, 11 Dec 2002 14:12:15 -0500


Update of /cvs-repository/Zope/lib/python/Products/ZCatalog
In directory cvs.zope.org:/tmp/cvs-serv12102/lib/python/Products/ZCatalog

Modified Files:
      Tag: Zope-2_6-branch
	Catalog.py Lazy.py 
Log Message:
Backport Lazy concatenation fix from the head, this also makes empty result sets coming from the Catalog consistent


=== Zope/lib/python/Products/ZCatalog/Catalog.py 1.98.6.2 => 1.98.6.3 ===
--- Zope/lib/python/Products/ZCatalog/Catalog.py:1.98.6.2	Tue Dec 10 10:55:00 2002
+++ Zope/lib/python/Products/ZCatalog/Catalog.py	Wed Dec 11 14:12:14 2002
@@ -519,7 +519,7 @@
                 return self.sortResults(rs, sort_index, reverse, limit, merge)
         else:
             # Empty result set
-            return LazyCat(rs)
+            return LazyCat([])
 
     def sortResults(self, rs, sort_index, reverse=0, limit=None, merge=1):
         # Sort a result set using a sort index. Return a lazy


=== Zope/lib/python/Products/ZCatalog/Lazy.py 1.7.6.1 => 1.7.6.2 ===
--- Zope/lib/python/Products/ZCatalog/Lazy.py:1.7.6.1	Tue Dec 10 10:55:00 2002
+++ Zope/lib/python/Products/ZCatalog/Lazy.py	Wed Dec 11 14:12:14 2002
@@ -22,7 +22,7 @@
     def __repr__(self): return `list(self)`
 
     def __len__(self):
-
+        # This is a worst-case len, subclasses should try to do better
         try: return self._len
         except AttributeError: pass
 
@@ -34,34 +34,13 @@
             except:
                 self._len=l
                 return l
+                
 
     def __add__(self, other):
-        try:
-            for base in other.__class__.__bases__:
-                if base.__name__ == 'Lazy':
-                    break
-            else:
-                raise TypeError
-        except:
-            raise TypeError, "Can not concatenate objects. Both must be lazy sequences."
-
-        if self.__class__.__name__ == 'LazyCat':
-            if hasattr(self, '_seq'):
-                seq = self._seq
-            else:
-                seq = [self._data]
-        else:
-            seq = [self]
-
-        if other.__class__.__name__ == 'LazyCat':
-            if hasattr(other, '_seq'):
-                seq = seq + other._seq
-            else:
-                seq.append(other._data)
-        else:
-            seq.append(other)
-
-        return LazyCat(seq)
+        if not isinstance(other, Lazy):
+            raise TypeError(
+                "Can not concatenate objects. Both must be lazy sequences.")
+        return LazyCat([self, other])
 
     def __getslice__(self,i1,i2):
         r=[]
@@ -77,6 +56,19 @@
     # for accessing small parts of big searches.
 
     def __init__(self, sequences, length=None):
+        if len(sequences) < 100:
+            # Optimize structure of LazyCats to avoid nesting
+            # We don't do this for large numbers of input sequences
+            # to make instantiation faster instead
+            flattened_seq = []
+            for s in sequences:
+                if isinstance(s, LazyCat):
+                    # If one of the sequences passed is itself a LazyCat, add
+                    # its base sequences rather than nest LazyCats
+                    flattened_seq.extend(s._seq)
+                else:
+                    flattened_seq.append(s)
+            sequences = flattened_seq
         self._seq=sequences
         self._data=[]
         self._sindex=0
@@ -118,6 +110,18 @@
                 self._eindex=eindex=-1
         self._eindex=eindex
         return data[i]
+        
+    def __len__(self):
+        # Make len of LazyCat only as expensive as the lens 
+        # of its underlying sequences
+        try:
+            return self._len
+        except:
+            l = 0
+            for s in self._seq:
+               l += len(s)
+            self._len = l
+            return l
 
 class LazyMap(Lazy):
     # Act like a sequence, but get data from a filtering process.