diff --git a/mercurial/util.py b/mercurial/util.py --- a/mercurial/util.py +++ b/mercurial/util.py @@ -1311,8 +1311,19 @@ self._cache.clear() - def copy(self): - result = lrucachedict(self.capacity) + def copy(self, capacity=None): + """Create a new cache as a copy of the current one. + + By default, the new cache has the same capacity as the existing one. + But, the cache capacity can be changed as part of performing the + copy. + + Items in the copy have an insertion/access order matching this + instance. + """ + + capacity = capacity or self.capacity + result = lrucachedict(capacity) # We copy entries by iterating in oldest-to-newest order so the copy # has the correct ordering. @@ -1322,6 +1333,8 @@ while n.key is _notset and n is not self._head: n = n.prev + # We could potentially skip the first N items when decreasing capacity. + # But let's keep it simple unless it is a performance problem. for i in range(len(self._cache)): result[n.key] = n.value n = n.prev diff --git a/tests/test-lrucachedict.py b/tests/test-lrucachedict.py --- a/tests/test-lrucachedict.py +++ b/tests/test-lrucachedict.py @@ -118,5 +118,59 @@ for key in ('a', 'b', 'c', 'd'): self.assertEqual(d[key], 'v%s' % key) + def testcopydecreasecapacity(self): + d = util.lrucachedict(5) + d['a'] = 'va' + d['b'] = 'vb' + d['c'] = 'vc' + d['d'] = 'vd' + + dc = d.copy(2) + for key in ('a', 'b'): + self.assertNotIn(key, dc) + for key in ('c', 'd'): + self.assertIn(key, dc) + self.assertEqual(dc[key], 'v%s' % key) + + dc['e'] = 've' + self.assertNotIn('c', dc) + for key in ('d', 'e'): + self.assertIn(key, dc) + self.assertEqual(dc[key], 'v%s' % key) + + # Original should remain unchanged. + for key in ('a', 'b', 'c', 'd'): + self.assertIn(key, d) + self.assertEqual(d[key], 'v%s' % key) + + def testcopyincreasecapacity(self): + d = util.lrucachedict(5) + d['a'] = 'va' + d['b'] = 'vb' + d['c'] = 'vc' + d['d'] = 'vd' + + dc = d.copy(6) + for key in ('a', 'b', 'c', 'd'): + self.assertIn(key, dc) + self.assertEqual(dc[key], 'v%s' % key) + + dc['e'] = 've' + dc['f'] = 'vf' + for key in ('a', 'b', 'c', 'd', 'e', 'f'): + self.assertIn(key, dc) + self.assertEqual(dc[key], 'v%s' % key) + + dc['g'] = 'vg' + self.assertNotIn('a', dc) + for key in ('b', 'c', 'd', 'e', 'f', 'g'): + self.assertIn(key, dc) + self.assertEqual(dc[key], 'v%s' % key) + + # Original should remain unchanged. + for key in ('a', 'b', 'c', 'd'): + self.assertIn(key, d) + self.assertEqual(d[key], 'v%s' % key) + if __name__ == '__main__': silenttestrunner.main(__name__)