提交 7485db79 authored 作者: nouiz's avatar nouiz

Merge pull request #1134 from lamblin/fix_ordered_set_memleak

Use other impl. of OrderedSet to prevent mem. leak
...@@ -290,8 +290,8 @@ if sys.version_info[:2] < (2, 7): ...@@ -290,8 +290,8 @@ if sys.version_info[:2] < (2, 7):
return True return True
return dict.__eq__(self, other) return dict.__eq__(self, other)
def __ne__(self, other): def __ne__(self, other):
return not self == other return not self == other
else: else:
try: try:
......
...@@ -19,9 +19,7 @@ def check_deterministic(iterable): ...@@ -19,9 +19,7 @@ def check_deterministic(iterable):
list, tuple, OrderedSet, types.GeneratorType, basestring)) list, tuple, OrderedSet, types.GeneratorType, basestring))
if MutableSet is not None: if MutableSet is not None:
# From http://code.activestate.com/recipes/576694/
# Copyright (C) 2009 Raymond Hettinger # Copyright (C) 2009 Raymond Hettinger
# Permission is hereby granted, free of charge, to any person obtaining a # Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the # copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including # "Software"), to deal in the Software without restriction, including
...@@ -40,9 +38,22 @@ if MutableSet is not None: ...@@ -40,9 +38,22 @@ if MutableSet is not None:
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
KEY, PREV, NEXT = range(3) ## {{{ http://code.activestate.com/recipes/576696/ (r5)
import collections
class OrderedSet(MutableSet): from weakref import proxy
class Link(object):
__slots__ = 'prev', 'next', 'key', '__weakref__'
class OrderedSet(collections.MutableSet):
'Set the remembers the order elements were added'
# Big-O running times for all methods are the same as for regular sets.
# The internal self.__map dictionary maps keys to links in a doubly linked list.
# The circular doubly linked list starts and ends with a sentinel element.
# The sentinel element never gets deleted (this simplifies the algorithm).
# The prev/next links are weakref proxies (to prevent circular references).
# Individual links are kept alive by the hard reference in self.__map.
# Those hard references disappear when a key is deleted from an OrderedSet.
# Added by IG-- pre-existing theano code expected sets # Added by IG-- pre-existing theano code expected sets
# to have this method # to have this method
...@@ -53,43 +64,50 @@ if MutableSet is not None: ...@@ -53,43 +64,50 @@ if MutableSet is not None:
def __init__(self, iterable=None): def __init__(self, iterable=None):
# Checks added by IG # Checks added by IG
check_deterministic(iterable) check_deterministic(iterable)
self.end = end = [] self.__root = root = Link() # sentinel node for doubly linked list
end += [None, end, end] # sentinel node for doubly linked list root.prev = root.next = root
self.map = {} # key --> [key, prev, next] self.__map = {} # key --> link
if iterable is not None: if iterable is not None:
self |= iterable self |= iterable
def __len__(self): def __len__(self):
return len(self.map) return len(self.__map)
def __contains__(self, key): def __contains__(self, key):
return key in self.map return key in self.__map
def add(self, key): def add(self, key):
if key not in self.map: # Store new key in a new link at the end of the linked list
end = self.end if key not in self.__map:
curr = end[PREV] self.__map[key] = link = Link()
curr[NEXT] = end[PREV] = self.map[key] = [key, curr, end] root = self.__root
last = root.prev
link.prev, link.next, link.key = last, root, key
last.next = root.prev = proxy(link)
def discard(self, key): def discard(self, key):
if key in self.map: # Remove an existing item using self.__map to find the link which is
key, prev, next = self.map.pop(key) # then removed by updating the links in the predecessor and successors.
prev[NEXT] = next if key in self.__map:
next[PREV] = prev link = self.__map.pop(key)
link.prev.next = link.next
link.next.prev = link.prev
def __iter__(self): def __iter__(self):
end = self.end # Traverse the linked list in order.
curr = end[NEXT] root = self.__root
while curr is not end: curr = root.next
yield curr[KEY] while curr is not root:
curr = curr[NEXT] yield curr.key
curr = curr.next
def __reversed__(self): def __reversed__(self):
end = self.end # Traverse the linked list in reverse order.
curr = end[PREV] root = self.__root
while curr is not end: curr = root.prev
yield curr[KEY] while curr is not root:
curr = curr[PREV] yield curr.key
curr = curr.prev
def pop(self, last=True): def pop(self, last=True):
if not self: if not self:
...@@ -123,8 +141,8 @@ if MutableSet is not None: ...@@ -123,8 +141,8 @@ if MutableSet is not None:
else: else:
return NotImplemented return NotImplemented
def __del__(self): ## end of http://code.activestate.com/recipes/576696/ }}}
self.clear() # remove circular references
else: else:
# Python 2.4 # Python 2.4
class OrderedSet(object): class OrderedSet(object):
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论