inputor

Evdev remapping utility in lua
git clone https://git.neptards.moe/u3shit/inputor.git
Log | Files | Refs

bitfield.lua (3069B)


      1 local base = string.match(..., "(.-)[^%.]+%.[^%.]+$")
      2 local bit = require("bit")
      3 local eh = require(base.."helper.enum")
      4 local ffi = require("ffi")
      5 local mth = require(base.."helper.mt")
      6 
      7 local ceil, error = math.ceil, error
      8 local table_concat = table.concat
      9 local enum_to_int = eh.to_int
     10 local band, bnot, bor, lshift, rshift = bit.band, bit.bnot, bit.bor, bit.lshift, bit.rshift
     11 local ffi_cast, ffi_fill, ffi_sizeof = ffi.cast, ffi.fill, ffi.sizeof
     12 
     13 local ulong_ary = ffi.typeof("unsigned long[?]")
     14 local ulongp = ffi.typeof("unsigned long*")
     15 local elem_bytes = ffi.sizeof("long")
     16 local elem_bits = elem_bytes * 8
     17 
     18 local mt, index = {}, {}
     19 
     20 local function array_size(len)
     21   return ceil(len / elem_bits)
     22 end
     23 index.array_size = array_size
     24 
     25 function index:clear()
     26   ffi_fill(self._buf, self.bytes)
     27   return self
     28 end
     29 
     30 function index:fill()
     31   ffi_fill(self._buf, self.bytes, 0xff)
     32   return self
     33 end
     34 
     35 function index:get(i)
     36   i = enum_to_int(self._enum, i)
     37   if i < 0 or i >= self.length then return false end
     38   return band(rshift(self._buf[i / elem_bits], i % elem_bits), 1) ~= 0
     39 end
     40 mt.base_getter = index.get
     41 
     42 function index:set(i, val)
     43   i = enum_to_int(self._enum, i)
     44   if i < 0 or i >= self.length then error("Index out of range") end
     45   local idx = i / elem_bits
     46   local bit = lshift(1ULL, i % elem_bits)
     47   local buf = self._buf
     48   if val then
     49     buf[idx] = bor(buf[idx], bit)
     50   else
     51     buf[idx] = band(buf[idx], bnot(bit))
     52   end
     53   return self
     54 end
     55 mt.base_setter = index.set
     56 
     57 -- poor man's macro processor
     58 local function iter_func(shit)
     59   local str = [[
     60 local enum_to_int, bit, elem_bits = ...
     61 local band, rshift = bit.band, bit.rshift
     62 local function func(self, i)
     63   i = enum_to_int(self._enum, i)
     64   while true do
     65     i = i+1
     66     if i >= self.length then return end
     67 
     68     local name = self._enum[i]
     69     local val = band(rshift(self._buf[i / elem_bits], i % elem_bits), 1) ~= 0
     70     <shit>
     71   end
     72 end
     73 return function(self) return func, self, -1 end
     74 ]]
     75   return assert(loadstring(str:gsub("<shit>", shit)))(enum_to_int, bit, elem_bits)
     76 end
     77 
     78 index.int_pairs = iter_func("if name or val then return i, val end")
     79 index.str_pairs = iter_func("if name or val then return name or i, val end")
     80 index.i_members = iter_func("if val then return i end")
     81 index.str_members = iter_func("if val then return name or i end")
     82 
     83 function index:tostring()
     84   local res = {}
     85   for m in self:str_members() do res[#res+1] = m end
     86   local raw = {}
     87   for i=1,ceil(self.length / elem_bits) do
     88     raw[i] = string.format("%#0x", self._buf[i-1])
     89   end
     90   return "["..table_concat(res, ", ").."] ("..table.concat(raw, ", ")..")"
     91 end
     92 mt.__tostring = index.tostring
     93 
     94 local function from_buf(enum, buf, len)
     95   buf = ffi_cast(ulongp, buf)
     96   local bs = elem_bytes * ceil(len / elem_bits)
     97   return setmetatable({_enum=enum, _buf=buf, length=len, bytes=bs}, mt)
     98 end
     99 index.from_buf = from_buf
    100 
    101 function index.new_for_ioctl(enum, len)
    102   local buf = ulong_ary(array_size(len))
    103   local x = from_buf(enum, buf, len)
    104   return x, buf, ffi_sizeof(buf)
    105 end
    106 
    107 mth.add_index_methods(mt, index)
    108 return setmetatable({}, mt)