Skip to content

Instantly share code, notes, and snippets.

@wpietri
Created January 19, 2016 03:35
Show Gist options
  • Save wpietri/157815c872695d4c54f4 to your computer and use it in GitHub Desktop.
Save wpietri/157815c872695d4c54f4 to your computer and use it in GitHub Desktop.
bitstring peformance: strings beat ints
# this is the implementation using strings - it's faster
class Bits:
def __init__(self, *args):
if len(args) == 0:
self.contents = ""
elif len(args) == 1:
if isinstance(args[0], str):
self.contents = args[0]
elif isinstance(args[0], int):
self.contents = "{:b}".format(args[0])
elif isinstance(args[0], Bits):
self.contents = args[0].contents
else:
raise ValueError("don't know how to parse {}".format(args[0]))
elif len(args) == 2 and isinstance(args[0], int):
format_string = "{:0" + str(args[1]) + "b}"
self.contents = format_string.format(args[0])
else:
raise ValueError("don't know how to parse {}, {}".format(args[0], args[1]))
def append(self, other):
if not isinstance(other, Bits):
raise ValueError
self.contents += other.contents
def __int__(self):
return int(self.contents, 2)
def __getitem__(self, given):
return Bits(self.contents.__getitem__(given))
def __add__(self, other):
return Bits(self.contents + other.contents)
def __len__(self):
return self.contents.__len__()
def __eq__(self, other):
return self.contents.__eq__(other.contents)
def __str__(self):
return self.contents
def __repr__(self):
return "Bits({})".format(str(self))
@classmethod
def join(cls, array):
return Bits(''.join(b.contents for b in array))
# this is the implementation using ints; it's slower
class Bits:
def __init__(self, *args):
if len(args) == 0:
self.value = 0
self.length = 0
elif len(args) == 1:
if isinstance(args[0], Bits):
self.value = args[0].value
self.length = args[0].length
elif isinstance(args[0], str):
self.value = int(args[0], 2)
self.length = len(args[0])
elif isinstance(args[0], int):
self.value = args[0]
self.length = self.value.bit_length()
if self.value == 0:
self.length = 1
print("doing it right")
else:
raise ValueError("don't know how to parse {}".format(args[0]))
elif len(args) == 2 and isinstance(args[0], int):
self.value = args[0]
self.length = args[1]
else:
raise ValueError("don't know how to parse {}, {}".format(args[0], args[1]))
def append(self, other):
self.value = self.value << other.length | other.value
self.length = self.length + other.length
def __int__(self):
return self.value
def __getitem__(self, key):
if isinstance(key, int):
pos = self.length - 1 - key
return Bits((self.value >> pos) & mask(1), 1)
elif isinstance(key, slice):
shift = self.length - key.stop
new_length = key.stop - key.start
return Bits((self.value >> shift) & mask(new_length), new_length)
def __add__(self, other):
result = Bits(self)
result.append(other)
return result
def __len__(self):
return self.length
def __eq__(self, other):
return self.value.__eq__(other.value) and self.length.__eq__(other.length)
def __str__(self):
if self.length == 0:
return ''
format_string = "{:0" + str(self.length) + "b}"
return format_string.format(self.value)
def __repr__(self):
return "Bits({})".format(str(self))
@classmethod
def join(cls, array):
result = Bits()
for b in array:
result.append(b)
return result
from unittest import TestCase
from simpleais import *
class TestBits(TestCase):
def test_empty(self):
self.assertEqual('', str(Bits()))
def test_zero(self):
self.assertEqual('0', str(Bits(0)))
def test_one(self):
self.assertEqual('1', str(Bits(1)))
def test_with_length(self):
self.assertEqual('0001', str(Bits(1, 4)))
def test_bits_from_bits(self):
self.assertEqual(Bits('1'), Bits(Bits('1')))
def test_bits_is_bits(self):
self.assertEqual('1001', str(Bits('1001')))
def test_length(self):
self.assertEqual(0, len(Bits()))
self.assertEqual(1, len(Bits('1')))
self.assertEqual(4, len(Bits('1001')))
def test_int_round_trip(self):
self.assertEqual(12345, int(Bits(12345)))
def test_join(self):
buf = [Bits('100'), Bits('000'), Bits('001')]
self.assertEqual(Bits('100000001'), Bits.join(buf))
def test_extract_single_bits(self):
bits = Bits("00011011")
self.assertEqual(Bits('0'), Bits('0')[0])
self.assertEqual(Bits('1'), Bits('1')[0])
self.assertEqual(Bits('1'), Bits('10')[0])
self.assertEqual(Bits('0'), Bits('10')[1])
self.assertEqual(Bits('1'), Bits('101')[0])
self.assertEqual(Bits('1'), Bits('101')[2])
def test_extract_ranges(self):
bits = Bits("00011011")
self.assertEqual(Bits('00'), bits[0:2])
self.assertEqual(Bits('0001'), bits[0:4])
self.assertEqual(Bits('1011'), bits[4:8])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment