| Index: infra_libs/memoize.py
|
| diff --git a/infra_libs/memoize.py b/infra_libs/memoize.py
|
| deleted file mode 100644
|
| index 3eed568112b9bfe1cb30aa9ae2375328efc7de62..0000000000000000000000000000000000000000
|
| --- a/infra_libs/memoize.py
|
| +++ /dev/null
|
| @@ -1,189 +0,0 @@
|
| -# Copyright 2014 The Chromium Authors. All rights reserved.
|
| -# Use of this source code is governed by a BSD-style license that can be
|
| -# found in the LICENSE file.
|
| -
|
| -"""
|
| -Collection of decorators to help optimize Python functions and classes
|
| -by caching return values.
|
| -
|
| -Return values are (by default) keyed off of the function's parameters.
|
| -Consequently, any parameters that are used in memoization must be hashable.
|
| -
|
| -This library offers two styles of memoization:
|
| -1) Absolute memoization (memo) uses the full set of parameters against a
|
| - per-function memo dictionary. If this is used on an instance method, the
|
| - 'self' parameter is included in the key.
|
| -2) Instance memoization (memo_i) uses a per-instance memoization dictionary.
|
| - The dictionary is stored as a member ('_memo__dict') of of the instance.
|
| - Consequently, the 'self' parameter is no longer needed/used in the
|
| - memoization key, removing the need to have the instance itself support being
|
| - hashed.
|
| -
|
| -Memoized function state can be cleared by calling the memoized function's
|
| -'memo_clear' method.
|
| -"""
|
| -
|
| -import inspect
|
| -
|
| -
|
| -# Instance variable added to class instances that use memoization to
|
| -# differentiate their memoization values.
|
| -MEMO_INSTANCE_VARIABLE = '_memo__dict'
|
| -
|
| -
|
| -class MemoizedFunction(object):
|
| - """Handles the memoization state of a given memoized function."""
|
| -
|
| - # Memoization constant to represent 'un-memoized' (b/c 'None' is a valid
|
| - # result)
|
| - class _EMPTY(object):
|
| - pass
|
| - EMPTY = _EMPTY()
|
| -
|
| - def __init__(self, func, ignore=None, memo_dict=None):
|
| - """
|
| - Args:
|
| - func: (function) The function to memoize
|
| - ignore: (container) The names of 'func' parameters to ignore when
|
| - generating its memo key. Only parameters that have no effect on the
|
| - output of the function should be included.
|
| - """
|
| - self.func = func
|
| - self.ignore = frozenset(ignore or ())
|
| - self.memo_dict = memo_dict
|
| - self.im_self = None
|
| - self.im_class = None
|
| -
|
| - def __repr__(self):
|
| - properties = [str(self.func)]
|
| - if self.im_self is not None:
|
| - properties.append('bound=%s' % (self.im_self,))
|
| - if len(self.ignore) > 0:
|
| - properties.append('ignore=%s' % (','.join(sorted(self.ignore))))
|
| - return '%s(%s)' % (type(self).__name__, ', '.join(properties))
|
| -
|
| - def __get__(self, obj, klass=None):
|
| - # Make this callable class a bindable Descriptor
|
| - if klass is None:
|
| - klass = type(obj)
|
| - self.im_self = obj
|
| - self.im_class = klass
|
| - return self
|
| -
|
| - def _get_call_args(self, args):
|
| - """Returns the call arguments, factoring in 'self' if this method is bound.
|
| - """
|
| - if self.im_self is not None:
|
| - return (self.im_self,) + args
|
| - return args
|
| -
|
| - def _get_memo_dict(self):
|
| - """Returns: (dict) the memoization dictionary to store return values in."""
|
| - memo_dict = None
|
| - if self.im_self is not None:
|
| - # Is the instance dictionary defined?
|
| - memo_dict = getattr(self.im_self, MEMO_INSTANCE_VARIABLE, None)
|
| - if memo_dict is None:
|
| - memo_dict = {}
|
| - setattr(self.im_self, MEMO_INSTANCE_VARIABLE, memo_dict)
|
| - return memo_dict
|
| -
|
| - # No instance dict; use our local 'memo_dict'.
|
| - if self.memo_dict is None:
|
| - self.memo_dict = {}
|
| - return self.memo_dict
|
| -
|
| - def _key(self, args, kwargs):
|
| - """Returns: the memoization key for a set of function arguments.
|
| -
|
| - This 'ignored' parameters are removed prior to generating the key.
|
| - """
|
| - if self.im_self is not None:
|
| - # We are bound to an instance; use None for args[0] ("self").
|
| - args = (None,) + tuple(args)
|
| -
|
| - call_params = inspect.getcallargs(self.func, *args, **kwargs)
|
| - return tuple((k, v)
|
| - for k, v in sorted(call_params.iteritems())
|
| - if k not in self.ignore)
|
| -
|
| - def __call__(self, *args, **kwargs):
|
| - """Retrieves the memoized function result.
|
| -
|
| - If the memoized function has not been memoized, it will be invoked;
|
| - otherwise, the memoized value will be returned.
|
| -
|
| - Args:
|
| - memo_key: The generated memoization key for this invocation.
|
| - args, kwargs: Function parameters (only used if not memoized yet)
|
| - Returns:
|
| - The memoized function's return value.
|
| - """
|
| -
|
| - memo_dict = self._get_memo_dict()
|
| - memo_key = self._key(args, kwargs)
|
| - result = memo_dict.get(memo_key, self.EMPTY)
|
| - if result is self.EMPTY:
|
| - args = self._get_call_args(args)
|
| - result = memo_dict[memo_key] = self.func(*args, **kwargs)
|
| - return result
|
| -
|
| - def memo_clear(self, *args, **kwargs):
|
| - """Clears memoization results for a given set of arguments.
|
| -
|
| - If no arguments are supplied, this will clear all retained memoization for
|
| - this function.
|
| -
|
| - If no memoized result is stored for the supplied parameters, this function
|
| - is a no-op.
|
| -
|
| - Args:
|
| - args, kwargs: Memoization function parameters whose memoized value should
|
| - be cleared.
|
| - """
|
| - memo_dict = self._get_memo_dict()
|
| -
|
| - if args or kwargs:
|
| - memo_key = self._key(args, kwargs)
|
| - memo_dict.pop(memo_key, None)
|
| - else:
|
| - memo_dict.clear()
|
| -
|
| -
|
| -
|
| -def memo(ignore=None, memo_dict=None):
|
| - """Generic function memoization decorator.
|
| -
|
| - This memoizes a specific function using a function key.
|
| -
|
| - The following example memoizes the function absolutely. It will be executed
|
| - once and, after that, will only returned cached results.
|
| -
|
| - @memo.memo(ignore=('print_debug_output',))
|
| - def my_method(print_debug_output=False):
|
| - # Perform complex calculation
|
| - if print_debug_output:
|
| - print 'The calculated result is: %r' % (result)
|
| - return result
|
| -
|
| - The following example memoizes for unique values of 'param1' and 'param2',
|
| - but not 'print_debug_output' since it doesn't affect the function's result:
|
| -
|
| - @memo.memo()
|
| - def my_method(param1, param2):
|
| - # Perform complex calculation using 'param1' and 'param2'
|
| - if print_debug_output:
|
| - print 'The calculated result for (%r, %r) is: %r' %
|
| - (param1, param2, result)
|
| - return result
|
| -
|
| - Args:
|
| - ignore: (list) The names of parameters to ignore when memoizing.
|
| - """
|
| - def wrap(func):
|
| - return MemoizedFunction(
|
| - func,
|
| - ignore=ignore,
|
| - memo_dict=memo_dict,
|
| - )
|
| - return wrap
|
|
|