Example #1
0
 def serialize(self, stream: BinaryIO) -> int:
     backing = self.get_backing()
     bitlen = self.length()
     chunk_count = (bitlen + 255) // 256  # excludes delimit bit, this is the backing, not the serialized form
     byte_len = (bitlen + 7) // 8
     tree_depth = self.tree_depth()
     full_chunks_count = max(0, chunk_count - 1)
     for chunk_index in range(full_chunks_count):
         chunk = backing.getter(to_gindex(chunk_index, tree_depth))
         stream.write(chunk.root)
     if chunk_count > 0:
         last_chunk = backing.getter(to_gindex(chunk_count - 1, tree_depth))
         # write the last chunk, may not be a full chunk
         last_chunk_bytes_count = byte_len - (full_chunks_count * 32)
         bytez = last_chunk.root[:last_chunk_bytes_count]
         # add in delimiting bit
         if bitlen % 8 == 0:
             bytez += b"\x01"
         else:
             bytez = bytez[:len(bytez) - 1] +\
                     (bytez[len(bytez) - 1] ^ (1 << (bitlen % 8))).to_bytes(length=1, byteorder='little')
         stream.write(bytez)
     else:
         stream.write(b"\x01")  # empty bitlist still has a delimiting bit
     return (bitlen + 7 + 1) // 8  # includes delimit bit in length computation
Example #2
0
 def set(self, i: int, v: boolean) -> None:
     ll = self.length()
     if i >= ll:
         raise NavigationError(f"cannot set bit {i} in bits of length {ll}")
     chunk_i = i >> 8
     chunk_setter_link: Link = self.get_backing().setter(to_gindex(chunk_i, self.__class__.tree_depth()))
     chunk = self.get_backing().getter(to_gindex(chunk_i, self.__class__.tree_depth()))
     new_chunk = _new_chunk_with_bit(chunk, i & 0xff, v)
     self.set_backing(chunk_setter_link(new_chunk))
Example #3
0
 def get(self, i: int) -> View:
     elem_type: Type[View] = self.item_elem_cls(i)
     # basic types are more complicated: we operate on subsections packed into a bottom chunk
     if self.is_packed():
         elems_per_chunk = 32 // elem_type.type_byte_length()
         chunk_i = i // elems_per_chunk
         chunk = self.get_backing().getter(to_gindex(chunk_i, self.tree_depth()))
         return cast(Type[BasicView], elem_type).basic_view_from_backing(chunk, i % elems_per_chunk)
     else:
         return elem_type.view_from_backing(
             self.get_backing().getter(to_gindex(i, self.tree_depth())), lambda v: self.set(i, v))
Example #4
0
 def key_to_static_gindex(cls, key: Any) -> Gindex:
     depth = cls.tree_depth()
     byte_limit = cls.limit()
     if key < 0 or key >= byte_limit:
         raise KeyError
     chunk_i = key // 32
     return to_gindex(chunk_i, depth)
Example #5
0
 def key_to_static_gindex(cls, key: Any) -> Gindex:
     fields = cls.fields()
     try:
         field_index = list(fields.keys()).index(key)
     except ValueError:  # list.index raises ValueError if the element (a key here) is missing
         raise KeyError
     return to_gindex(field_index, cls.tree_depth())
Example #6
0
 def key_to_static_gindex(cls, key: Any) -> Gindex:
     depth = cls.tree_depth()
     bit_len = cls.vector_length()
     if key < 0 or key >= bit_len:
         raise KeyError
     chunk_i = key // 256
     return to_gindex(chunk_i, depth)
Example #7
0
 def serialize(self, stream: BinaryIO) -> int:
     backing = self.get_backing()
     bitlen = self.length()
     chunk_count = (bitlen + 255) // 256  # excludes delimit bit, this is the backing, not the serialized form
     byte_len = (bitlen + 7) // 8
     tree_depth = self.tree_depth()
     full_chunks_count = max(0, chunk_count - 1)
     for chunk_index in range(full_chunks_count):
         chunk: Node = backing.getter(to_gindex(chunk_index, tree_depth))
         stream.write(chunk.root)
     if chunk_count > 0:
         last_chunk = backing.getter(to_gindex(chunk_count - 1, tree_depth))
         # write the last chunk, may not be a full chunk
         last_chunk_bytes_count = byte_len - (full_chunks_count * 32)
         stream.write(last_chunk.root[:last_chunk_bytes_count])
     return byte_len
