|
|
|
@ -1,36 +1,129 @@
@@ -1,36 +1,129 @@
|
|
|
|
|
"""The Bits class simplifies bit level operations. |
|
|
|
|
(c) 2020 S Groesz |
|
|
|
|
""" |
|
|
|
|
|
|
|
|
|
class Bits: |
|
|
|
|
def __init__(self, data=None): |
|
|
|
|
if data is None: |
|
|
|
|
self.__raw = b'' |
|
|
|
|
else: |
|
|
|
|
self.__raw = bytes(data) |
|
|
|
|
|
|
|
|
|
class Bits(int): |
|
|
|
|
|
|
|
|
|
def __init__(self, byte): |
|
|
|
|
self.__setvalue(byte) |
|
|
|
|
|
|
|
|
|
def __bytes__(self): |
|
|
|
|
return self.__raw |
|
|
|
|
return bytes([self.__value]) |
|
|
|
|
|
|
|
|
|
def __int__(self): |
|
|
|
|
#return int.from_bytes(bytes(self), "big") # alternative Py > 3.1 |
|
|
|
|
i = 0 |
|
|
|
|
for b in bytes(self): |
|
|
|
|
i = i * 256 + int(b) # Python 2: int(b) -> ord(b) |
|
|
|
|
return i |
|
|
|
|
return self.__value |
|
|
|
|
|
|
|
|
|
def __hash__(self): |
|
|
|
|
return hash(bytes(self)) |
|
|
|
|
def __repr__(self): |
|
|
|
|
ret = f'{self.__class__.__module__}.{self.__class__.__name__}' |
|
|
|
|
ret += f'({bytes(self)})' |
|
|
|
|
return ret |
|
|
|
|
|
|
|
|
|
def __str__(self): |
|
|
|
|
return self.bin() |
|
|
|
|
|
|
|
|
|
def __index__(self): |
|
|
|
|
return int(self) |
|
|
|
|
|
|
|
|
|
def __len__(self): |
|
|
|
|
return 8 |
|
|
|
|
|
|
|
|
|
def __getitem__(self, index): |
|
|
|
|
return bool(int(self.bin()[index])) #self.bool(key) |
|
|
|
|
|
|
|
|
|
def __setitem__(self, index, value): |
|
|
|
|
# we'll take the easy way for now |
|
|
|
|
s = list(self.bin()) |
|
|
|
|
# str->int->bool->int : accept bool, str, int, return either "0" or "1" |
|
|
|
|
s[index] = str(int(bool(int(value)))) |
|
|
|
|
self.__setvalue("".join(s)) |
|
|
|
|
|
|
|
|
|
def __get__(self, instance, owner): |
|
|
|
|
return self.bin() |
|
|
|
|
|
|
|
|
|
def __setvalue(self, value): |
|
|
|
|
self.__value = 0 |
|
|
|
|
if isinstance(value, int): |
|
|
|
|
if value < 0 or value > 255: |
|
|
|
|
raise ValueError("Integer must be between 0 and 255") |
|
|
|
|
self.__value = value |
|
|
|
|
elif (len(value) > 0) and (len(value) <=8): |
|
|
|
|
for bit in range(0, len(value)): |
|
|
|
|
self.__value += (int(bool(int(value[bit]))) * |
|
|
|
|
(2 ** (len(value) - 1 - bit))) |
|
|
|
|
else: |
|
|
|
|
raise TypeError("Expected object with len <= 8") |
|
|
|
|
|
|
|
|
|
def bin(self, pad=True): |
|
|
|
|
bitcount = self.__value.bit_length() |
|
|
|
|
if pad and ((bitcount % 8) > 0): |
|
|
|
|
ret = "0" * (8 - (bitcount % 8)) |
|
|
|
|
return ret + bin(self.__value)[2:] |
|
|
|
|
|
|
|
|
|
@property |
|
|
|
|
def chr(self): |
|
|
|
|
return chr(self.__value) |
|
|
|
|
|
|
|
|
|
@property |
|
|
|
|
def byte(self): |
|
|
|
|
return bytes(self) |
|
|
|
|
|
|
|
|
|
def reverse(self): |
|
|
|
|
self.__setvalue(self.bin()[::-1]) |
|
|
|
|
|
|
|
|
|
@property |
|
|
|
|
def msb(self): |
|
|
|
|
return self.bin()[0] |
|
|
|
|
|
|
|
|
|
@property |
|
|
|
|
def lsb(self): |
|
|
|
|
return self.bin()[7] |
|
|
|
|
|
|
|
|
|
@property |
|
|
|
|
def nibble(self): |
|
|
|
|
return [self.bin()[:4], self.bin()[4:]] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Bytes(bytearray): |
|
|
|
|
|
|
|
|
|
def __init__(self, b, *args, **kwargs): |
|
|
|
|
self.__raw = bytearray(b) |
|
|
|
|
|
|
|
|
|
def __bytes__(self): |
|
|
|
|
return bytes(self.__raw) |
|
|
|
|
|
|
|
|
|
def __int__(self): |
|
|
|
|
return self.int() |
|
|
|
|
|
|
|
|
|
def __repr__(self): |
|
|
|
|
return (f'{self.__class__.__name__}({bytes(self)})') |
|
|
|
|
#return "{:08b}".format(int(self)) |
|
|
|
|
ret = f'{self.__class__.__module__}.{self.__class__.__name__}' |
|
|
|
|
ret += f'({bytes(self)})' |
|
|
|
|
return ret |
|
|
|
|
|
|
|
|
|
def __index__(self): |
|
|
|
|
return self.int() |
|
|
|
|
|
|
|
|
|
def __getitem__(self, index): |
|
|
|
|
if not isinstance(index, int): |
|
|
|
|
raise TypeError |
|
|
|
|
return Bits(self.__raw[index]) |
|
|
|
|
|
|
|
|
|
def __setitem__(self, index, value): |
|
|
|
|
if not isinstance(index, int): |
|
|
|
|
raise TypeError |
|
|
|
|
self.__raw[index] = int(value) |
|
|
|
|
|
|
|
|
|
def __delitem__(self, index): |
|
|
|
|
del self.__raw[index] |
|
|
|
|
|
|
|
|
|
def __test_key(self, key): |
|
|
|
|
if not isinstance(key, int): |
|
|
|
|
raise TypeError |
|
|
|
|
if key >= len(self.__raw): |
|
|
|
|
raise IndexError |
|
|
|
|
return True |
|
|
|
|
|
|
|
|
|
def __eq__(self, compare): |
|
|
|
|
return hash(self) == hash(compare) |
|
|
|
|
return int(self) == int(compare) |
|
|
|
|
|
|
|
|
|
def __ne__(self, compare): |
|
|
|
|
return hash(self) != hash(compare) |
|
|
|
|
return int(self) != int(compare) |
|
|
|
|
|
|
|
|
|
def __lt__(self, compare): |
|
|
|
|
return int(self) < int(compare) |
|
|
|
@ -44,3 +137,54 @@ class Bits:
@@ -44,3 +137,54 @@ class Bits:
|
|
|
|
|
def __ge__(self, compare): |
|
|
|
|
return int(self) >= int(compare) |
|
|
|
|
|
|
|
|
|
def __hash__(self): |
|
|
|
|
return None |
|
|
|
|
|
|
|
|
|
def __bool__(self): |
|
|
|
|
return bool(int(self)) |
|
|
|
|
|
|
|
|
|
def __len__(self): |
|
|
|
|
return len(self.__raw) |
|
|
|
|
|
|
|
|
|
def __get__(self, instance, owner=None): |
|
|
|
|
return self.__raw |
|
|
|
|
|
|
|
|
|
def __str__(self): |
|
|
|
|
return self.bin() |
|
|
|
|
|
|
|
|
|
def int(self, _bytes=None, byteorder="big", signed=False): |
|
|
|
|
if _bytes is None: |
|
|
|
|
_bytes = bytes(self) |
|
|
|
|
return int.from_bytes(bytes=_bytes, byteorder=byteorder, |
|
|
|
|
signed=signed) |
|
|
|
|
|
|
|
|
|
def bin(self, i=None, pad=True): |
|
|
|
|
if i is None: |
|
|
|
|
i = self.int() |
|
|
|
|
bitcount = i.bit_length() |
|
|
|
|
ret = "" |
|
|
|
|
if pad and ((bitcount % 8) > 0): |
|
|
|
|
ret = "0" * (8 - (bitcount % 8)) |
|
|
|
|
chop = 2 |
|
|
|
|
if i < 0: |
|
|
|
|
# account for the sign character |
|
|
|
|
chop += 1 |
|
|
|
|
return ret + bin(i)[chop:] |
|
|
|
|
|
|
|
|
|
@property |
|
|
|
|
def bytes(self): |
|
|
|
|
return bytes(self) |
|
|
|
|
|
|
|
|
|
@property |
|
|
|
|
def bytearray(self): |
|
|
|
|
return bytearray(bytes(self)) |
|
|
|
|
|
|
|
|
|
def from_int(self, i, byteorder="big"): |
|
|
|
|
signed = False |
|
|
|
|
if i < 0: |
|
|
|
|
signed = True |
|
|
|
|
length = (len(self.bin(i=i, pad=True)) / 8) |
|
|
|
|
return i.to_bytes(length=length, |
|
|
|
|
byteorder=byteorder, |
|
|
|
|
signed=signed) |
|
|
|
|
|
|
|
|
|