Add library.scan_hierarchy to quickly gather layout stats
This commit is contained in:
parent
34a334f6f3
commit
fbe5cee7f5
@ -1,16 +1,17 @@
|
|||||||
"""
|
"""
|
||||||
File-level read/write functionality.
|
File-level read/write functionality.
|
||||||
"""
|
"""
|
||||||
from typing import List, Dict, Tuple, Optional, BinaryIO, TypeVar, Type
|
from typing import List, Dict, Tuple, Optional, BinaryIO, TypeVar, Type, MutableMapping
|
||||||
import io
|
import io
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
|
from collections import defaultdict
|
||||||
|
|
||||||
from .basic import KlamathError
|
from .basic import KlamathError
|
||||||
from .record import Record
|
from .record import Record
|
||||||
|
|
||||||
from .records import HEADER, BGNLIB, ENDLIB, UNITS, LIBNAME
|
from .records import HEADER, BGNLIB, ENDLIB, UNITS, LIBNAME
|
||||||
from .records import BGNSTR, STRNAME, ENDSTR
|
from .records import BGNSTR, STRNAME, ENDSTR, SNAME, COLROW, ENDEL
|
||||||
from .records import BOX, BOUNDARY, NODE, PATH, TEXT, SREF, AREF
|
from .records import BOX, BOUNDARY, NODE, PATH, TEXT, SREF, AREF
|
||||||
from .elements import Element, Reference, Text, Box, Boundary, Path, Node
|
from .elements import Element, Reference, Text, Box, Boundary, Path, Node
|
||||||
|
|
||||||
@ -183,3 +184,50 @@ def read_elements(stream: BinaryIO) -> List[Element]:
|
|||||||
stream.seek(size, io.SEEK_CUR)
|
stream.seek(size, io.SEEK_CUR)
|
||||||
size, tag = Record.read_header(stream)
|
size, tag = Record.read_header(stream)
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
||||||
|
def scan_hierarchy(stream: BinaryIO) -> Dict[bytes, Dict[bytes, int]]:
|
||||||
|
"""
|
||||||
|
Scan through a GDS file, building a table of instance counts
|
||||||
|
`{b'structure_name': {b'ref_name': count}}`.
|
||||||
|
|
||||||
|
This is intended to provide a fast overview of the file's
|
||||||
|
contents without performing a full read of all elements.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
stream: Seekable stream to read from. Should be positioned
|
||||||
|
before the first structure record, but possibly
|
||||||
|
already past the file header.
|
||||||
|
"""
|
||||||
|
structures = {}
|
||||||
|
|
||||||
|
ref_name = None
|
||||||
|
ref_count = None
|
||||||
|
cur_structure: MutableMapping[bytes, int] = defaultdict(int)
|
||||||
|
size, tag = Record.read_header(stream)
|
||||||
|
while tag != ENDLIB.tag:
|
||||||
|
if tag == BGNSTR.tag:
|
||||||
|
stream.seek(size, io.SEEK_CUR)
|
||||||
|
name = STRNAME.read(stream)
|
||||||
|
if name in structures:
|
||||||
|
raise KlamathError(f'Duplicate structure name: {name!r}')
|
||||||
|
cur_structure = defaultdict(int)
|
||||||
|
structures[name] = cur_structure
|
||||||
|
ref_name = None
|
||||||
|
ref_count = None
|
||||||
|
elif tag == SNAME.tag:
|
||||||
|
ref_name = SNAME.read_data(stream, size)
|
||||||
|
elif tag == COLROW.tag:
|
||||||
|
colrow = COLROW.read_data(stream, size)
|
||||||
|
ref_count = colrow[0] * colrow[1]
|
||||||
|
elif tag == ENDEL.tag:
|
||||||
|
if ref_count is None:
|
||||||
|
ref_count = 1
|
||||||
|
assert(ref_name is not None)
|
||||||
|
cur_structure[ref_name] += ref_count
|
||||||
|
else:
|
||||||
|
stream.seek(size, io.SEEK_CUR)
|
||||||
|
size, tag = Record.read_header(stream)
|
||||||
|
|
||||||
|
dict_structures = {key: dict(value) for key, value in structures.items()}
|
||||||
|
return dict_structures
|
||||||
|
Loading…
Reference in New Issue
Block a user