+++ /dev/null
-# -*- coding: utf-8 -*-
-#######################################################################################
-# Photo is a part of Plinn - http://plinn.org #
-# Copyright (C) 2008 BenoƮt PIN <benoit.pin@ensmp.fr> #
-# #
-# This program is free software; you can redistribute it and/or #
-# modify it under the terms of the GNU General Public License #
-# as published by the Free Software Foundation; either version 2 #
-# of the License, or (at your option) any later version. #
-# #
-# This program is distributed in the hope that it will be useful, #
-# but WITHOUT ANY WARRANTY; without even the implied warranty of #
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
-# GNU General Public License for more details. #
-# #
-# You should have received a copy of the GNU General Public License #
-# along with this program; if not, write to the Free Software #
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #
-#######################################################################################
-""" Memoization utils
-
-
-
-"""
-
-import inspect
-from BTrees.OOBTree import OOBTree
-
-def memoizedmethod(*indexes, **options) :
- """ Used as decorator, this function stores result
- of method m inside self._methodResultsCache or
- self._v__methodResultsCache if volatile.
- This decorator may be used inside a class which provides
- a mapping object named _methodResultsCache and / or
- _v__methodResultsCache.
-
- example :
-
- 1 - simple metdhod memoization
-
- @memoizedmethod()
- def methodWithNoParameters(self): pass
-
- 2 - indexed memoisation:
- Parameters names are passed to memoizedmethod are
- evaluated to construct an indexed cache.
- Names must be a subset of the memoized method signature.
-
- @memoizedmethod('arg1', 'arg2')
- def methodWithParameters(self, arg1, arg2=None): pass
- """
- volatile = options.get('volatile', False)
- cacheVarName = '_methodResultsCache'
- if volatile==True :
- cacheVarName = '_v_%s' % cacheVarName
-
- def makeMemoizedMethod(m) :
- methodname = m.__name__
-
- if not indexes :
- def memoizedMethod(self) :
- if not hasattr(self, cacheVarName) :
- setattr(self, cacheVarName, OOBTree())
- cache = getattr(self, cacheVarName)
- if cache.has_key(methodname) :
- return cache[methodname]
- else :
- res = m(self)
- cache[methodname] = res
- return res
-
- memoizedMethod.__name__ = methodname
- memoizedMethod.__doc__ = m.__doc__
- return memoizedMethod
-
- else :
- args, varargs, varkw, defaults = inspect.getargspec(m)
- args = list(args)
- if defaults is None :
- defaults = []
- mandatoryargs = args[1:-len(defaults)]
- optargs = args[-len(defaults):]
- defaultValues = dict(zip([name for name in args[-len(defaults):]], [val for val in defaults]))
-
- indexPositions = []
- for index in indexes :
- try :
- indexPositions.append((index, args.index(index)))
- except ValueError :
- raise ValueError("%r argument is not in signature of %r" % (index, methodname))
-
- if indexPositions :
- indexPositions.sort(lambda a, b : cmp(a[1], b[1]))
-
- indexPositions = tuple(indexPositions)
-
-
- def memoizedMethod(self, *args, **kw) :
- # test if m if called by ZPublished
- if len(args) < len(mandatoryargs) and hasattr(self, 'REQUEST') :
- assert not kw
- args = list(args)
- get = lambda name : self.REQUEST[name]
- for name in mandatoryargs :
- try :
- args.append(get(name))
- except KeyError :
- exactOrAtLeast = defaults and 'exactly' or 'at least'
- raise TypeError('%(methodname)s takes %(exactOrAtLeast)s %(mandatoryArgsLength)d argument (%(givenArgsLength)s given)' % \
- { 'methodname': methodname
- , 'exactOrAtLeast': exactOrAtLeast
- , 'mandatoryArgsLength': len(mandatoryargs)
- , 'givenArgsLength': len(args)})
-
- for name in optargs :
- get = self.REQUEST.get
- args.append(get(name, defaultValues[name]))
-
- args = tuple(args)
-
- if not hasattr(self, cacheVarName) :
- setattr(self, cacheVarName, OOBTree())
- cache = getattr(self, cacheVarName)
- if not cache.has_key(methodname) :
- cache[methodname] = OOBTree()
-
- cache = cache[methodname]
- index = aggregateIndex(indexPositions, args)
-
- if cache.has_key(index) :
- return cache[index]
- else :
- res = m(self, *args, **kw)
- cache[index] = res
- return res
-
- memoizedMethod.__name__ = methodname
- memoizedMethod.__doc__ = m.__doc__
- return memoizedMethod
-
- return makeMemoizedMethod
-
-def aggregateIndex(indexPositions, args):
- '''
- Returns the index to be used when looking for or inserting
- a cache entry.
- view_name is a string.
- local_keys is a mapping or None.
- '''
-
- agg_index = []
-
- for name, pos in indexPositions :
- val = args[pos-1]
- agg_index.append((name, str(val)))
-
- return tuple(agg_index)