extends RefCounted class_name _Bitset # Stores a list of booleans, representing them efficiently as a PackedByteArray var _data: PackedByteArray var _bit_count: int static func of_bools(values: Array) -> _Bitset: var result := _Bitset.new(values.size()) for i in values.size(): if values[i]: result.set_bit(i) return result func _init(bit_count: int): var bytes := bit_count / 8 if bit_count % 8 > 0: bytes += 1 _data = PackedByteArray() _data.resize(bytes) _bit_count = bit_count func bit_count() -> int: return _bit_count func is_empty() -> bool: return _bit_count == 0 func is_not_empty() -> bool: return _bit_count != 0 func get_bit(idx: int) -> bool: assert(idx < _bit_count, "Accessing bit %d on bitset of size %d!" % [idx, _bit_count]) var byte_idx := idx / 8 var bit_idx := idx % 8 return (_data[byte_idx] >> bit_idx) & 0x1 != 0 func set_bit(idx: int) -> void: assert(idx < _bit_count, "Accessing bit %d on bitset of size %d!" % [idx, _bit_count]) var byte_idx := idx / 8 var bit_idx := idx % 8 _data[byte_idx] |= 0x1 << bit_idx func clear_bit(idx: int) -> void: assert(idx < _bit_count, "Accessing bit %d on bitset of size %d!" % [idx, _bit_count]) var byte_idx := idx / 8 var bit_idx := idx % 8 _data[byte_idx] &= ~(0x1 << bit_idx) func toggle_bit(idx: int) -> void: assert(idx < _bit_count, "Accessing bit %d on bitset of size %d!" % [idx, _bit_count]) var byte_idx := idx / 8 var bit_idx := idx % 8 _data[byte_idx] ^= 0x1 << bit_idx func get_set_indices() -> Array[int]: var result := [] as Array[int] for i in _data.size(): var byte := _data[i] if byte & 0x01: result.append(i * 8 + 0) if byte & 0x02: result.append(i * 8 + 1) if byte & 0x04: result.append(i * 8 + 2) if byte & 0x08: result.append(i * 8 + 3) if byte & 0x10: result.append(i * 8 + 4) if byte & 0x20: result.append(i * 8 + 5) if byte & 0x40: result.append(i * 8 + 6) if byte & 0x80: result.append(i * 8 + 7) return result func equals(other) -> bool: if other is _Bitset: return other._bit_count == _bit_count and other._data == _data else: return false func _to_string() -> String: if is_empty(): return "Bitset(n=0)" else: var body := "" for i in _bit_count: if i != 0 and i % 4 == 0: body += " " if get_bit(i): body += "1" else: body += "0" return "Bitset(n=%d, %s)" % [_bit_count, body]