Patchwork [2,of,4] revset: add __length_hint__ to smart classes

login
register
mail settings
Submitter Durham Goode
Date Sept. 30, 2014, 1:12 a.m.
Message ID <93be919300f04bfd26fd.1412039531@dev2000.prn2.facebook.com>
Download mbox | patch
Permalink /patch/6031/
State Superseded
Headers show

Comments

Durham Goode - Sept. 30, 2014, 1:12 a.m.
# HG changeset patch
# User Durham Goode <durham@fb.com>
# Date 1412036731 25200
#      Mon Sep 29 17:25:31 2014 -0700
# Node ID 93be919300f04bfd26fd5294499fb62c96ba7f93
# Parent  c6129c781a9f11be26191e64dcebf8d539c8c76a
revset: add __length_hint__ to smart classes

This adds a __length_hint__ to the smart revset classes so we can optimize at
runtime to avoid things like iterating over the large set and checking
containment against the small set when doing 'X & Y'.
Durham Goode - Sept. 30, 2014, 1:47 a.m.
On 9/29/14, 6:12 PM, Durham Goode wrote:
> # HG changeset patch
> # User Durham Goode <durham@fb.com>
> # Date 1412036731 25200
> #      Mon Sep 29 17:25:31 2014 -0700
> # Node ID 93be919300f04bfd26fd5294499fb62c96ba7f93
> # Parent  c6129c781a9f11be26191e64dcebf8d539c8c76a
> revset: add __length_hint__ to smart classes
>
> This adds a __length_hint__ to the smart revset classes so we can optimize at
> runtime to avoid things like iterating over the large set and checking
> containment against the small set when doing 'X & Y'.
>
> diff --git a/mercurial/revset.py b/mercurial/revset.py
> --- a/mercurial/revset.py
> +++ b/mercurial/revset.py
> @@ -2204,6 +2204,9 @@ class baseset(list):
>           super(baseset, self).__init__(data)
>           self._set = None
>   
> +    def __length_hint__(self):
> +        return len(self)
> +
>       def ascending(self):
>           """Sorts the set in ascending order (in place).
>   
> @@ -2376,6 +2379,9 @@ class lazyset(object):
>           l = baseset([r for r in self])
>           return len(l)
>   
> +    def __length_hint__(self):
> +        return self._subset.__length_hint__()
> +
I'm not 100% satisfied with this stuff.  _subset is not guaranteed to be 
a smart set, and therefore might not even implement __length_hint__.  
But to fix it would require auditing every revset to ensure that subsets 
are always one of our smartsets.
Durham Goode - Sept. 30, 2014, 6:03 p.m.
On 9/29/14, 6:47 PM, Durham Goode wrote:
>
> On 9/29/14, 6:12 PM, Durham Goode wrote:
>> # HG changeset patch
>> # User Durham Goode <durham@fb.com>
>> # Date 1412036731 25200
>> #      Mon Sep 29 17:25:31 2014 -0700
>> # Node ID 93be919300f04bfd26fd5294499fb62c96ba7f93
>> # Parent  c6129c781a9f11be26191e64dcebf8d539c8c76a
>> revset: add __length_hint__ to smart classes
>>
>> This adds a __length_hint__ to the smart revset classes so we can 
>> optimize at
>> runtime to avoid things like iterating over the large set and checking
>> containment against the small set when doing 'X & Y'.
>>
>> diff --git a/mercurial/revset.py b/mercurial/revset.py
>> --- a/mercurial/revset.py
>> +++ b/mercurial/revset.py
>> @@ -2204,6 +2204,9 @@ class baseset(list):
>>           super(baseset, self).__init__(data)
>>           self._set = None
>>   +    def __length_hint__(self):
>> +        return len(self)
>> +
>>       def ascending(self):
>>           """Sorts the set in ascending order (in place).
>>   @@ -2376,6 +2379,9 @@ class lazyset(object):
>>           l = baseset([r for r in self])
>>           return len(l)
>>   +    def __length_hint__(self):
>> +        return self._subset.__length_hint__()
>> +
> I'm not 100% satisfied with this stuff.  _subset is not guaranteed to 
> be a smart set, and therefore might not even implement 
> __length_hint__.  But to fix it would require auditing every revset to 
> ensure that subsets are always one of our smartsets.
I've sent a V2 that addresses this issue.

Patch

diff --git a/mercurial/revset.py b/mercurial/revset.py
--- a/mercurial/revset.py
+++ b/mercurial/revset.py
@@ -2204,6 +2204,9 @@  class baseset(list):
         super(baseset, self).__init__(data)
         self._set = None
 
+    def __length_hint__(self):
+        return len(self)
+
     def ascending(self):
         """Sorts the set in ascending order (in place).
 
@@ -2376,6 +2379,9 @@  class lazyset(object):
         l = baseset([r for r in self])
         return len(l)
 
+    def __length_hint__(self):
+        return self._subset.__length_hint__()
+
     def __getitem__(self, x):
         # Basic implementation to be changed in future patches.
         l = baseset([r for r in self])
@@ -2478,6 +2484,9 @@  class _addset(_orderedsetmixin):
     def __len__(self):
         return len(self._list)
 
+    def __length_hint__(self):
+        return self._r1.__length_hint__() + self._r2.__length_hint__()
+
     @util.propertycache
     def _list(self):
         if not self._genlist:
@@ -2688,6 +2697,11 @@  class _generatorset(object):
     def set(self):
         return self
 
+    def __length_hint__(self):
+        if util.safehasattr(self._gen, '__length_hint__'):
+            return self._gen.__length_hint__()
+        return sys.maxint
+
     def sort(self, reverse=False):
         if not self._finished:
             for i in self:
@@ -2800,6 +2814,9 @@  class _spanset(_orderedsetmixin):
             for r in iterrange:
                 yield r
 
+    def __length_hint__(self):
+        return abs(self._start - self._end)
+
     def __contains__(self, rev):
         start = self._start
         end = self._end