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

43

44

45

46

47

48

49

50

51

52

53

54

# https://pyrocko.org - GPLv3 

# 

# The Pyrocko Developers, 21st Century 

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

 

from __future__ import absolute_import, print_function, division 

 

 

class Stage(object): 

def __init__(self, f): 

self._f = f 

self._parent = None 

self._cache = {} 

 

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

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

return self.call_nocache(*x) 

 

if x not in self._cache: 

if self._parent is not None: 

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

else: 

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

 

return self._cache[x] 

 

def call_nocache(self, *x): 

if self._parent is not None: 

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

else: 

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

 

def clear(self): 

self._cache.clear() 

 

 

class Chain(object): 

def __init__(self, *stages): 

parent = None 

self.stages = [] 

for stage in stages: 

if not isinstance(stage, Stage): 

stage = Stage(stage) 

 

stage._parent = parent 

parent = stage 

self.stages.append(stage) 

 

def clear(self): 

for stage in self.stages: 

stage.clear() 

 

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

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