summaryrefslogtreecommitdiffstats
path: root/powerline/lib/memoize.py
blob: cedbe45e69c40061cac0358dab30febc4d6860a4 (plain)
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
# vim:fileencoding=utf-8:noet
from __future__ import (unicode_literals, division, absolute_import, print_function)

from functools import wraps

from powerline.lib.monotonic import monotonic


def default_cache_key(**kwargs):
	return frozenset(kwargs.items())


class memoize(object):
	'''Memoization decorator with timeout.'''
	def __init__(self, timeout, cache_key=default_cache_key, cache_reg_func=None):
		self.timeout = timeout
		self.cache_key = cache_key
		self.cache = {}
		self.cache_reg_func = cache_reg_func

	def __call__(self, func):
		@wraps(func)
		def decorated_function(**kwargs):
			if self.cache_reg_func:
				self.cache_reg_func(self.cache)
				self.cache_reg_func = None

			key = self.cache_key(**kwargs)
			try:
				cached = self.cache.get(key, None)
			except TypeError:
				return func(**kwargs)
			# Handle case when time() appears to be less then cached['time'] due 
			# to clock updates. Not applicable for monotonic clock, but this 
			# case is currently rare.
			if cached is None or not (cached['time'] < monotonic() < cached['time'] + self.timeout):
				cached = self.cache[key] = {
					'result': func(**kwargs),
					'time': monotonic(),
				}
			return cached['result']
		return decorated_function