Example #8
0
    def pop(self):
        ll = self.length()
        if ll == 0:
            raise Exception("list is empty, cannot pop")
        i = ll - 1
        chunk_i = i // 256
        target: Gindex = to_gindex(chunk_i, self.__class__.tree_depth())
        if i & 0xff == 0:
            set_last = self.get_backing().setter(target)
            next_backing = set_last(zero_node(0))
        else:
            set_last = self.get_backing().setter(target)
            chunk = self.get_backing().getter(target)
            next_backing = set_last(_new_chunk_with_bit(chunk, ll & 0xff, boolean(False)))

        # if possible, summarize
        can_summarize = (target & 1) == 0
        if can_summarize:
            # summarize to the highest node possible.
            # I.e. the resulting target must be a right-hand, unless it's the only content node.
            while (target & 1) == 0 and target != 0b10:
                target >>= 1
            summary_fn = next_backing.summarize_into(target)
            next_backing = summary_fn()

        set_length = next_backing.rebind_right
        new_length = uint256(ll - 1).get_backing()
        next_backing = set_length(new_length)
        self.set_backing(next_backing)
Example #9
0
    def pop(self):
        ll = self.length()
        if ll == 0:
            raise Exception("list is empty, cannot pop")
        i = ll - 1
        target: Gindex
        can_summarize: bool
        if self.__class__.is_packed():
            next_backing = self.get_backing()
            elem_type: Type[View] = self.__class__.element_cls()
            if isinstance(elem_type, BasicTypeDef):
                elems_per_chunk = 32 // elem_type.type_byte_length()
                chunk_i = i // elems_per_chunk
                target = to_gindex(chunk_i, self.__class__.tree_depth())
                if i % elems_per_chunk == 0:
                    chunk = zero_node(0)
                else:
                    chunk = next_backing.getter(target)
                set_last = next_backing.setter(target)
                chunk = cast(BasicView,
                             elem_type.default(None)).backing_from_base(
                                 chunk, i % elems_per_chunk)
                next_backing = set_last(chunk)

                can_summarize = (target & 1) == 0 and i % elems_per_chunk == 0
            else:
                raise Exception(
                    "cannot pop a packed element that is not a basic type")
        else:
            target = to_gindex(i, self.__class__.tree_depth())
            set_last = self.get_backing().setter(target)
            next_backing = set_last(zero_node(0))
            can_summarize = (target & 1) == 0

        # if possible, summarize
        if can_summarize:
            # summarize to the highest node possible.
            # I.e. the resulting target must be a right-hand, unless it's the only content node.
            while (target & 1) == 0 and target != 0b10:
                target >>= 1
            summary_fn = next_backing.summarize_into(target)
            next_backing = summary_fn()

        set_length = next_backing.rebind_right
        new_length = uint256(ll - 1).get_backing()
        next_backing = set_length(new_length)
        self.set_backing(next_backing)
Example #10
0
 def get(self, i: int) -> boolean:
     ll = self.length()
     if i >= ll:
         raise NavigationError(f"cannot get bit {i} in bits of length {ll}")
     chunk_i = i >> 8
     chunk = self.get_backing().getter(to_gindex(chunk_i, self.__class__.tree_depth()))
     chunk_byte = chunk.root[(i & 0xff) >> 3]
     return boolean((chunk_byte >> (i & 0x7)) & 1)
Example #11
0
 def view_from_backing(cls: Type[BV], node: Node, hook: Optional[ViewHook] = None) -> BV:
     depth = cls.tree_depth()
     byte_len = cls.vector_length()
     if depth == 0:
         return cls.decode_bytes(node.merkle_root()[:byte_len])
     else:
         chunk_count = (byte_len + 31) // 32
         chunks = [node.getter(to_gindex(i, depth)) for i in range(chunk_count)]
         bytez = b"".join(ch.merkle_root() for ch in chunks)[:byte_len]
         return cls.decode_bytes(bytez)
Example #12
0
    def key_to_static_gindex(cls, key: Any) -> Gindex:
        if key < 0:
            raise KeyError

        if cls.is_packed():
            elems_per_chunk = 32 // cls.element_cls().type_byte_length()
            chunk_i = key // elems_per_chunk
        else:
            chunk_i = key

        return to_gindex(chunk_i, cls.tree_depth())
