feat: improve unmarshall performance for SignatureType (#436)

This commit is contained in:
J. Nick Koston 2025-03-23 00:41:06 -10:00 committed by GitHub
parent 2ae89b1dd9
commit e0aeeacf8d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 47 additions and 9 deletions

View File

@ -607,7 +607,7 @@ class Unmarshaller:
)
else:
array_length = self._uint32_unpack(self._buf, self._pos - UINT32_SIZE)[0]
child_type: SignatureType = type_.children[0]
child_type = type_._child_0
token_as_int = child_type.token_as_int
if token_as_int in {
@ -631,9 +631,8 @@ class Unmarshaller:
result_dict: dict[Any, Any] = {}
key: str | int
beginning_pos = self._pos
children = child_type.children
child_0 = children[0]
child_1 = children[1]
child_0 = child_type._child_0
child_1 = child_type._child_1
child_0_token_as_int = child_0.token_as_int
child_1_token_as_int = child_1.token_as_int
# Strings with variant values are the most common case

View File

@ -9,6 +9,8 @@ cdef class SignatureType:
cdef public unsigned int token_as_int
cdef public list children
cdef str _signature
cdef public SignatureType _child_0
cdef public SignatureType _child_1
cdef class SignatureTree:

View File

@ -21,13 +21,22 @@ class SignatureType:
"""
_tokens = "ybnqiuxtdsogavh({"
__slots__ = ("_signature", "children", "token", "token_as_int")
__slots__ = (
"_child_0",
"_child_1",
"_signature",
"children",
"token",
"token_as_int",
)
def __init__(self, token: str) -> None:
"""Init a new SignatureType."""
self.token: str = token
self.token_as_int = ord(token)
self.children: list[SignatureType] = []
self._child_0: Optional[SignatureType] = None
self._child_1: Optional[SignatureType] = None
self._signature: Optional[str] = None
def __eq__(self, other: object) -> bool:
@ -60,6 +69,18 @@ class SignatureType:
self._signature = self._collapse()
return self._signature
def _add_child(self, child: "SignatureType") -> None:
"""Add a child type to this type.
:param child: The child type to add.
:type child: :class:`SignatureType`
"""
if self._child_0 is None:
self._child_0 = child
elif self._child_1 is None:
self._child_1 = child
self.children.append(child)
@staticmethod
def _parse_next(signature: str) -> tuple["SignatureType", str]:
if not signature:
@ -76,7 +97,7 @@ class SignatureType:
(child, signature) = SignatureType._parse_next(signature[1:])
if not child:
raise InvalidSignatureError("missing type for array")
self.children.append(child)
self._add_child(child)
return (self, signature)
if token == "(":
self = SignatureType("(")
@ -85,7 +106,7 @@ class SignatureType:
(child, signature) = SignatureType._parse_next(signature)
if not signature:
raise InvalidSignatureError('missing closing ")" for struct')
self.children.append(child)
self._add_child(child)
if signature[0] == ")":
return (self, signature[1:])
elif token == "{":
@ -94,13 +115,13 @@ class SignatureType:
(key_child, signature) = SignatureType._parse_next(signature)
if not key_child or len(key_child.children):
raise InvalidSignatureError("expected a simple type for dict entry key")
self.children.append(key_child)
self._add_child(key_child)
(value_child, signature) = SignatureType._parse_next(signature)
if not value_child:
raise InvalidSignatureError("expected a value for dict entry")
if not signature or signature[0] != "}":
raise InvalidSignatureError('missing closing "}" for dict entry')
self.children.append(value_child)
self._add_child(value_child)
return (self, signature[1:])
# basic type

View File

@ -23,6 +23,15 @@ def test_multiple_simple():
assert_simple_type("s", tree.types[i])
def test_children():
tree = SignatureTree("ss")
assert len(tree.types) == 2
parent = tree.types[0]
assert parent.token == "s"
assert parent.signature == "s"
assert len(parent.children) == 0
def test_array():
tree = SignatureTree("as")
assert len(tree.types) == 1
@ -31,6 +40,11 @@ def test_array():
assert child.token == "a"
assert len(child.children) == 1
assert_simple_type("s", child.children[0])
assert child.children[0].token == "s"
assert child._child_0.signature == "s"
assert child._child_1 is None
with pytest.raises(AttributeError):
_ = child._child_1.signature
def test_array_multiple():
@ -67,6 +81,8 @@ def test_simple_struct():
assert len(child.children) == 3
for i in range(3):
assert_simple_type("s", child.children[i])
assert child._child_0.signature == "s"
assert child._child_1.signature == "s"
def test_nested_struct():