diff -r 8c1438c15ed0 Lib/collections/__init__.py --- a/Lib/collections/__init__.py Mon Jul 28 00:19:36 2014 +0200 +++ b/Lib/collections/__init__.py Tue Jul 29 02:30:29 2014 +0200 @@ -171,6 +171,76 @@ class OrderedDict(dict): link.next = first root.next = first.prev = link + def move_before(self, ref_key, key): + '''Move an existing element before another one. + + Raises KeyError if one of the elements does not exist. + ''' + link = self.__map[key] + link_ref = self.__map[ref_key] + # Detach link from linked list + link_prev = link.prev + link_next = link.next + link_prev.next = link_next + link_next.prev = link_prev + # Reattach link before link_ref + link_next = link_ref + link_prev = link_next.prev + link.prev, link.next, link.key = link_prev, link_next, key + link_prev.next = link + link_next.prev = _proxy(link) + + def move_after(self, ref_key, key): + '''Move an existing element after another one. + + Raises KeyError if one of the elements does not exist. + ''' + link = self.__map[key] + link_ref = self.__map[ref_key] + # Detach link from linked list + link_prev = link.prev + link_next = link.next + link_prev.next = link_next + link_next.prev = link_prev + # Reattach link after link_ref + link_prev = link_ref + link_next = link_prev.next + link.prev, link.next, link.key = link_prev, link_next, key + link_prev.next = link + link_next.prev = _proxy(link) + + def insert_before(self, ref_key, key, value): + '''Insert a new element before an existing one. + + Raises KeyError if an element with the same key already exists. + ''' + if key in self: + raise KeyError('key \'%s\' already exists') + self.__map[key] = link = _Link() + # Attach link at proper position + link_next = self.__map[ref_key] + link_prev = link_next.prev + link.prev, link.next, link.key = link_prev, link_next, key + link_prev.next = link + link_next.prev = _proxy(link) + dict.__setitem__(self, key, value) + + def insert_after(self, ref_key, key, value): + '''Insert a new element after an existing one. + + Raises KeyError if an element with the same key already exists. + ''' + if key in self: + raise KeyError('key \'%s\' already exists') + self.__map[key] = link = _Link() + # Attach link at proper position + link_prev = self.__map[ref_key] + link_next = link_prev.next + link.prev, link.next, link.key = link_prev, link_next, key + link_prev.next = link + link_next.prev = _proxy(link) + dict.__setitem__(self, key, value) + def __sizeof__(self): sizeof = _sys.getsizeof n = len(self) + 1 # number of links including root diff -r 8c1438c15ed0 Lib/test/test_collections.py --- a/Lib/test/test_collections.py Mon Jul 28 00:19:36 2014 +0200 +++ b/Lib/test/test_collections.py Tue Jul 29 02:30:29 2014 +0200 @@ -1569,6 +1569,42 @@ class TestOrderedDict(unittest.TestCase) with self.assertRaises(KeyError): od.move_to_end('x') + def test_move_before(self): + od = OrderedDict.fromkeys('abcde') + od.move_before('b', 'c') + self.assertEqual(list(od), list('acbde')) + with self.assertRaises(KeyError): + od.move_before('m', 'a') + with self.assertRaises(KeyError): + od.move_before('a', 'm') + + def test_move_after(self): + od = OrderedDict.fromkeys('abcde') + od.move_after('e', 'd') + self.assertEqual(list(od), list('abced')) + with self.assertRaises(KeyError): + od.move_after('m', 'e') + with self.assertRaises(KeyError): + od.move_after('e', 'm') + + def test_insert_before(self): + od = OrderedDict.fromkeys('abcde') + od.insert_before('c', 'f', 6) + self.assertEqual(list(od), list('abfcde')) + with self.assertRaises(KeyError): + od.insert_before('m', 'g', 7) # key 'm' does not exists + with self.assertRaises(KeyError): + od.insert_before('a', 'd', 4) # key 'd' already exists + + def test_insert_after(self): + od = OrderedDict.fromkeys('abcde') + od.insert_after('c', 'f', 6) + self.assertEqual(list(od), list('abcfde')) + with self.assertRaises(KeyError): + od.insert_after('m', 'g', 7) # key 'm' does not exists + with self.assertRaises(KeyError): + od.insert_after('e', 'd', 4) # key 'd' already exists + def test_sizeof(self): # Wimpy test: Just verify the reported size is larger than a regular dict d = dict(a=1)