-
Notifications
You must be signed in to change notification settings - Fork 160
/
Copy pathcache.py
51 lines (39 loc) · 1.86 KB
/
cache.py
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
from __future__ import annotations
from collections.abc import Callable, Hashable
from typing import TYPE_CHECKING, TypeVar
if TYPE_CHECKING:
from sc2.bot_ai import BotAI
T = TypeVar("T")
class CacheDict(dict):
def retrieve_and_set(self, key: Hashable, func: Callable[[], T]) -> T:
"""Either return the value at a certain key,
or set the return value of a function to that key, then return that value."""
if key not in self:
self[key] = func()
return self[key]
class property_cache_once_per_frame(property): # noqa: N801
"""This decorator caches the return value for one game loop,
then clears it if it is accessed in a different game loop.
Only works on properties of the bot object, because it requires
access to self.state.game_loop
This decorator compared to the above runs a little faster, however you should only use this decorator if you are sure that you do not modify the mutable once it is calculated and cached.
Copied and modified from https://tedboy.github.io/flask/_modules/werkzeug/utils.html#cached_property
#"""
def __init__(self, func: Callable[[BotAI], T], name=None) -> None:
self.__name__ = name or func.__name__
self.__frame__ = f"__frame__{self.__name__}"
self.func = func
def __set__(self, obj: BotAI, value: T) -> None:
obj.cache[self.__name__] = value
# pyre-ignore[16]
obj.cache[self.__frame__] = obj.state.game_loop
# pyre-fixme[34]
def __get__(self, obj: BotAI, _type=None) -> T:
value = obj.cache.get(self.__name__, None)
# pyre-ignore[16]
bot_frame = obj.state.game_loop
if value is None or obj.cache[self.__frame__] < bot_frame:
value = self.func(obj)
obj.cache[self.__name__] = value
obj.cache[self.__frame__] = bot_frame
return value