Feedback on compact data management module

Hello,
I recently created a compact data storage module and would appreciate any feedback you guys may have. Please let me know if there are any errors or issues :slight_smile:
Thanks

Module
-- [ Bitmaps ]
-- Simple module for handling compact data storage. 		 	 		
-- Created by Lincoln Touw 8/11/2025 16:13:07 UTC-0500 	 	 		
  		 		 		
local bit_masks: {number} = {} 	 	
for i = 0, 7 do bit_masks[i] = bit32.lshift(1, i) end
 	 			
export type Bitmap = {} 	 			 	  		

local Bitmap = {}  				
Bitmap.__index = Bitmap
-- Creates a new Bitmap with a size of <code>allocation_size</code> bits.
Bitmap.new = function( 	 			 		
	allocation_size: number 	
) return setmetatable({ map = buffer.create(math.ceil(allocation_size / 8)), }, Bitmap)
end  		
-- Reconstructs a Bitmap from the given string.
Bitmap.fromString = function(
	map: string
) return setmetatable({ map = buffer.fromstring(map), }, Bitmap) 		
end 	
	 
-- Returns the maximum allowed amount of bits in the Bitmap. 	 			
function Bitmap:getBitCount(): number return buffer.len(self.map) * 8 end
-- Returns the amount of allocated bytes for the Bitmap. 	
function Bitmap:getByteCount(): number return buffer.len(self.map) end   
-- Counts the total amount of bits that are set to 1. 	 		
function Bitmap:countSetBits(): number 		  	 		
	local total: number = 0 	   			 	 		 		 	 	 	  		 
	for i = 0, buffer.len(self.map) - 1 do
		local byte = buffer.readu8(self.map, i)
		-- (using kernighan's algorithm)
		-- https://how.dev/answers/what-is-kernighans-algorithm  	
		while byte ~= 0 do
			byte = bit32.band(byte, byte - 1)
			total += 1 	 		
		end
	end
	return total	 
end  	 	 		 	
 	 	
-- Changes the state of the specified bit.
function Bitmap:writeBit( 	 		   		
	bit_offset: number,
	state: boolean
): Bitmap 	 	 	
	local byte_ind = math.floor(bit_offset / 8)
	local bit_mask = bit_masks[math.floor(bit_offset % 8)] 	 			 	 	  	 	
	local byte_val = buffer.readu8(self.map, byte_ind) 		 		
	byte_val =  	
		if state then
		bit32.bor(byte_val, bit_mask)
		else  		   
		bit32.band(byte_val, bit32.bnot(bit_mask)) 		  		 
	buffer.writeu8(self.map, byte_ind, byte_val)
	return self 			 
end  
-- Reads and returns the state of a specified bit.
function Bitmap:readBit( 			 
	bit_offset: number 		
): boolean			
	local byte_ind = math.floor(bit_offset / 8)
	local bit_mask = bit_masks[math.floor(bit_offset % 8)] 	 	 	
	local byte_val = buffer.readu8(self.map, byte_ind)
	return bit32.band(byte_val, bit_mask) ~= 0 		  		 	  	 	 	
end 	 	   

-- Writes to a range of bits.
function Bitmap:writeRange(
	start_bit: number,
	count: number, 	 	 	 	 	 		 	 
	state: boolean
): Bitmap  			 	
	for i = start_bit, start_bit + count - 1 do self:writeBit(i, state) end 	
	return self 		
end 	 	
-- Reads and returns a range of bits.
function Bitmap:readRange(  		
	start_bit: number,
	count: number 	 	 		 	 	
): { boolean }  			 	 	  	
	local output: { boolean } = {} 	 	 	 	
	for i = start_bit, start_bit + count - 1 do table.insert(output, self:readBit(i)) end 	
	return output 	 	 	
end 		

-- Resets all bits to 0. 	
function Bitmap:reset(): Bitmap  	
	for i = 0, buffer.len(self.map) - 1 do buffer.writeu8(self.map, i, 0) end
	return self  			
end 
-- Sets the state of every bit in the Bitmap to 1. 	 	 	
function Bitmap:set( 		
	state: boolean
): Bitmap  	 	 	
	for i = 0, buffer.len(self.map) - 1 do	buffer.writeu8(self.map, i, 0xFF) end 		
	return self  		
end  		
-- Inverts a bit so 0 -> 1 and 1 -> 0.
function Bitmap:invertBit(
	bit_offset: number
): boolean 		
	local byte_ind = math.floor(bit_offset / 8)  	
	local bit_mask = bit_masks[math.floor(bit_offset % 8)] 		
	local byte_val = buffer.readu8(self.map, byte_ind)
	byte_val = bit32.bxor(byte_val, bit_mask)
	buffer.writeu8(self.map, byte_ind, byte_val) 		 	 	 	 		 		 		 
	return byte_val 	 			 
end  
-- Inverts all bits so 0 -> 1 and 1 -> 0. 	 		
function Bitmap:invertAll(): Bitmap	 		
	local len = buffer.len(self.map)
	for i = 0, len - 1 do 		 	
		local b = buffer.readu8(self.map, i)
		buffer.writeu8(self.map, i, bit32.bnot(b) % 256)
	end return self 
end   		 
 			 	
-- Finds the first bit that matches the given state, and returns the location of that bit (if any) in the Bitmap. 	 		
function Bitmap:search(
	state: boolean 	
): number? 	 				
	for i = 0, self:getBitCount() - 1 do
		if self:readBit(i) == state then return i end 		
	end return nil
end 	 	 		 	

-- Converts the Bitmap to a string (for remote saving, etc.) 	 			
function Bitmap:toString(): string return buffer.tostring(self.map) end
-- Pretty-print a Bitmap in rows for debugging etc.
function Bitmap:print(
	row_size: number?
): ()  		  			 
	local total_bits: number = self:getBitCount()
	local rows: string = "\n" 		  		   
	for i = 0, total_bits - 1 do 		
		rows ..= self:readBit(i) and "1" or "0"  	
		if (i + 1) % (row_size or 8) == 0 then rows ..= '\n' end 	
	end print(rows) return rows 			 	
end
 
-- return module
return Bitmap