def deserialize(cls: Type[V], stream: BinaryIO, scope: int) -> V: if scope < 1: raise Exception("cannot have empty scope for bitlist, need at least a delimiting bit") if scope > cls.max_byte_length(): raise Exception(f"scope is too large: {scope}, max bitlist byte length is: {cls.max_byte_length()}") chunks: PyList[Node] = [] bytelen = scope - 1 # excluding the last byte (which contains the delimiting bit) while scope > 32: chunks.append(RootNode(Root(stream.read(32)))) scope -= 32 # scope is [1, 32] here last_chunk_part = stream.read(scope) last_byte = int(last_chunk_part[scope-1]) if last_byte == 0: raise Exception("last byte must not be 0: bitlist requires delimiting bit") last_byte_bitlen = last_byte.bit_length() - 1 # excluding the delimiting bit bitlen = bytelen * 8 + last_byte_bitlen if bitlen % 256 != 0: last_chunk = last_chunk_part[:scope-1] +\ (last_byte ^ (1 << last_byte_bitlen)).to_bytes(length=1, byteorder='little') last_chunk += b"\x00" * (32 - len(last_chunk)) chunks.append(RootNode(Root(last_chunk))) if bitlen > cls.limit(): raise Exception(f"bitlist too long: {bitlen}, delimiting bit is over limit ({cls.limit()})") contents = subtree_fill_to_contents(chunks, cls.contents_depth()) backing = PairNode(contents, uint256(bitlen).get_backing()) return cast(Bitlist, cls.view_from_backing(backing))
def get_backing(self) -> Node: if len(self) == 32: # super common case, optimize for it return RootNode(Root(self)) elif len(self) < 32: return RootNode(Root(self + b"\x00" * (32 - len(self)))) else: return subtree_fill_to_contents(pack_bytes_to_chunks(self), self.__class__.tree_depth())
def pack_bytes_to_chunks(bytez: bytes) -> PyList[Node]: full_chunks_byte_len = (len(bytez) >> 5) << 5 out: PyList[Node] = [ RootNode(Root(bytez[i:i + 32])) for i in range(0, full_chunks_byte_len, 32) ] if len(bytez) != full_chunks_byte_len: out.append( RootNode( Root(bytez[full_chunks_byte_len:] + (b"\x00" * (32 - (len(bytez) - full_chunks_byte_len)))))) return out
def _new_chunk_with_bit(chunk: Node, i: int, v: boolean) -> Node: new_chunk_root = bytearray(bytes(chunk.root)) # mutable copy if v: new_chunk_root[(i & 0xff) >> 3] |= 1 << (i & 0x7) else: new_chunk_root[(i & 0xff) >> 3] &= (~(1 << (i & 0x7))) & 0xff return RootNode(Root(new_chunk_root))
def __iter__(self): self.i = 0 self.j = self.per_node self.rootIndex = 0 self.currentRoot = RootNode(ZERO_ROOT) self.stack = [None] * self.depth return self
def deserialize(cls: Type[V], stream: BinaryIO, scope: int) -> V: if scope != cls.type_byte_length(): raise Exception(f"scope is invalid: {scope}, bitvector byte length is: {cls.type_byte_length()}") chunks: PyList[Node] = [] bytelen = scope - 1 # excluding the last byte while scope > 32: chunks.append(RootNode(Root(stream.read(32)))) scope -= 32 # scope is [1, 32] here last_chunk_part = stream.read(scope) last_byte = int(last_chunk_part[scope-1]) bitlen = bytelen * 8 + last_byte.bit_length() if bitlen > cls.vector_length(): raise Exception(f"bitvector too long: {bitlen}, last byte has bits over bit length ({cls.vector_length()})") last_chunk = last_chunk_part + (b"\x00" * (32 - len(last_chunk_part))) chunks.append(RootNode(Root(last_chunk))) backing = subtree_fill_to_contents(chunks, cls.tree_depth()) return cast(Bitvector, cls.view_from_backing(backing))
def pack_ints_to_chunks(items: Iterable[int], items_per_chunk: int) -> PyList[Node]: item_byte_len = 32 // items_per_chunk return [ RootNode( Root(b"".join( v.to_bytes(length=item_byte_len, byteorder='little') for v in chunk_elems))) for chunk_elems in grouper(items, items_per_chunk, fillvalue=0) ]
def __init__(self, anchor: Node, depth: int, length: int): self.anchor = anchor self.depth = depth self.length = length self.i = 0 self.currentRoot = RootNode(ZERO_ROOT) self.stack = [None] * depth limit = 1 << depth if limit < length: raise Exception(f"cannot handle iterate length {length} bottom nodes " f"in subtree of depth {depth} deep (limit {limit} nodes)")
def __init__(self, anchor: Node, depth: int, length: int, elem_type: Type[BasicView]): self.anchor = anchor self.depth = depth self.length = length self.i = 0 self.rootIndex = 0 self.currentRoot = RootNode(ZERO_ROOT) self.stack = [None] * depth self.elem_type = elem_type self.per_node = 32 // elem_type.type_byte_length() self.j = self.per_node limit = (1 << depth) * self.per_node if limit < length: raise Exception(f"cannot handle iterate length {length} bottom subviews ({self.per_node} per node) " f"in subtree of depth {depth} deep (limit {limit} subviews)")
def pack_byte_ints_to_chunks(items: Iterable[int]) -> PyList[Node]: return [ RootNode(Root(b"".join(map(byte_int_to_byte, chunk_bytes)))) for chunk_bytes in grouper(items, 32, fillvalue=0) ]
def get_backing(self) -> Node: bytez = self.encode_bytes() return RootNode(Root(bytez + b"\x00" * (32 - len(bytez))))
def backing_from_base(self, base: Node, i: int) -> Node: section_bytez = self.encode_bytes() chunk_bytez = base.root[:len(section_bytez) * i] + section_bytez + base.root[ len(section_bytez) * (i + 1):] return RootNode(Root(chunk_bytez))