bitfield.py 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. # Written by Bram Cohen, Uoti Urpala, and John Hoffman
  2. # see LICENSE.txt for license information
  3. try:
  4. True
  5. except:
  6. True = 1
  7. False = 0
  8. bool = lambda x: not not x
  9. try:
  10. sum([1])
  11. negsum = lambda a: len(a)-sum(a)
  12. except:
  13. negsum = lambda a: reduce(lambda x,y: x+(not y), a, 0)
  14. def _int_to_booleans(x):
  15. r = []
  16. for i in range(8):
  17. r.append(bool(x & 0x80))
  18. x <<= 1
  19. return tuple(r)
  20. lookup_table = []
  21. reverse_lookup_table = {}
  22. for i in xrange(256):
  23. x = _int_to_booleans(i)
  24. lookup_table.append(x)
  25. reverse_lookup_table[x] = chr(i)
  26. class Bitfield:
  27. def __init__(self, length = None, bitstring = None, copyfrom = None):
  28. if copyfrom is not None:
  29. self.length = copyfrom.length
  30. self.array = copyfrom.array[:]
  31. self.numfalse = copyfrom.numfalse
  32. return
  33. if length is None:
  34. raise ValueError, "length must be provided unless copying from another array"
  35. self.length = length
  36. if bitstring is not None:
  37. extra = len(bitstring) * 8 - length
  38. if extra < 0 or extra >= 8:
  39. raise ValueError
  40. t = lookup_table
  41. r = []
  42. for c in bitstring:
  43. r.extend(t[ord(c)])
  44. if extra > 0:
  45. if r[-extra:] != [0] * extra:
  46. raise ValueError
  47. del r[-extra:]
  48. self.array = r
  49. self.numfalse = negsum(r)
  50. else:
  51. self.array = [False] * length
  52. self.numfalse = length
  53. def __setitem__(self, index, val):
  54. val = bool(val)
  55. self.numfalse += self.array[index]-val
  56. self.array[index] = val
  57. def __getitem__(self, index):
  58. return self.array[index]
  59. def __len__(self):
  60. return self.length
  61. def tostring(self):
  62. booleans = self.array
  63. t = reverse_lookup_table
  64. s = len(booleans) % 8
  65. r = [ t[tuple(booleans[x:x+8])] for x in xrange(0, len(booleans)-s, 8) ]
  66. if s:
  67. r += t[tuple(booleans[-s:] + ([0] * (8-s)))]
  68. return ''.join(r)
  69. def complete(self):
  70. return not self.numfalse
  71. def test_bitfield():
  72. try:
  73. x = Bitfield(7, 'ab')
  74. assert False
  75. except ValueError:
  76. pass
  77. try:
  78. x = Bitfield(7, 'ab')
  79. assert False
  80. except ValueError:
  81. pass
  82. try:
  83. x = Bitfield(9, 'abc')
  84. assert False
  85. except ValueError:
  86. pass
  87. try:
  88. x = Bitfield(0, 'a')
  89. assert False
  90. except ValueError:
  91. pass
  92. try:
  93. x = Bitfield(1, '')
  94. assert False
  95. except ValueError:
  96. pass
  97. try:
  98. x = Bitfield(7, '')
  99. assert False
  100. except ValueError:
  101. pass
  102. try:
  103. x = Bitfield(8, '')
  104. assert False
  105. except ValueError:
  106. pass
  107. try:
  108. x = Bitfield(9, 'a')
  109. assert False
  110. except ValueError:
  111. pass
  112. try:
  113. x = Bitfield(7, chr(1))
  114. assert False
  115. except ValueError:
  116. pass
  117. try:
  118. x = Bitfield(9, chr(0) + chr(0x40))
  119. assert False
  120. except ValueError:
  121. pass
  122. assert Bitfield(0, '').tostring() == ''
  123. assert Bitfield(1, chr(0x80)).tostring() == chr(0x80)
  124. assert Bitfield(7, chr(0x02)).tostring() == chr(0x02)
  125. assert Bitfield(8, chr(0xFF)).tostring() == chr(0xFF)
  126. assert Bitfield(9, chr(0) + chr(0x80)).tostring() == chr(0) + chr(0x80)
  127. x = Bitfield(1)
  128. assert x.numfalse == 1
  129. x[0] = 1
  130. assert x.numfalse == 0
  131. x[0] = 1
  132. assert x.numfalse == 0
  133. assert x.tostring() == chr(0x80)
  134. x = Bitfield(7)
  135. assert len(x) == 7
  136. x[6] = 1
  137. assert x.numfalse == 6
  138. assert x.tostring() == chr(0x02)
  139. x = Bitfield(8)
  140. x[7] = 1
  141. assert x.tostring() == chr(1)
  142. x = Bitfield(9)
  143. x[8] = 1
  144. assert x.numfalse == 8
  145. assert x.tostring() == chr(0) + chr(0x80)
  146. x = Bitfield(8, chr(0xC4))
  147. assert len(x) == 8
  148. assert x.numfalse == 5
  149. assert x.tostring() == chr(0xC4)