|
@@ -1,6 +1,5 @@
|
|
from typing import *
|
|
from typing import *
|
|
from functools import reduce
|
|
from functools import reduce
|
|
-import math
|
|
|
|
|
|
|
|
# Bitmap inherits 'int' and is therefore immutable.
|
|
# Bitmap inherits 'int' and is therefore immutable.
|
|
# Methods that return a Bitmap return a new bitmap and leave the arguments untouched.
|
|
# Methods that return a Bitmap return a new bitmap and leave the arguments untouched.
|
|
@@ -13,11 +12,11 @@ class Bitmap(int):
|
|
# iterable: positions of bits to set.
|
|
# iterable: positions of bits to set.
|
|
@classmethod
|
|
@classmethod
|
|
def from_list(cls, iterable):
|
|
def from_list(cls, iterable):
|
|
- v = reduce(lambda x,y: x|2**y, iterable, 0) # iterable
|
|
|
|
|
|
+ v = reduce(lambda x,y: x|1<<y, iterable, 0) # iterable
|
|
return super(cls, cls).__new__(cls, v)
|
|
return super(cls, cls).__new__(cls, v)
|
|
|
|
|
|
def __repr__(self):
|
|
def __repr__(self):
|
|
- return "Bitmap("+format(self, 'b')+")"
|
|
|
|
|
|
+ return "Bitmap('"+format(self, 'b')+"')"
|
|
|
|
|
|
def __str__(self):
|
|
def __str__(self):
|
|
return self.__repr__()
|
|
return self.__repr__()
|
|
@@ -31,23 +30,53 @@ class Bitmap(int):
|
|
def __invert__(self):
|
|
def __invert__(self):
|
|
return self.__class__(super().__invert__())
|
|
return self.__class__(super().__invert__())
|
|
|
|
|
|
|
|
+ def __neg__(self):
|
|
|
|
+ return self.__class__(super().__neg__())
|
|
|
|
+
|
|
def has(self, pos):
|
|
def has(self, pos):
|
|
- return self & 2**pos
|
|
|
|
|
|
+ return self & 1 << pos
|
|
|
|
|
|
def has_all(self, bitmap):
|
|
def has_all(self, bitmap):
|
|
return (self | bitmap) == self
|
|
return (self | bitmap) == self
|
|
|
|
|
|
- # pos of first set bit
|
|
|
|
- def first_bit_pos(self):
|
|
|
|
- return math.floor(math.log2(x & -x))
|
|
|
|
|
|
+ def lowest_bit(self) -> int:
|
|
|
|
+ low = self & -self # only the lowest bit set
|
|
|
|
+ pos = -1
|
|
|
|
+ while low:
|
|
|
|
+ low >>= 1
|
|
|
|
+ pos += 1
|
|
|
|
+ return pos
|
|
|
|
+
|
|
|
|
+ def highest_bit(self) -> int:
|
|
|
|
+ pos = -1
|
|
|
|
+ while self:
|
|
|
|
+ self >>= 1
|
|
|
|
+ pos += 1
|
|
|
|
+ return pos
|
|
|
|
|
|
|
|
+ # Takes 1 iteration over our bitmap
|
|
def items(self) -> Iterable[int]:
|
|
def items(self) -> Iterable[int]:
|
|
pos = 0
|
|
pos = 0
|
|
- while 2**pos <= self:
|
|
|
|
- if self & 2**pos:
|
|
|
|
|
|
+ while self > 0:
|
|
|
|
+ if (self >> 1) << 1 != self:
|
|
yield pos
|
|
yield pos
|
|
pos += 1
|
|
pos += 1
|
|
|
|
+ self >>= 1
|
|
|
|
+
|
|
|
|
+ # Takes 2 iterations over our bitmap, one for highest_bit,
|
|
|
|
+ # and then to find the rest of the bits.
|
|
|
|
+ def reverse_items(self) -> Iterable[int]:
|
|
|
|
+ pos = self.highest_bit()
|
|
|
|
+ if pos >= 0:
|
|
|
|
+ yield pos
|
|
|
|
+ pos -= 1
|
|
|
|
+ while pos >= 0:
|
|
|
|
+ high = 1 << pos
|
|
|
|
+ if self & high:
|
|
|
|
+ yield pos
|
|
|
|
+ self -= high # unset high bit
|
|
|
|
+ pos -= 1
|
|
|
|
|
|
# Create a bitmap with a single bit set.
|
|
# Create a bitmap with a single bit set.
|
|
def bit(pos):
|
|
def bit(pos):
|
|
- return Bitmap(2 ** pos)
|
|
|
|
|
|
+ return Bitmap(1 << pos)
|