Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
163 changes: 91 additions & 72 deletions src/bitcode/bitcode.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,18 @@
#

CFG_INTBITSET_ENABLE_SANITY_CHECKS = True
from collections.abc import Iterable


class intbitset:
def __init__(self, rhs=None, preallocate=-1, trailing_bits=0, sanity_checks=CFG_INTBITSET_ENABLE_SANITY_CHECKS,
no_allocate=0):
self.bitset = 0

self.bitset = set()
if isinstance(rhs, int):
self.bitset = rhs
self.add(rhs)
elif isinstance(rhs, intbitset):
self.bitset = rhs.bitset
elif isinstance(rhs, (list, set, frozenset, range, tuple)):
self.bitset = rhs.bitset.copy()
elif isinstance(rhs, Iterable):
for value in rhs:
self.add(value)

Expand All @@ -35,115 +35,120 @@ def add(self, value):
"""
if value < 0:
raise ValueError("Value can't be negative")
self.bitset |= 1 << value
self.bitset.add(value)

def clear(self):
self.bitset = 0
self.bitset = set()

def is_infinite(self):
return False

def extract_finite_list(self, up_to=""):
return sorted(self.bitset)

def copy(self):
""" Return a shallow copy of a set. """
new = intbitset()
new.bitset = self.bitset
new.bitset = self.bitset.copy()
return new

def difference(self, *args):
""" Return a new intbitset with elements from the intbitset that are not in the others. """
new = intbitset(self.bitset)
for other in args:
new.bitset = (new.bitset ^ other.bitset) & self.bitset
new = intbitset()
new.bitset = self.bitset.difference(*args)
return new

def difference_update(self, *args):
""" Update the intbitset, removing elements found in others. """
for other in args:
self.bitset &= (self.bitset ^ other.bitset)
self.bitset.difference_update(*args)

def discard(self, value):
"""
Remove an element from a intbitset if it is a member.
If the element is not a member, do nothing.
"""
self.bitset &= ~(1 << value)
self.bitset.discard(value)

def isdisjoint(self, other):
""" Return True if two intbitsets have a null intersection. """
return self.intersection(*[other]).bitset == 0
return self.bitset.isdisjoint(other.bitset)

def issuperset(self, other):
""" Report whether this set contains another set. """
return (self.bitset & other.bitset) == other.bitset
return self.bitset.issuperset(other.bitset)

def issubset(self, other):
""" Report whether another set contains this set. """
return (self.bitset & other.bitset) == self.bitset
return self.bitset.issubset(other.bitset)

def remove(self, key):
"""
Remove an element from a set; it must be a member.
If the element is not a member, raise a KeyError.
"""
initial_bitset = self.bitset
self.discard(key)
if initial_bitset == self.bitset:
raise KeyError(f"{key} not in bitset")
self.bitset.remove(key)

def strbits(self):
"""
Return a string of 0s and 1s representing the content in memory
of the intbitset.
"""
return bin(self.bitset)[2:]
new = self.bitset
if len(new) == 0:
return ""
res = ["0"] * (max(new) + 1)
for _ in new:
res[_] = "1"
return ''.join(res)

def symmetric_difference(self, other):
"""
Return the symmetric difference of two sets as a new set.
(i.e. all elements that are in exactly one of the sets.)
"""
new = intbitset()
new.bitset = other.bitset ^ self.bitset
new.bitset = self.bitset.symmetric_difference(other.bitset)
return new

def symmetric_difference_update(self, other):
""" Update an intbitset with the symmetric difference of itself and another. """
self.bitset ^= other.bitset
self.bitset.symmetric_difference_update(other.bitset)

def tolist(self):
"""
Legacy method to retrieve a list of all the elements inside an
intbitset.
"""
elements = []
for element in self:
elements = [element] + elements
return elements
return list(self.bitset)

def union(self, *args):
""" Return a new intbitset with elements from the intbitset and all others. """
new = intbitset()
bitset = self.bitset
for other in args:
bitset |= other.bitset
new.bitset = bitset
new.bitset = self.bitset.union(*args)
return new

def union_update(self, *args):
""" Update the intbitset, adding elements from all others. """
for other in args:
self.bitset |= other.bitset
self.bitset = self.bitset.union(*args)

def intersection(self, *args):
""" Return a new intbitset with elements common to the intbitset and all others. """
new = intbitset()
bitset = self.bitset
for other in args:
bitset &= other.bitset
new.bitset = bitset
new.bitset = self.bitset.intersection(*args)
return new

def intersection_update(self, *args):
""" Update the intbitset, keeping only elements found in it and all others. """
for other in args:
self.bitset &= other.bitset
self.bitset.intersection_update(*args)

def pop(self):
sorted_lis = sorted(self.bitset)
try:
poped = sorted_lis.pop()
except IndexError:
raise KeyError
self.bitset = set(sorted_lis)
return poped

def __and__(self, other):
"""
Expand All @@ -165,50 +170,64 @@ def __eq__(self, other):

def __contains__(self, key):
""" Return key in self. """
key_bit = 1 << key
return key_bit & self.bitset == key_bit
return key in self.bitset

def __len__(self):
""" Return len(self). """
bitset = self.bitset
size = 0
while bitset != 0:
size += bitset & 1
bitset >>= 1
return size
return len(self.bitset)

def __iter__(self):
""" Implement iter(self). """
bits = bin(self.bitset)[2:]
size = len(bits) - 1
for bit in bits:
if bit == "1":
yield size
size -= 1

def __hash__(self):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

are intbitset hashable?

return self.bitset
return iter(sorted(self.bitset))

def __str__(self):
binary = bin(self.bitset)[2:]
n = len(binary)
ans = "intbitset(["
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should use bitcode there

for char in binary:
if char == "1":
ans += str(n - 1)
if n > 0:
ans += ", "
n -= 1
ans = ans.rstrip(', ')
for char in sorted(self.bitset):
ans += str(char) + ", "
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You may consider accumulating in a list and ", ".join the list at the end

ans = ans.rstrip(", ")
ans += "])"
return ans

def __getitem__(self, item):

elements = []
for element in self:
elements = [element] + elements
n = len(elements)
sorted_list = sorted(list(self.bitset))
if isinstance(item, slice):
indices = range(*item.indices(len(sorted_list)))
return [sorted_list[i] for i in indices]
n = len(self.bitset)
if item >= n:
raise IndexError("Sequence index out of range")
return elements[item]
return sorted_list[item]

def __iand__(self, other):
self.bitset = self.bitset & other.bitset

def __ior__(self, other):
self.bitset = self.bitset | other.bitset

def __xor__(self, other):
new = intbitset()
new.bitset = self.bitset ^ other.bitset
return new

def __ixor__(self, other):
self.bitset = self.bitset ^ other.bitset

def __sub__(self, other):
new = intbitset()
new.bitset = self.bitset - other.bitset
return new

def __isub__(self, other):
self.bitset = self.bitset - other.bitset

def __ge__(self, other):
return set.__ge__(self.bitset, other.bitset)

def __gt__(self, other):
return set.__gt__(self.bitset, other.bitset)

def __le__(self, other):
return set.__le__(self.bitset, other.bitset)

def __lt__(self, other):
return set.__lt__(self.bitset, other.bitset)
Loading