Split KeyAttrDict.__cache into memory friendly partitions.

This commit is contained in:
xs5871 2023-02-08 21:21:22 +00:00 committed by xs5871
parent 62d6bf16df
commit e7427ff53b

View File

@ -400,43 +400,59 @@ KEY_GENERATORS = (
class KeyAttrDict: class KeyAttrDict:
__cache = {} # Instead of relying on the uncontrollable availability of a big chunk of
# contiguous memory for key caching, we can manually fragment the cache into
# reasonably small partitions. The partition size is chosen from the magic
# values of CPs hash allocation sizes.
# (https://github.com/adafruit/circuitpython/blob/main/py/map.c, 2023-02)
__partition_size = 37
__cache = [{}]
def __iter__(self): def __iter__(self):
return self.__cache.__iter__() return self.__cache.__iter__()
def __setitem__(self, key: str, value: Key): def __setitem__(self, name: str, key: Key):
self.__cache.__setitem__(key, value) # Overwrite existing reference.
for partition in self.__cache:
if name in partition:
partition[name] = key
return key
def __getattr__(self, key: Key): # Insert new reference.
return self.__getitem__(key) if len(self.__cache[-1]) >= self.__partition_size:
self.__cache.append({})
self.__cache[-1][name] = key
return key
def get(self, key: Key, default: Optional[Key] = None): def __getattr__(self, name: str):
return self.__getitem__(name)
def get(self, name: str, default: Optional[Key] = None):
try: try:
return self.__getitem__(key) return self.__getitem__(name)
except Exception: except Exception:
return default return default
def clear(self): def clear(self):
self.__cache.clear() self.__cache.clear()
self.__cache.append({})
def __getitem__(self, key: Key): def __getitem__(self, name: str):
try: for partition in self.__cache:
return self.__cache[key] if name in partition:
except KeyError: return partition[name]
pass
for func in KEY_GENERATORS: for func in KEY_GENERATORS:
maybe_key = func(key) maybe_key = func(name)
if maybe_key: if maybe_key:
break break
else: else:
raise ValueError(f'Invalid key: {key}') raise ValueError(f'Invalid key: {name}')
if debug.enabled: if debug.enabled:
debug(f'{key}: {maybe_key}') debug(f'{name}: {maybe_key}')
return self.__cache[key] return maybe_key
# Global state, will be filled in throughout this file, and # Global state, will be filled in throughout this file, and