def __init__(self, content, lowest=1, highest=1): self.content = content self.content_length = content.__len__() self.length = fastdivmod.powersum(self.content_length, lowest, highest) self.lowest = lowest self.highest = highest def arbitrary_entry(i): return (fastdivmod.powersum(self.content_length, lowest, i + lowest - 1), i + lowest) def entry_from_prev(i, prev): return (prev[0] + (self.content_length**prev[1]), prev[1] + 1) self.offsets = cachingseq.CachingFuncSequence(arbitrary_entry, highest - lowest + 1, entry_from_prev) # This needs to be a constant in order to reuse caclulations in future # calls to bisect (a moving target will produce more misses). if self.offsets[-1][0] > sys.maxint: i = 0 while i + 2 < len(self.offsets): if self.offsets[i + 1][0] > sys.maxint: self.index_of_offset = i self.offset_break = self.offsets[i][0] break i += 1 else: self.index_of_offset = len(self.offsets) self.offset_break = sys.maxint
def testIter(self): c = cachingseq.CachingFuncSequence(lambda i: i, 10) # Cache empty on construction self.assertEquals(0, len(c._cache)) self.assertEquals(10, len(c)) self.assertEquals(range(10), list(c)) # Cache full after iteration self.assertEquals(10, len(c._cache))
def testIncFunc(self): def first_func(x): assert x == 0 return 1 def inc_func(i, prev): return prev * 2 c = cachingseq.CachingFuncSequence(first_func, 10, inc_func) self.assertEquals([1, 2, 4, 8, 16, 32, 64, 128, 256, 512], list(c))
def testLimits(self): c = cachingseq.CachingFuncSequence(lambda i: i, 10) self.assertEquals(9, c[9]) self.assertEquals(9, c[-1]) self.assertEquals(0, c[0]) self.assertEquals(0, c[-10]) self.assertRaises(IndexError, lambda: c[10]) self.assertRaises(IndexError, lambda: c[11]) self.assertRaises(IndexError, lambda: c[-11]) self.assertRaises(IndexError, lambda: c[-12]) self.assertEquals(2, len(c._cache)) # Make sure .func is settable at runtime... c.func = lambda i: 'bbb' self.assertEquals('bbb', c[1]) # ...and that we don't call it again. self.assertEquals(0, c[0])
def __init__(self, content, lowest=1, highest=1): self.content = content self.content_length = content.__len__() self.length = fastdivmod.powersum(self.content_length, lowest, highest) self.lowest = lowest self.highest = highest def arbitrary_entry(i): return ( fastdivmod.powersum(self.content_length, lowest, i + lowest - 1), i + lowest, ) def entry_from_prev(i, prev): return (prev[0] + (self.content_length**prev[1]), prev[1] + 1) self.offsets = cachingseq.CachingFuncSequence(arbitrary_entry, highest - lowest + 1, entry_from_prev) # `offset_break` is an optimization around bisect, which would normally # choose the "middle" value to bisect on, which does a lot of work # that's unnecessary at the bottom of the range (say, the first 256 # entries). # # A good choice of OFFSET_BREAK_THRESHOLD minimizes the wasted work up # front (we have to calculate all the offsets now up to it), and is # still larger than most performant lookups will need. Anything above # that will result in a big penalty as we get into arbitrary-precision # integers and use the standard bisect logic. if self.offsets[-1][0] > OFFSET_BREAK_THRESHOLD: for i in range(len(self.offsets) - 1): if self.offsets[i + 1][0] > OFFSET_BREAK_THRESHOLD: self.index_of_offset = i self.offset_break = self.offsets[i][0] return self.index_of_offset = len(self.offsets) self.offset_break = self.offsets[-1][0] + 1