[library / gdsii] add materialize_detached and do some more cleanup
This commit is contained in:
parent
29947c6c01
commit
93dd3503ca
11 changed files with 930 additions and 23 deletions
|
|
@ -33,6 +33,23 @@ class IMaterializable(ABC):
|
|||
for name in dict.fromkeys(names)
|
||||
})
|
||||
|
||||
def materialize_detached(self, name: str) -> Pattern:
|
||||
"""Materialize a caller-owned pattern which is safe to mutate."""
|
||||
return self.materialize(name, persist=False).deepcopy()
|
||||
|
||||
def materialize_many_detached(
|
||||
self,
|
||||
names: Sequence[str],
|
||||
) -> LibraryView:
|
||||
"""Materialize caller-owned patterns without retaining them in this library."""
|
||||
from .mapping import LibraryView # noqa: PLC0415
|
||||
|
||||
materialized = self.materialize_many(names, persist=False)
|
||||
return LibraryView({
|
||||
name: materialized[name].deepcopy()
|
||||
for name in dict.fromkeys(names)
|
||||
})
|
||||
|
||||
|
||||
class IBorrowing(ABC):
|
||||
"""Capability for library views which directly borrow other libraries."""
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ from .capabilities import IBorrowing, IMaterializable
|
|||
from .utils import dangling_mode_t, _validate_dangling_mode
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from collections.abc import Callable, Iterator, Mapping, MutableMapping
|
||||
from collections.abc import Callable, Iterator, Mapping, MutableMapping, Sequence
|
||||
|
||||
import numpy
|
||||
from numpy.typing import NDArray
|
||||
|
|
@ -103,6 +103,25 @@ class _SubtreeLibraryView(ILibraryView, IMaterializable, IBorrowing):
|
|||
return self._source.materialize(name, persist=persist)
|
||||
return self._source[name]
|
||||
|
||||
def materialize_detached(self, name: str) -> Pattern:
|
||||
if name not in self._names:
|
||||
raise KeyError(name)
|
||||
if isinstance(self._source, IMaterializable):
|
||||
return self._source.materialize_detached(name)
|
||||
return self._source[name].deepcopy()
|
||||
|
||||
def materialize_many_detached(
|
||||
self,
|
||||
names: Sequence[str],
|
||||
) -> LibraryView:
|
||||
ordered_names = tuple(dict.fromkeys(names))
|
||||
missing = next((name for name in ordered_names if name not in self._names), None)
|
||||
if missing is not None:
|
||||
raise KeyError(missing)
|
||||
if isinstance(self._source, IMaterializable):
|
||||
return self._source.materialize_many_detached(ordered_names)
|
||||
return LibraryView({name: self._source[name].deepcopy() for name in ordered_names})
|
||||
|
||||
def child_graph(
|
||||
self,
|
||||
dangling: dangling_mode_t = 'error',
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ class _SourceEntry:
|
|||
|
||||
def _materialize_detached_pattern(view: ILibraryView, name: str) -> Pattern:
|
||||
if isinstance(view, IMaterializable):
|
||||
return view.materialize(name, persist=False).deepcopy()
|
||||
return view.materialize_detached(name)
|
||||
return view[name].deepcopy()
|
||||
|
||||
|
||||
|
|
@ -74,10 +74,7 @@ class _ProcessedLibraryView(ILibraryView, IMaterializable, IBorrowing):
|
|||
"""Apply this view's processing to one detached source pattern."""
|
||||
raise NotImplementedError
|
||||
|
||||
def materialize(self, name: str, *, persist: bool = True) -> Pattern:
|
||||
if name in self._cache:
|
||||
return self._cache[name]
|
||||
|
||||
def _materialize_uncached_detached(self, name: str) -> Pattern:
|
||||
if name in self._lookups_in_progress:
|
||||
chain = ' -> '.join(self._lookups_in_progress + [name])
|
||||
raise LibraryError(
|
||||
|
|
@ -93,10 +90,52 @@ class _ProcessedLibraryView(ILibraryView, IMaterializable, IBorrowing):
|
|||
finally:
|
||||
self._lookups_in_progress.pop()
|
||||
|
||||
return pattern
|
||||
|
||||
def materialize(self, name: str, *, persist: bool = True) -> Pattern:
|
||||
if name in self._cache:
|
||||
return self._cache[name]
|
||||
|
||||
pattern = self._materialize_uncached_detached(name)
|
||||
|
||||
if persist:
|
||||
self._cache[name] = pattern
|
||||
return pattern
|
||||
|
||||
def materialize_detached(self, name: str) -> Pattern:
|
||||
if name in self._cache:
|
||||
return self._cache[name].deepcopy()
|
||||
return self._materialize_uncached_detached(name)
|
||||
|
||||
def materialize_many_detached(
|
||||
self,
|
||||
names: Sequence[str],
|
||||
) -> LibraryView:
|
||||
ordered_names = tuple(dict.fromkeys(names))
|
||||
result: dict[str, Pattern] = {}
|
||||
uncached = [name for name in ordered_names if name not in self._cache]
|
||||
|
||||
for name in ordered_names:
|
||||
if name in self._cache:
|
||||
result[name] = self._cache[name].deepcopy()
|
||||
|
||||
if uncached:
|
||||
if isinstance(self._source, IMaterializable):
|
||||
source_patterns = self._source.materialize_many_detached(uncached)
|
||||
else:
|
||||
source_patterns = LibraryView({name: self._source[name].deepcopy() for name in uncached})
|
||||
for name in uncached:
|
||||
if name in self._lookups_in_progress:
|
||||
chain = ' -> '.join(self._lookups_in_progress + [name])
|
||||
raise LibraryError(f'Detected circular reference or recursive lookup of "{name}".\nLookup chain: {chain}')
|
||||
self._lookups_in_progress.append(name)
|
||||
try:
|
||||
result[name] = self._process_pattern(name, source_patterns[name])
|
||||
finally:
|
||||
self._lookups_in_progress.pop()
|
||||
|
||||
return LibraryView({name: result[name] for name in ordered_names})
|
||||
|
||||
def source_order(self) -> tuple[str, ...]:
|
||||
return self._source.source_order()
|
||||
|
||||
|
|
@ -362,6 +401,14 @@ class OverlayLibrary(ILibrary, IMaterializable, IBorrowing):
|
|||
visible = layer.source_target_map.get(target, target)
|
||||
return self._resolve_target(visible)
|
||||
|
||||
def _remap_source_pattern(self, layer: _SourceLayer, source_pat: Pattern) -> Pattern:
|
||||
def remap(target: str | None) -> str | None:
|
||||
return None if target is None else self._effective_target(layer, target)
|
||||
|
||||
if source_pat.refs:
|
||||
source_pat.refs = map_targets(source_pat.refs, remap)
|
||||
return source_pat
|
||||
|
||||
def materialize(self, name: str, *, persist: bool = True) -> Pattern:
|
||||
if name not in self._entries:
|
||||
raise KeyError(name)
|
||||
|
|
@ -371,17 +418,54 @@ class OverlayLibrary(ILibrary, IMaterializable, IBorrowing):
|
|||
|
||||
layer = self._layers[entry.layer_index]
|
||||
source_pat = _materialize_detached_pattern(layer.library, entry.source_name)
|
||||
|
||||
def remap(target: str | None) -> str | None:
|
||||
return None if target is None else self._effective_target(layer, target)
|
||||
|
||||
if source_pat.refs:
|
||||
source_pat.refs = map_targets(source_pat.refs, remap)
|
||||
pat = source_pat
|
||||
pat = self._remap_source_pattern(layer, source_pat)
|
||||
if persist:
|
||||
self._entries[name] = pat
|
||||
return pat
|
||||
|
||||
def materialize_detached(self, name: str) -> Pattern:
|
||||
if name not in self._entries:
|
||||
raise KeyError(name)
|
||||
entry = self._entries[name]
|
||||
if isinstance(entry, Pattern):
|
||||
return entry.deepcopy()
|
||||
layer = self._layers[entry.layer_index]
|
||||
source_pat = _materialize_detached_pattern(layer.library, entry.source_name)
|
||||
return self._remap_source_pattern(layer, source_pat)
|
||||
|
||||
def materialize_many_detached(
|
||||
self,
|
||||
names: Sequence[str],
|
||||
) -> LibraryView:
|
||||
ordered_names = tuple(dict.fromkeys(names))
|
||||
missing = next((name for name in ordered_names if name not in self._entries), None)
|
||||
if missing is not None:
|
||||
raise KeyError(missing)
|
||||
|
||||
result: dict[str, Pattern] = {}
|
||||
grouped: dict[int, list[tuple[str, str]]] = defaultdict(list)
|
||||
for name in ordered_names:
|
||||
entry = self._entries[name]
|
||||
if isinstance(entry, Pattern):
|
||||
result[name] = entry.deepcopy()
|
||||
else:
|
||||
grouped[entry.layer_index].append((name, entry.source_name))
|
||||
|
||||
for layer_index, cells in grouped.items():
|
||||
layer = self._layers[layer_index]
|
||||
source_names = [source_name for _name, source_name in cells]
|
||||
if isinstance(layer.library, IMaterializable):
|
||||
source_patterns = layer.library.materialize_many_detached(source_names)
|
||||
else:
|
||||
source_patterns = LibraryView({
|
||||
source_name: layer.library[source_name].deepcopy()
|
||||
for source_name in source_names
|
||||
})
|
||||
for name, source_name in cells:
|
||||
result[name] = self._remap_source_pattern(layer, source_patterns[source_name])
|
||||
|
||||
return LibraryView({name: result[name] for name in ordered_names})
|
||||
|
||||
def child_graph(
|
||||
self,
|
||||
dangling: dangling_mode_t = 'error',
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue