Created
May 31, 2018 21:28
-
-
Save cheshirekow/e4cc3206014f4080288b4ff33356ea4e to your computer and use it in GitHub Desktop.
Simple BitField in python
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class BitMember(object): | |
def __init__(self, size, offset=0): | |
self.size = size | |
self.offset = offset | |
@property | |
def mask(self): | |
return ~((~0) << (self.offset + self.size)) & ((~0) << self.offset) | |
class BitField(object): | |
def __init__(self): | |
self.value = 0 | |
self._offset = 0 | |
def __setattr__(self, name, value): | |
__dict__ = super(BitField, self).__getattribute__('__dict__') | |
obj = __dict__.get(name, None) | |
if isinstance(obj, BitMember): | |
offset = self.__dict__[name].offset | |
mask = self.__dict__[name].mask | |
# Clear the current value | |
self.value = self.value & ~mask | |
# Update with the new value | |
self.value |= (value << offset) & mask | |
else: | |
if isinstance(value, BitMember): | |
value = BitMember(value.size, offset=self._offset) | |
self._offset += value.size | |
super(BitField, self).__setattr__(name, value) | |
def __getattribute__(self, name): | |
__dict__ = super(BitField, self).__getattribute__('__dict__') | |
obj = __dict__.get(name, None) | |
if isinstance(obj, BitMember): | |
offset = self.__dict__[name].offset | |
mask = self.__dict__[name].mask | |
return (self.value & mask) >> offset | |
return super(BitField, self).__getattribute__(name) | |
def describe(self): | |
""" | |
Return a string describing the BitField. For example: | |
``` | |
class MyVec(BitVector): | |
def __init__(self): | |
super(MyVec, self).__init__() | |
self.x = BitMember(0,3) | |
self.y = BitMember(3,1) | |
self.z = BitMember(4,10) | |
``` | |
``` | |
print MyVec().describe() | |
``` | |
``` | |
0000000000 0 000 | |
c b a | |
off size field | |
--- ---- ----- | |
a: 0 3 x | |
b: 3 1 y | |
c: 4 10 z | |
``` | |
""" | |
__dict__ = super(BitField, self).__getattribute__('__dict__') | |
fields = [] | |
for name, obj in __dict__.items(): | |
if isinstance(obj, BitMember): | |
fields.append((obj.offset, name, obj)) | |
fields = sorted(fields, reverse=True) | |
line0 = [] | |
line1 = [] | |
legend = [] | |
keys = 'abcdefghijklmnopqrstuvwxyz' | |
for idx, (_, name, obj) in enumerate(fields): | |
key = keys[len(fields) - idx - 1] | |
line0.append('0' * obj.size) | |
line1.append('{}{}'.format(' ' * (obj.size - 1), key)) | |
legend.append((key, obj, name)) | |
out = io.StringIO() | |
out.write(u' '.join(line0)) | |
out.write(u'\n') | |
out.write(u' '.join(line1)) | |
out.write(u'\n\n') | |
out.write(u' off size field\n') | |
out.write(u' --- ---- -----\n') | |
for key, obj, name in legend[::-1]: | |
out.write(u'{:1s}: {:3d} {:4d} {}\n'.format( | |
key, obj.offset, obj.size, name)) | |
return out.getvalue() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment