From e8772e9931d05f3cd903baf83f432957cdf7eea5 Mon Sep 17 00:00:00 2001 From: S Groesz Date: Tue, 13 Oct 2020 06:32:50 +0000 Subject: [PATCH] update Bits; tests passing --- Makefile | 1 + bits/main.py | 181 +++++++++++++++++++++++++++++++++++++++++++-- tests/test_bits.py | 44 ++++++++++- 3 files changed, 217 insertions(+), 9 deletions(-) diff --git a/Makefile b/Makefile index c011131..26a6c9f 100644 --- a/Makefile +++ b/Makefile @@ -2,6 +2,7 @@ init: pip install -r requirements.txt test: + python -m unittest -v tests/test_bit.py python -m unittest -v tests/test_bits.py .PHONY: init test diff --git a/bits/main.py b/bits/main.py index 9f6e92d..7a919fb 100644 --- a/bits/main.py +++ b/bits/main.py @@ -72,8 +72,9 @@ class Bits: Provide bit operation helpers. """ - def __init__(self, var=0): + def __init__(self, var=0, msb_last=False): self.__value = 0 + self.__r_to_l = bool(msb_last) self.__setvalue(var) def __bytes__(self): @@ -86,9 +87,7 @@ class Bits: return self.__value def __repr__(self): - ret = f'{self.__class__.__module__}.{self.__class__.__name__}' - ret += f'({bytes(self)})' - return ret + return f'{self.__class__.__name__}({self.__value!r})' def __str__(self): return self.bin() @@ -127,15 +126,165 @@ class Bits: # we'll take the easy way for now l = self.list() # str->int->bool->int : accept bool, str, int, return either "0" or "1" - l[index] = bool(int(value)) + l[index] = Bit(value) self.__setvalue(l) def __get__(self, instance, owner): return self.bin() + def __add__(self, other): + return Bits(int(self) + int(Bits(other))) + + def __sub__(self, other): + return Bits(int(self) - int(Bits(other))) + + def __mul__(self, other): + return Bits(int(self) * int(Bits(other))) + + def __matmul__(self, other): + return NotImplemented + + def __truediv__(self, other): + return NotImplemented + + def __floordiv__(self, other): + return Bits(int(self) // int(Bits(other))) + + def __mod__(self, other): + return Bits(int(self) % int(Bits(other))) + + def __divmod__(self, other): + return (self // Bits(other), self % Bits(other)) + + def __pow__(self, other, mod=None): + ret = Bits(0) + if mod is None: + ret = Bits(int(self) ** int(Bits(other))) + else: + ret = Bits(int(self) ** int(Bits(other)) % int(Bits(mod))) + return ret + + def __lshift__(self, other): + return Bits(int(self) << int(Bits(other))) + + def __rshift__(self, other): + return Bits(int(self) >> int(Bits(other))) + + def __and__(self, other): + return Bits(int(self) & int(Bits(other))) + + def __xor__(self, other): + return Bits(int(self) ^ int(Bits(other))) + + def __or__(self, other): + return Bits(int(self) | int(Bits(other))) + + def __radd__(self, other): + return Bits(other) + self + + def __rsub__(self, other): + return Bits(other) - self + + def __rmul__(self, other): + return Bits(other) * self + + def __rmatmul__(self, other): + return NotImplemented + + def __rtruediv__(self, other): + return NotImplemented + + def __rfloordiv__(self, other): + return Bits(other) // self + + def __rmod__(self, other): + return Bits(other) % self + + def __rdivmod__(self, other): + return (Bits(other) // self, Bits(other) % self) + + def __rpow__(self, other, mod=None): + ret = Bits(0) + if mod is None: + ret = Bits(other) ** self + else: + ret = Bits(other) ** self % Bits(mod) + return ret + + def __rlshift__(self, other): + return Bits(other) << self + + def __rrshift__(self, other): + return Bits(other) >> self + + def __rand__(self, other): + return Bits(other) & self + + def __rxor__(self, other): + return Bits(other) ^ self + + def __ror__(self, other): + return Bits(other) | self + + def __iadd__(self, other): + self = self + Bits(other) + return self + + def __isub__(self, other): + self = self - Bits(other) + return self + + def __imul__(self, other): + self = self * Bits(other) + return self + + def __imatmul__(self, other): + return NotImplemented + + def __itruediv__(self, other): + return NotImplemented + + def __ifloordiv__(self, other): + self = self // Bits(other) + return self + + def __imod__(self, other): + self = self % Bits(other) + return self + + def __ipow__(self, other): + self = self ** Bits(other) + return self + + def __ilshift__(self, other): + self = self << Bits(other) + return self + + def __irshift__(self, other): + self = self >> Bits(other) + return self + + def __iand__(self, other): + self = self & Bits(other) + return self + + def __ixor__(self, other): + self = self ^ Bits(other) + return self + + def __ior__(self, other): + self = self | Bits(other) + return self + + def __contains__(self, item): + val = Bits(item) & self + return val == Bits(item) + def __setvalue(self, var): self.__value = 0 - if isinstance(var, int): + if isinstance(var, Bits): + self.__value = int(var) + elif isinstance(var, int): if var < 0 or var > 255: raise ValueError("Integer must be between 0 and 255") self.__value = var @@ -166,6 +315,14 @@ class Bits: def chr(self): return chr(self.__value) + @property + def int(self): + return int(self) + + @int.setter + def int(self, value): + self.__setvalue(value) + @property def byte(self): return bytes(self) @@ -185,11 +342,19 @@ class Bits: def nibble(self): return [self.bin()[:4], self.bin()[4:]] + @property + def rtl(self): + return self.__r_to_l + + @rtl.setter + def rtl(self, msb_last): + self.__r_to_l = bool(msb_last) + def list(self, pad=True, reverse=False): ret = [] bits = self.bin(pad=pad, reverse=reverse) - for bit in bits: - ret.append(bool(int(bit))) + for b in bits: + ret.append(Bit(b)) return ret diff --git a/tests/test_bits.py b/tests/test_bits.py index 91b57d1..daefd2e 100644 --- a/tests/test_bits.py +++ b/tests/test_bits.py @@ -90,7 +90,7 @@ class TestBits(TestCase): with self.subTest("testcase[\"int\"]: " + str(testcase["int"]) \ + " [without leading zeros]"): self.assertEqual(testcase["bitsObject"].bin(pad=False), - testcase["bits"].strip("0")) + testcase["bits"].lstrip("0")) def test_reverse(self): """ @@ -102,6 +102,48 @@ class TestBits(TestCase): self.assertEqual(testcase["bitsObject"].bin(), testcase["bits"][::-1]) + def test_membership_operators(self): + """ + Test the membership operator (x in y) + """ + with self.subTest("should all be True"): + for i in range(1, 256): + self.assertTrue(i in Bits(255), f"Bits({i}) in Bits(255) fail") + with self.subTest("should all be False"): + for i in range(1, 256): + self.assertFalse(i in Bits(0), f"Bits({i}) in Bits(0) fail") + with self.subTest("should pass"): + self.assertIn(1, Bits("00100111"), "1 in Bits(39)") + self.assertIn(2, Bits(39), "2 in Bits(39)") + self.assertIn(4, Bits(39), "4 in Bits(39)") + self.assertNotIn(8, Bits(39), "8 in Bits(39)") + self.assertNotIn(16, Bits(39), "16 in Bits(39)") + self.assertIn(32, Bits(39), "32 in Bits(39)") + self.assertNotIn(64, Bits(39), "64 in Bits(39)") + self.assertNotIn(128, Bits(39), "128 in Bits(39)") + + def test_binary_operations(self): + self.assertEqual((Bits("00000100") << 3), Bits("00100000"), + "Bits(4) << 3 == Bits(32)") + self.assertEqual((Bits("00100000") << 1), Bits("01000000"), + "Bits(32) << 1 == Bits(64)") + self.assertEqual((Bits(64) >> 2), Bits(16), + "Bits(64) >> 2 == Bits(16)") + self.assertEqual(( 2 << Bits(6)), Bits(128), + "2 << Bits(6) == Bits(128)") + self.assertEqual((Bits(255) & Bits(64)), Bits(64), + "Bits(255) and Bits(64) == Bits(64)") + self.assertNotEqual((Bits(32) & Bits(64)), Bits(64), + "Bits(32) and Bits(64) != Bits(64)") + self.assertEqual((Bits(2) | Bits(32)), 34, + "Bits(2) or Bits(32) == 34") + self.assertEqual((Bits(80) | Bits(64)), Bits(80), + "Bits(80) or Bits(64) == Bits(80)") + self.assertEqual((Bits(80) ^ Bits(64)), Bits(16), + "Bits(80) xor Bits(64) == Bits(16)") + self.assertEqual((Bits(80) & Bits(64)), Bits(64), + "Bits(80) and Bits(64) == Bits(64)") + def test_comparisons(self): """ Test the comparison operators