You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			109 lines
		
	
	
		
			3.0 KiB
		
	
	
	
		
			Lua
		
	
			
		
		
	
	
			109 lines
		
	
	
		
			3.0 KiB
		
	
	
	
		
			Lua
		
	
| local base = string.match(..., "(.-)[^%.]+%.[^%.]+$")
 | |
| local bit = require("bit")
 | |
| local eh = require(base.."helper.enum")
 | |
| local ffi = require("ffi")
 | |
| local mth = require(base.."helper.mt")
 | |
| 
 | |
| local ceil, error = math.ceil, error
 | |
| local table_concat = table.concat
 | |
| local enum_to_int = eh.to_int
 | |
| local band, bnot, bor, lshift, rshift = bit.band, bit.bnot, bit.bor, bit.lshift, bit.rshift
 | |
| local ffi_cast, ffi_fill, ffi_sizeof = ffi.cast, ffi.fill, ffi.sizeof
 | |
| 
 | |
| local ulong_ary = ffi.typeof("unsigned long[?]")
 | |
| local ulongp = ffi.typeof("unsigned long*")
 | |
| local elem_bytes = ffi.sizeof("long")
 | |
| local elem_bits = elem_bytes * 8
 | |
| 
 | |
| local mt, index = {}, {}
 | |
| 
 | |
| local function array_size(len)
 | |
|   return ceil(len / elem_bits)
 | |
| end
 | |
| index.array_size = array_size
 | |
| 
 | |
| function index:clear()
 | |
|   ffi_fill(self._buf, self.bytes)
 | |
|   return self
 | |
| end
 | |
| 
 | |
| function index:fill()
 | |
|   ffi_fill(self._buf, self.bytes, 0xff)
 | |
|   return self
 | |
| end
 | |
| 
 | |
| function index:get(i)
 | |
|   i = enum_to_int(self._enum, i)
 | |
|   if i < 0 or i >= self.length then return false end
 | |
|   return band(rshift(self._buf[i / elem_bits], i % elem_bits), 1) ~= 0
 | |
| end
 | |
| mt.base_getter = index.get
 | |
| 
 | |
| function index:set(i, val)
 | |
|   i = enum_to_int(self._enum, i)
 | |
|   if i < 0 or i >= self.length then error("Index out of range") end
 | |
|   local idx = i / elem_bits
 | |
|   local bit = lshift(1ULL, i % elem_bits)
 | |
|   local buf = self._buf
 | |
|   if val then
 | |
|     buf[idx] = bor(buf[idx], bit)
 | |
|   else
 | |
|     buf[idx] = band(buf[idx], bnot(bit))
 | |
|   end
 | |
|   return self
 | |
| end
 | |
| mt.base_setter = index.set
 | |
| 
 | |
| -- poor man's macro processor
 | |
| local function iter_func(shit)
 | |
|   local str = [[
 | |
| local enum_to_int, bit, elem_bits = ...
 | |
| local band, rshift = bit.band, bit.rshift
 | |
| local function func(self, i)
 | |
|   i = enum_to_int(self._enum, i)
 | |
|   while true do
 | |
|     i = i+1
 | |
|     if i >= self.length then return end
 | |
| 
 | |
|     local name = self._enum[i]
 | |
|     local val = band(rshift(self._buf[i / elem_bits], i % elem_bits), 1) ~= 0
 | |
|     <shit>
 | |
|   end
 | |
| end
 | |
| return function(self) return func, self, -1 end
 | |
| ]]
 | |
|   return assert(loadstring(str:gsub("<shit>", shit)))(enum_to_int, bit, elem_bits)
 | |
| end
 | |
| 
 | |
| index.int_pairs = iter_func("if name or val then return i, val end")
 | |
| index.str_pairs = iter_func("if name or val then return name or i, val end")
 | |
| index.i_members = iter_func("if val then return i end")
 | |
| index.str_members = iter_func("if val then return name or i end")
 | |
| 
 | |
| function index:tostring()
 | |
|   local res = {}
 | |
|   for m in self:str_members() do res[#res+1] = m end
 | |
|   local raw = {}
 | |
|   for i=1,ceil(self.length / elem_bits) do
 | |
|     raw[i] = string.format("%#0x", self._buf[i-1])
 | |
|   end
 | |
|   return "["..table_concat(res, ", ").."] ("..table.concat(raw, ", ")..")"
 | |
| end
 | |
| mt.__tostring = index.tostring
 | |
| 
 | |
| local function from_buf(enum, buf, len)
 | |
|   buf = ffi_cast(ulongp, buf)
 | |
|   local bs = elem_bytes * ceil(len / elem_bits)
 | |
|   return setmetatable({_enum=enum, _buf=buf, length=len, bytes=bs}, mt)
 | |
| end
 | |
| index.from_buf = from_buf
 | |
| 
 | |
| function index.new_for_ioctl(enum, len)
 | |
|   local buf = ulong_ary(array_size(len))
 | |
|   local x = from_buf(enum, buf, len)
 | |
|   return x, buf, ffi_sizeof(buf)
 | |
| end
 | |
| 
 | |
| mth.add_index_methods(mt, index)
 | |
| return setmetatable({}, mt)
 |