Example #1
0
 def test_invalid_i(self):
     bitmap = Bitmap(size=10, value=10)
     with self.assertRaises(TypeError):
         _ = bitmap.get_bit(2.0)  # type: ignore
     with self.assertRaises(TypeError):
         bitmap.set_bit('0b0010')  # type: ignore
     with self.assertRaises(TypeError):
         bitmap.clear_bit([2])  # type: ignore
     # i < 0
     with self.assertRaises(ValueError):
         bitmap.flip_bit(-1)
     # i >= size
     with self.assertRaises(ValueError):
         _ = bitmap.get_bit(10)
Example #2
0
 def test_clear_bit(self):
     bitmap = Bitmap(value=10)
     bitmap.clear_bit(1)
     self.assertEqual(bitmap.get_bit(2), 0)
     self.assertEqual(bitmap.value, 8)
Example #3
0
class BitmapSet(abc.MutableSet):

    # ------- init methods -----------------------------------------------------

    def __init__(self, bounds: Bounds, elems: Optional[Elems] = None) -> None:
        self._validate_bounds(bounds)
        self._bounds = bounds
        self._size = self._get_size(bounds)
        self._init_bitmap(elems)

    @abstractclassmethod
    def _validate_bounds(cls, bounds: Bounds) -> None:
        pass

    @abstractmethod
    def _get_size(self, bounds: Bounds) -> int:
        pass

    def _init_bitmap(self, elems: Optional[Elems]) -> None:
        self._bitmap = Bitmap(size=self.size)
        if elems:
            self._init_elems(elems)

    def _init_elems(self, elems: Elems) -> None:
        if isinstance(elems, int):
            self._bitmap.value = elems
        elif hasattr(elems, '__iter__'):
            for elem in elems:
                self.add(elem)
        else:
            raise TypeError

    def copy(self):
        return self.__class__(self._bounds, elems=self._bitmap.value)

    # ------- container methods ------------------------------------------------

    @property
    def size(self) -> int:
        return self._size

    def __len__(self) -> int:
        # return self._elems.bit_count()  # new in version 3.10
        return bin(self._bitmap.value).count('1')

    def __iter__(self) -> Iterator[Elem]:
        for i, bit in enumerate(reversed(bin(self._bitmap.value)[2:])):
            if bit == '1':
                yield self._unhash(i)

    def __reversed__(self) -> Iterator[Elem]:
        bin_value = bin(self._bitmap.value)[2:]
        for i, bit in zip(reversed(range(len(bin_value))), bin_value):
            if bit == '1':
                yield self._unhash(i)

    def __repr__(self) -> str:
        return '{' + ', '.join([str(elem) for elem in iter(self)]) + '}'

    def __reduce__(self) -> tuple[type, tuple[Bounds, int]]:
        return (self.__class__, (self._bounds, self._bitmap.value))

    # ------- single elem methods ----------------------------------------------

    @abstractmethod
    def _validate_elem(self, elem: Elem) -> None:
        pass

    @abstractmethod
    def _hash(self, elem: Elem) -> int:
        pass

    @abstractmethod
    def _unhash(self, i: int) -> Elem:
        pass

    def __getitem__(self, elem: Elem) -> bool:
        return elem in self

    def __contains__(self, value: Elem) -> bool:
        self._validate_elem(value)
        i = self._hash(value)
        return bool(self._bitmap.get_bit(i))

    def __setitem__(self, elem: Elem, v: Union[bool, int]) -> None:
        self._validate_elem(elem)
        i = self._hash(elem)
        self._bitmap.update_bit(i, v)

    def add(self, value: Elem) -> None:
        self._validate_elem(value)
        i = self._hash(value)
        self._bitmap.set_bit(i)

    def __delitem__(self, elem: Elem) -> None:
        self.remove(elem)

    def remove(self, value: Elem) -> None:
        if value not in self:
            raise KeyError
        else:
            self.discard(value)

    def discard(self, value: Elem) -> None:
        self._validate_elem(value)
        i = self._hash(value)
        self._bitmap.clear_bit(i)

    def pop(self) -> Elem:
        elem = next(iter(self))
        i = self._hash(elem)
        self._bitmap.clear_bit(i)
        return elem

    def clear(self) -> None:
        self._bitmap.value = 0

    # ------- other methods ----------------------------------------------------

    def _validate_other(self, other: Any) -> None:
        if not isinstance(other, self.__class__):
            raise TypeError
        elif other.size != self.size:
            raise ValueError

    def __ne__(self, other):
        return not self.equals(other)

    def __eq__(self, other):
        return self.equals(other)

    def equals(self, other):
        try:
            self._validate_other(other)
            return self._bitmap.value == other._bitmap.value
        except TypeError:
            return False
        except ValueError:
            return False

    def isdisjoint(self, other):
        self._validate_other(other)
        return bool(self._bitmap.value ^ other._bitmap.value)

    def __le__(self, other):
        return self.issubset(other)

    def issubset(self, other):
        self._validate_other(other)
        return (self._bitmap.value -
                (self._bitmap.value & other._bitmap.value)) == 0

    def __lt__(self, other):
        return self.ispropersubset(other)

    def ispropersubset(self, other):
        return self <= other and self != other

    def __ge__(self, other):
        return self.issuperset(other)

    def issuperset(self, other):
        self._validate_other(other)
        return (other._bitmap.value -
                (self._bitmap.value & other._bitmap.value)) == 0

    def __gt__(self, other):
        return self.ispropersuperset(other)

    def ispropersuperset(self, other):
        return self >= other and self != other

    def __or__(self, other):
        return self.union(other)

    def __ror__(self, other):
        return self.union(other)

    def union(self, *others):
        value = self._bitmap.value
        for other in others:
            self._validate_other(other)
            value |= other._bitmap.value
        return self.__class__(self._bounds, elems=value)

    def update(self, *others):
        for other in others:
            self._validate_other(other)
            self._bitmap.value |= other._bitmap.value

    def __ior__(self, other):
        self.update(other)
        return self

    def __and__(self, other):
        return self.intersection(other)

    def __rand__(self, other):
        return self.intersection(other)

    def intersection(self, *others):
        value = self._bitmap.value
        for other in others:
            self._validate_other(other)
            value &= other._bitmap.value
        return self.__class__(self._bounds, elems=value)

    def intersection_update(self, *others):
        for other in others:
            self._validate_other(other)
            self._bitmap.value &= other._bitmap.value

    def __iand__(self, other):
        self.intersection_update(other)
        return self

    def __sub__(self, other):
        return self.difference(other)

    def difference(self, *others):
        value = self._bitmap.value
        for other in others:
            self._validate_other(other)
            value -= (value & other._bitmap.value)
        return self.__class__(self._bounds, elems=value)

    def __rsub__(self, other):
        self._validate_other(other)
        value = other._bitmap.value - (self._bitmap.value & other._bitmap.value)
        return self.__class__(self._bounds, elems=value)

    def difference_update(self, *others):
        for other in others:
            self._validate_other(other)
            self._bitmap.value -= (self._bitmap.value & other._bitmap.value)

    def __isub__(self, other):
        self.difference_update(other)
        return self

    def __xor__(self, other):
        return self.symmetric_difference(other)

    def __rxor__(self, other):
        return self.symmetric_difference(other)

    def symmetric_difference(self, other):
        self._validate_other(other)
        value = self._bitmap.value ^ other._bitmap.value
        return self.__class__(self._bounds, elems=value)

    def symmetric_difference_update(self, other):
        self._validate_other(other)
        self._bitmap.value ^= other._bitmap.value

    def __ixor__(self, other):
        self.symmetric_difference_update(other)
        return self