Skip to content

Commit 8abb7a4

Browse files
committed
Small performance optimizations
1 parent ab17b03 commit 8abb7a4

File tree

2 files changed

+26
-7
lines changed

2 files changed

+26
-7
lines changed

dissect/cstruct/compiler.py

+23-6
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import io
66
import logging
7+
import re
78
from enum import Enum
89
from textwrap import dedent, indent
910
from typing import TYPE_CHECKING, Iterator, Optional
@@ -47,6 +48,8 @@
4748
WcharArray,
4849
)
4950

51+
RE_TYPE_LOOKUP = re.compile(r"lookup\[[\"\'](.+?)[\"\']\].type")
52+
5053
log = logging.getLogger(__name__)
5154

5255
python_compile = compile
@@ -58,7 +61,7 @@ def compile(structure: type[Structure]) -> type[Structure]:
5861

5962
try:
6063
structure._read = classmethod(
61-
generate_read(structure.cs, structure.fields, structure.__name__, structure.align)
64+
generate_read(structure.cs, structure.fields, structure.__lookup__, structure.__name__, structure.align)
6265
)
6366
structure.__compiled__ = True
6467
except Exception as e:
@@ -68,11 +71,26 @@ def compile(structure: type[Structure]) -> type[Structure]:
6871
return structure
6972

7073

71-
def generate_read(cs: cstruct, fields: list[Field], name: Optional[str] = None, align: bool = False) -> Iterator[str]:
74+
def generate_read(
75+
cs: cstruct, fields: list[Field], lookup, name: Optional[str] = None, align: bool = False
76+
) -> Iterator[str]:
7277
source = generate_read_source(cs, fields, align)
7378

74-
code = python_compile(source, f"<compiled {name or 'anonymous'}>", "exec")
75-
exec(code, {"BitBuffer": BitBuffer, "_struct": _struct}, d := {})
79+
token_id = 0
80+
token_map = {}
81+
82+
def _replace_token(match):
83+
nonlocal token_id
84+
token = f"_{token_id}"
85+
token_map[token] = match.group(1)
86+
token_id += 1
87+
return token
88+
89+
source = re.sub(RE_TYPE_LOOKUP, _replace_token, source)
90+
symbols = {token: lookup[field_name].type for token, field_name in token_map.items()}
91+
92+
code = python_compile(source, f"<compiled {name or 'anonymous'}._read>", "exec")
93+
exec(code, {"BitBuffer": BitBuffer, "_struct": _struct, **symbols}, d := {})
7694
obj = d.popitem()[1]
7795
obj.__source__ = source
7896

@@ -83,7 +101,6 @@ def generate_read_source(cs: cstruct, fields: list[Field], align: bool = False)
83101
preamble = """
84102
r = {}
85103
s = {}
86-
lookup = cls.__lookup__
87104
"""
88105

89106
if any(field.bits for field in fields):
@@ -92,7 +109,7 @@ def generate_read_source(cs: cstruct, fields: list[Field], align: bool = False)
92109
read_code = "\n".join(generate_fields_read(cs, fields, align))
93110

94111
outro = """
95-
obj = cls(**r)
112+
obj = type.__call__(cls, **r)
96113
obj._sizes = s
97114
obj._values = r
98115

dissect/cstruct/types/structure.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,9 @@ def _update_fields(
101101
from dissect.cstruct import compiler
102102

103103
try:
104-
classdict["_read"] = classmethod(compiler.generate_read(cls.cs, fields, cls.align))
104+
classdict["_read"] = classmethod(
105+
compiler.generate_read(cls.cs, fields, raw_lookup, cls.__name__, align=cls.align)
106+
)
105107
classdict["__compiled__"] = True
106108
except Exception:
107109
classdict["__compiled__"] = False

0 commit comments

Comments
 (0)