Example #13
0
 def view_from_backing(cls: Type[BL], node: Node, hook: Optional[ViewHook] = None) -> BL:
     contents_depth = cls.contents_depth()
     contents_node = node.get_left()
     length = uint256.view_from_backing(node.get_right())
     if length > cls.limit():
         raise Exception("ByteList backing declared length exceeds limit")
     if contents_depth == 0:
         return cls.decode_bytes(contents_node.root[:length])
     else:
         chunk_count = (length + 31) // 32
         chunks = [contents_node.getter(to_gindex(i, contents_depth)) for i in range(chunk_count)]
         bytez = b"".join(ch.root for ch in chunks)[:length]
         return cls.decode_bytes(bytez)
Example #14
0
 def set(self, i: int, v: View) -> None:
     elem_type: Type[View] = self.item_elem_cls(i)
     # if not the right type, try to coerce it
     if not isinstance(v, elem_type):
         v = elem_type.coerce_view(v)
     if self.is_packed():
         # basic types are more complicated: we operate on a subsection of a bottom chunk
         if isinstance(v, BasicView):
             elems_per_chunk = 32 // v.type_byte_length()
             chunk_i = i // elems_per_chunk
             target = to_gindex(chunk_i, self.tree_depth())
             chunk_setter_link: Link = self.get_backing().setter(target)
             chunk = self.get_backing().getter(target)
             new_chunk = v.backing_from_base(chunk, i % elems_per_chunk)
             self.set_backing(chunk_setter_link(new_chunk))
         else:
             raise Exception(
                 "cannot pack subtree elements that are not basic types")
     else:
         setter_link: Link = self.get_backing().setter(
             to_gindex(i, self.tree_depth()))
         self.set_backing(setter_link(v.get_backing()))
Example #15
0
    def append(self, v: View):
        ll = self.length()
        if ll >= self.__class__.limit():
            raise Exception("list is maximum capacity, cannot append")
        i = ll
        elem_type: Type[View] = self.__class__.element_cls()
        if not isinstance(v, elem_type):
            v = elem_type.coerce_view(v)
        if self.__class__.is_packed():
            next_backing = self.get_backing()
            if isinstance(elem_type, BasicTypeDef):
                if not isinstance(v, BasicView):
                    raise Exception("input element is not a basic view")
                basic_v: BasicView = v
                elems_per_chunk = 32 // elem_type.type_byte_length()
                chunk_i = i // elems_per_chunk
                target: Gindex = to_gindex(chunk_i,
                                           self.__class__.tree_depth())
                if i % elems_per_chunk == 0:
                    set_last = next_backing.setter(target, expand=True)
                    chunk = zero_node(0)
                else:
                    set_last = next_backing.setter(target)
                    chunk = next_backing.getter(target)
                chunk = basic_v.backing_from_base(chunk, i % elems_per_chunk)
                next_backing = set_last(chunk)
            else:
                raise Exception(
                    "cannot append a packed element that is not a basic type")
        else:
            target: Gindex = to_gindex(i, self.__class__.tree_depth())
            set_last = self.get_backing().setter(target, expand=True)
            next_backing = set_last(v.get_backing())

        set_length = next_backing.rebind_right
        new_length = uint256(ll + 1).get_backing()
        next_backing = set_length(new_length)
        self.set_backing(next_backing)
Example #16
0
 def append(self, v: boolean):
     ll = self.length()
     if ll >= self.__class__.limit():
         raise Exception("list is maximum capacity, cannot append")
     i = ll
     chunk_i = i // 256
     target: Gindex = to_gindex(chunk_i, self.__class__.tree_depth())
     if i & 0xff == 0:
         set_last = self.get_backing().setter(target, expand=True)
         next_backing = set_last(_new_chunk_with_bit(zero_node(0), 0, v))
     else:
         set_last = self.get_backing().setter(target)
         chunk = self.get_backing().getter(target)
         next_backing = set_last(_new_chunk_with_bit(chunk, i & 0xff, v))
     set_length = next_backing.rebind_right
     new_length = uint256(ll + 1).get_backing()
     next_backing = set_length(new_length)
     self.set_backing(next_backing)