comparison mercurial/smartset.py @ 31015:1076f7eba964

smartset: convert set to list lazily If the caller only wants to construct a baseset via a set, and then do "__contains__" tests. It's unnecessary to initialize the list. Testing on my unfiltered hg-committed repo where len(draft()) is 2600, this patch shows about 6% improvement on set intensive queries: Before: $ for i in `seq 5`; hg perfrevset 'draft() & draft() & draft() & draft()' ! wall 0.001196 comb 0.000000 user 0.000000 sys 0.000000 (best of 2011) ! wall 0.001191 comb 0.000000 user 0.000000 sys 0.000000 (best of 2099) ! wall 0.001186 comb 0.010000 user 0.010000 sys 0.000000 (best of 1953) ! wall 0.001182 comb 0.000000 user 0.000000 sys 0.000000 (best of 2135) ! wall 0.001193 comb 0.000000 user 0.000000 sys 0.000000 (best of 2177) After: $ for i in `seq 5`; hg perfrevset 'draft() & draft() & draft() & draft()' ! wall 0.001128 comb 0.000000 user 0.000000 sys 0.000000 (best of 2247) ! wall 0.001119 comb 0.000000 user 0.000000 sys 0.000000 (best of 2317) ! wall 0.001115 comb 0.000000 user 0.000000 sys 0.000000 (best of 2244) ! wall 0.001131 comb 0.000000 user 0.000000 sys 0.000000 (best of 2093) ! wall 0.001124 comb 0.000000 user 0.000000 sys 0.000000 (best of 2134) It could have bigger impact on larger sets in theory.
author Jun Wu <quark@fb.com>
date Fri, 17 Feb 2017 20:59:29 -0800
parents 1be65deb3d54
children 74f77f1c2215
comparison
equal deleted inserted replaced
31014:219629d42786 31015:1076f7eba964
169 if not isinstance(data, list): 169 if not isinstance(data, list):
170 if isinstance(data, set): 170 if isinstance(data, set):
171 self._set = data 171 self._set = data
172 # set has no order we pick one for stability purpose 172 # set has no order we pick one for stability purpose
173 self._ascending = True 173 self._ascending = True
174 data = list(data) 174 # converting set to list has a cost, do it lazily
175 self._list = data 175 data = None
176 else:
177 data = list(data)
178 if data is not None:
179 self._list = data
176 self._datarepr = datarepr 180 self._datarepr = datarepr
177 181
178 @util.propertycache 182 @util.propertycache
179 def _set(self): 183 def _set(self):
180 return set(self._list) 184 return set(self._list)
183 def _asclist(self): 187 def _asclist(self):
184 asclist = self._list[:] 188 asclist = self._list[:]
185 asclist.sort() 189 asclist.sort()
186 return asclist 190 return asclist
187 191
192 @util.propertycache
193 def _list(self):
194 # _list is only lazily constructed if we have _set
195 assert '_set' in self.__dict__
196 return list(self._set)
197
188 def __iter__(self): 198 def __iter__(self):
189 if self._ascending is None: 199 if self._ascending is None:
190 return iter(self._list) 200 return iter(self._list)
191 elif self._ascending: 201 elif self._ascending:
192 return iter(self._asclist) 202 return iter(self._asclist)
202 @util.propertycache 212 @util.propertycache
203 def __contains__(self): 213 def __contains__(self):
204 return self._set.__contains__ 214 return self._set.__contains__
205 215
206 def __nonzero__(self): 216 def __nonzero__(self):
207 return bool(self._list) 217 return bool(len(self))
208 218
209 def sort(self, reverse=False): 219 def sort(self, reverse=False):
210 self._ascending = not bool(reverse) 220 self._ascending = not bool(reverse)
211 self._istopo = False 221 self._istopo = False
212 222
216 else: 226 else:
217 self._ascending = not self._ascending 227 self._ascending = not self._ascending
218 self._istopo = False 228 self._istopo = False
219 229
220 def __len__(self): 230 def __len__(self):
221 return len(self._list) 231 if '_list' in self.__dict__:
232 return len(self._list)
233 else:
234 return len(self._set)
222 235
223 def isascending(self): 236 def isascending(self):
224 """Returns True if the collection is ascending order, False if not. 237 """Returns True if the collection is ascending order, False if not.
225 238
226 This is part of the mandatory API for smartset.""" 239 This is part of the mandatory API for smartset."""