diff --git a/CHANGES.rst b/CHANGES.rst index 54261a6df..69995a073 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -33,6 +33,7 @@ The ASDF Standard is at v1.6.0 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Add support for python 3.12 [#1641] +- Move IntegerType to converter and drop cache of converted values. [#1527] 2.15.1 (2023-08-07) ------------------- diff --git a/asdf/_tests/tags/core/tests/test_integer.py b/asdf/_tests/tags/core/tests/test_integer.py index 2b3528613..6e86de88e 100644 --- a/asdf/_tests/tags/core/tests/test_integer.py +++ b/asdf/_tests/tags/core/tests/test_integer.py @@ -58,26 +58,6 @@ def test_integer_storage(tmpdir, inline): assert rf.tree["integer"]["string"] == str(value) -def test_integer_storage_duplication(tmpdir): - tmpfile = str(tmpdir.join("integer.asdf")) - - random.seed(0) - value = random.getrandbits(1000) - tree = {"integer1": IntegerType(value), "integer2": IntegerType(value)} - - with asdf.AsdfFile(tree) as af: - af.write_to(tmpfile) - - with asdf.open(tmpfile, _force_raw_types=True) as rf: - assert len(rf._blocks.blocks) == 1 - assert rf.tree["integer1"]["words"]["source"] == 0 - assert rf.tree["integer2"]["words"]["source"] == 0 - - with asdf.open(tmpfile) as aa: - assert aa.tree["integer1"] == value - assert aa.tree["integer2"] == value - - def test_integer_conversion(): random.seed(0) value = random.getrandbits(1000) diff --git a/asdf/core/_converters/integer.py b/asdf/core/_converters/integer.py new file mode 100644 index 000000000..61ddf882d --- /dev/null +++ b/asdf/core/_converters/integer.py @@ -0,0 +1,45 @@ +import numpy as np + +from asdf.extension import Converter + + +class IntegerConverter(Converter): + tags = [ + "tag:stsci.edu:asdf/core/integer-1.0.0", + "tag:stsci.edu:asdf/core/integer-1.1.0", + ] + + types = ["asdf.tags.core.integer.IntegerType"] + + def to_yaml_tree(self, obj, tag, ctx): + abs_value = int(np.abs(obj._value)) + + # pack integer value into 32-bit words + words = [] + value = abs_value + while value > 0: + words.append(value & 0xFFFFFFFF) + value >>= 32 + + array = np.array(words, dtype=np.uint32) + + tree = {} + ctx.set_array_storage(array, obj._storage) + tree["words"] = array + tree["sign"] = obj._sign + tree["string"] = str(int(obj._value)) + + return tree + + def from_yaml_tree(self, node, tag, ctx): + from asdf.tags.core.integer import IntegerType + + value = 0 + for x in node["words"][::-1]: + value <<= 32 + value |= int(x) + + if node["sign"] == "-": + value = -value + + return IntegerType(value) diff --git a/asdf/core/_extensions.py b/asdf/core/_extensions.py index fb2a9d982..059ea4e5a 100644 --- a/asdf/core/_extensions.py +++ b/asdf/core/_extensions.py @@ -3,6 +3,7 @@ from ._converters.complex import ComplexConverter from ._converters.constant import ConstantConverter from ._converters.external_reference import ExternalArrayReferenceConverter +from ._converters.integer import IntegerConverter from ._converters.ndarray import NDArrayConverter from ._converters.reference import ReferenceConverter from ._converters.tree import ( @@ -21,6 +22,7 @@ AsdfObjectConverter(), ExtensionMetadataConverter(), HistoryEntryConverter(), + IntegerConverter(), SoftwareConverter(), SubclassMetadataConverter(), ReferenceConverter(), diff --git a/asdf/tags/core/integer.py b/asdf/tags/core/integer.py index 898ac3ad6..70056c109 100644 --- a/asdf/tags/core/integer.py +++ b/asdf/tags/core/integer.py @@ -1,11 +1,7 @@ from numbers import Integral -import numpy as np -from asdf import _types - - -class IntegerType(_types._AsdfType): +class IntegerType: """ Enables the storage of arbitrarily large integer values @@ -42,12 +38,6 @@ class IntegerType(_types._AsdfType): ... assert aa['largeval'] == largeval """ - name = "core/integer" - version = "1.0.0" - supported_versions = {"1.0.0", "1.1.0"} - - _value_cache = {} - def __init__(self, value, storage_type="internal"): if storage_type not in ["internal", "inline"]: msg = f"storage_type '{storage_type}' is not a recognized storage type" @@ -56,45 +46,6 @@ def __init__(self, value, storage_type="internal"): self._sign = "-" if value < 0 else "+" self._storage = storage_type - @classmethod - def to_tree(cls, node, ctx): - abs_value = int(np.abs(node._value)) - - # If the same value has already been stored, reuse the array - if abs_value in cls._value_cache: - array = cls._value_cache[abs_value] - else: - # pack integer value into 32-bit words - words = [] - value = abs_value - while value > 0: - words.append(value & 0xFFFFFFFF) - value >>= 32 - - array = np.array(words, dtype=np.uint32) - if node._storage == "internal": - cls._value_cache[abs_value] = array - - tree = {} - ctx.set_array_storage(array, node._storage) - tree["words"] = array - tree["sign"] = node._sign - tree["string"] = str(int(node._value)) - - return tree - - @classmethod - def from_tree(cls, tree, ctx): - value = 0 - for x in tree["words"][::-1]: - value <<= 32 - value |= int(x) - - if tree["sign"] == "-": - value = -value - - return cls(value) - def __int__(self): return int(self._value)