util: properly copy lrucachedict instances
Previously, copy() only worked if the cache was full. We teach
copy() to only copy defined nodes.
Differential Revision: https://phab.mercurial-scm.org/D4498
--- a/mercurial/util.py Thu Sep 06 11:27:25 2018 -0700
+++ b/mercurial/util.py Thu Sep 06 11:33:40 2018 -0700
@@ -1313,11 +1313,19 @@
def copy(self):
result = lrucachedict(self._capacity)
+
+ # We copy entries by iterating in oldest-to-newest order so the copy
+ # has the correct ordering.
+
+ # Find the first non-empty entry.
n = self._head.prev
- # Iterate in oldest-to-newest order, so the copy has the right ordering
+ while n.key is _notset and n is not self._head:
+ n = n.prev
+
for i in range(len(self._cache)):
result[n.key] = n.value
n = n.prev
+
return result
def _movetohead(self, node):
--- a/tests/test-lrucachedict.py Thu Sep 06 11:27:25 2018 -0700
+++ b/tests/test-lrucachedict.py Thu Sep 06 11:33:40 2018 -0700
@@ -68,12 +68,28 @@
dc = d.copy()
self.assertEqual(len(dc), 2)
- # TODO this fails
- return
for key in ('a', 'b'):
self.assertIn(key, dc)
self.assertEqual(dc[key], 'v%s' % key)
+ self.assertEqual(len(d), 2)
+ for key in ('a', 'b'):
+ self.assertIn(key, d)
+ self.assertEqual(d[key], 'v%s' % key)
+
+ d['c'] = 'vc'
+ del d['b']
+ dc = d.copy()
+ self.assertEqual(len(dc), 2)
+ for key in ('a', 'c'):
+ self.assertIn(key, dc)
+ self.assertEqual(dc[key], 'v%s' % key)
+
+ def testcopyempty(self):
+ d = util.lrucachedict(4)
+ dc = d.copy()
+ self.assertEqual(len(dc), 0)
+
def testcopyfull(self):
d = util.lrucachedict(4)
d['a'] = 'va'