1# http://pyrocko.org - GPLv3 

2# 

3# The Pyrocko Developers, 21st Century 

4# ---|P------/S----------~Lg---------- 

5 

6 

7class Stage(object): 

8 def __init__(self, f): 

9 self._f = f 

10 self._parent = None 

11 self._cache = {} 

12 

13 def __call__(self, *x, **kwargs): 

14 if kwargs.get('nocache', False): 

15 return self.call_nocache(*x) 

16 

17 if x not in self._cache: 

18 if self._parent is not None: 

19 self._cache[x] = self._f(self._parent(*x[:-1]), *x[-1]) 

20 else: 

21 self._cache[x] = self._f(*x[-1]) 

22 

23 return self._cache[x] 

24 

25 def call_nocache(self, *x): 

26 if self._parent is not None: 

27 return self._f(self._parent.call_nocache(*x[:-1]), *x[-1]) 

28 else: 

29 return self._f(*x[-1]) 

30 

31 def clear(self): 

32 self._cache.clear() 

33 

34 

35class Chain(object): 

36 def __init__(self, *stages): 

37 parent = None 

38 self.stages = [] 

39 for stage in stages: 

40 if not isinstance(stage, Stage): 

41 stage = Stage(stage) 

42 

43 stage._parent = parent 

44 parent = stage 

45 self.stages.append(stage) 

46 

47 def clear(self): 

48 for stage in self.stages: 

49 stage.clear() 

50 

51 def __call__(self, *x, **kwargs): 

52 return self.stages[len(x)-1](*x, **kwargs)