Created
January 19, 2016 03:35
-
-
Save wpietri/157815c872695d4c54f4 to your computer and use it in GitHub Desktop.
bitstring peformance: strings beat ints
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
# 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 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
# 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 |
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
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