1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
|
import weakref
from rpython.rlib.rweakref import dead_ref
def _reduced_value(s):
while True:
divide = s & 1
s >>= 1
if not divide:
return s
class RWeakListMixin(object):
_mixin_ = True
def initialize(self):
self.handles = []
self.look_distance = 0
def get_all_handles(self):
return self.handles
def reserve_next_handle_index(self):
# The reservation ordering done here is tweaked for pypy's
# memory allocator. We look from index 'look_distance'.
# Look_distance increases from 0. But we also look at
# "look_distance/2" or "/4" or "/8", etc. If we find that one
# of these secondary locations is free, we assume it's because
# there was recently a minor collection; so we reset
# look_distance to 0 and start again from the lowest locations.
length = len(self.handles)
for d in range(self.look_distance, length):
if self.handles[d]() is None:
self.look_distance = d + 1
return d
s = _reduced_value(d)
if self.handles[s]() is None:
break
# restart from the beginning
for d in range(0, length):
if self.handles[d]() is None:
self.look_distance = d + 1
return d
# full! extend, but don't use '+=' here
self.handles = self.handles + [dead_ref] * (length // 3 + 5)
self.look_distance = length + 1
return length
def add_handle(self, content):
index = self.reserve_next_handle_index()
self.store_handle(index, content)
return index
def store_handle(self, index, content):
self.handles[index] = weakref.ref(content)
def fetch_handle(self, index):
if 0 <= index < len(self.handles):
return self.handles[index]()
return None
|