# -*- coding: utf-8 -*- # Copyright 2018 gevent contributors. See LICENSE for details. # cython: auto_pickle=False,embedsignature=True,always_allow_keywords=False from __future__ import absolute_import from __future__ import division from __future__ import print_function from weakref import WeakKeyDictionary from weakref import ref from heapq import heappop from heapq import heappush __all__ = [ 'IdentRegistry', ] class ValuedWeakRef(ref): """ A weak ref with an associated value. """ # This seems entirely spurious; even on Python 2.7 # weakref.ref descends from object # pylint: disable=slots-on-old-class __slots__ = ('value',) class IdentRegistry(object): """ Maintains a unique mapping of (small) positive integer identifiers to objects that can be weakly referenced. It is guaranteed that no two objects will have the the same identifier at the same time, as long as those objects are also uniquely hashable. """ def __init__(self): # {obj -> (ident, wref(obj))} self._registry = WeakKeyDictionary() # A heap of numbers that have been used and returned self._available_idents = [] def get_ident(self, obj): """ Retrieve the identifier for *obj*, creating one if necessary. """ try: return self._registry[obj][0] except KeyError: pass if self._available_idents: # Take the smallest free number ident = heappop(self._available_idents) else: # Allocate a bigger one ident = len(self._registry) vref = ValuedWeakRef(obj, self._return_ident) vref.value = ident # pylint:disable=assigning-non-slot,attribute-defined-outside-init self._registry[obj] = (ident, vref) return ident def _return_ident(self, vref): # By the time this is called, self._registry has been # updated if heappush is not None: # Under some circumstances we can get called # when the interpreter is shutting down, and globals # aren't available any more. heappush(self._available_idents, vref.value) def __len__(self): return len(self._registry) from gevent._util import import_c_accel import_c_accel(globals(), 'gevent.__ident')