add more methods
This commit is contained in:
parent
691069b307
commit
f6d150545c
|
@ -1 +1 @@
|
|||
from .main import Bits
|
||||
from .main import Bits, Bytes
|
||||
|
|
188
bits/main.py
188
bits/main.py
|
@ -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
|
||||
|
||||
def __hash__(self):
|
||||
return hash(bytes(self))
|
||||
return self.__value
|
||||
|
||||
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 __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):
|
||||
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:
|
|||
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)
|
||||
|
||||
|
|
Loading…
Reference in New Issue