add more methods

This commit is contained in:
S Groesz 2020-10-06 23:30:52 +00:00
parent 691069b307
commit f6d150545c
2 changed files with 167 additions and 23 deletions

View File

@ -1 +1 @@
from .main import Bits from .main import Bits, Bytes

View File

@ -1,36 +1,129 @@
"""The Bits class simplifies bit level operations.
(c) 2020 S Groesz
"""
class Bits: class Bits(int):
def __init__(self, data=None):
if data is None: def __init__(self, byte):
self.__raw = b'' self.__setvalue(byte)
else:
self.__raw = bytes(data)
def __bytes__(self): def __bytes__(self):
return self.__raw return bytes([self.__value])
def __int__(self): def __int__(self):
#return int.from_bytes(bytes(self), "big") # alternative Py > 3.1 return self.__value
i = 0
for b in bytes(self):
i = i * 256 + int(b) # Python 2: int(b) -> ord(b)
return i
def __hash__(self):
return hash(bytes(self))
def __repr__(self): def __repr__(self):
return (f'{self.__class__.__name__}({bytes(self)})') ret = f'{self.__class__.__module__}.{self.__class__.__name__}'
#return "{:08b}".format(int(self)) 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):
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): def __eq__(self, compare):
return hash(self) == hash(compare) return int(self) == int(compare)
def __ne__(self, compare): def __ne__(self, compare):
return hash(self) != hash(compare) return int(self) != int(compare)
def __lt__(self, compare): def __lt__(self, compare):
return int(self) < int(compare) return int(self) < int(compare)
@ -44,3 +137,54 @@ class Bits:
def __ge__(self, compare): def __ge__(self, compare):
return int(self) >= int(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)