micropython-samples/bitmap/bitmap.py

138 wiersze
3.2 KiB
Python
Czysty Zwykły widok Historia

2019-02-20 16:51:19 +00:00
# bitmap.py
# Ideas for non-allocating classes based around a bitmap. Three classes are
# presented:
# IntSet: this is a set which is constrained to accept only integers in
# a range 0 <= i <= maxval. Provides a minimal set of methods which can readily
# be expanded.
# SetByte: an even more minimal version of IntSet where the range is
# 0 <= i <=255.
# BoolList: A list of booleans. The list index is constrained to lie in range
# 0 <= i <= maxval.
class BitMap:
def __init__(self, maxval):
d, m = divmod(maxval, 8)
self._ba = bytearray(d + int(m > 0))
self._size = maxval
def _check(self, i):
if i < 0 or i >= self._size:
raise ValueError('Index out of range')
def _val(self, i):
self._check(i)
return (self._ba[i >> 3] & 1 << (i & 7)) > 0
def _set(self, i):
self._check(i)
self._ba[i >> 3] |= 1 << (i & 7)
def _clear(self, i):
self._check(i)
self._ba[i >> 3] &= ~(1 << (i &7))
# Iterate through an IntSet returning members
# Iterate through an IntList returning index value of True members
def __iter__(self):
for i in range(self._size):
if self._val(i):
yield i
# if MyIntSet: True unless set is empty
# if MyBoolList: True if any element is True
def __bool__(self):
for x in self._ba:
if x:
return True
return False
class IntSet(BitMap):
def __init__(self, maxval=256):
super().__init__(maxval)
# if n in MyIntSet:
def __contains__(self, i):
self._check(i)
return self._val(i)
# MyIntSet.discard(n)
def discard(self, i):
self._clear(i)
# MyIntSet.remove(n)
def remove(self, i):
if i in self:
self.discard(i)
else:
raise KeyError(i)
# MyIntSet.add(n)
def add(self, i):
self._set(i)
# Generator iterates through set intersection. Avoids allocation.
def intersec(self, other):
for i in other:
if i in self:
yield i
class BoolList(BitMap):
def __init__(self, maxval=256):
super().__init__(maxval)
# MyBoolList[n] = True
def __setitem__(self, bit, val):
self._set(bit) if val else self._clear(bit)
# if MyBoolList[n]:
def __getitem__(self, bit):
return self._val(bit)
# if False in MyBoolList:
def __contains__(self, i):
if i:
for b in self._ba:
if b:
return True
else:
for b in self._ba:
if not b:
return True
return False
# Minimal implementation of set for 0-255
class SetByte:
def __init__(self):
self._ba = bytearray(32)
def __bool__(self):
for x in self._ba:
if x:
return True
return False
def __contains__(self, i):
return (self._ba[i >> 3] & 1 << (i & 7)) > 0
def discard(self, i):
self._ba[i >> 3] &= ~(1 << (i &7))
def add(self, i):
self._ba[i >> 3] |= 1 << (i & 7)
# Test for set intersection
bs = IntSet()
bs.add(1)
bs.add(2)
1 in bs
c = IntSet()
c.add(1)
c.add(4)
c.add(5)
g = bs.intersec(c)
next(g)
next(g)