diff --git a/polymer/eduke32/Makefile b/polymer/eduke32/Makefile index b4badc991..45ae1ee9c 100644 --- a/polymer/eduke32/Makefile +++ b/polymer/eduke32/Makefile @@ -170,7 +170,8 @@ ifneq (0,$(LUNATIC)) $(OBJ)/luaJIT_BC_lunacon.$o \ $(OBJ)/luaJIT_BC_geom.$o \ $(OBJ)/luaJIT_BC_randgen.$o \ - $(OBJ)/luaJIT_BC_stat.$o + $(OBJ)/luaJIT_BC_stat.$o \ + $(OBJ)/luaJIT_BC_bitar.$o # now, take care of having the necessary symbols (sector, wall, etc.) in the # executable no matter what the debugging level diff --git a/polymer/eduke32/source/lunatic/bitar.lua b/polymer/eduke32/source/lunatic/bitar.lua index f5eacfa9e..f92f521ea 100644 --- a/polymer/eduke32/source/lunatic/bitar.lua +++ b/polymer/eduke32/source/lunatic/bitar.lua @@ -1,33 +1,18 @@ -- "Bit array" module based on LuaJIT's BitOp. +local ffi = require "ffi" local bit = require "bit" local error = error +local assert = assert local type = type +local setmetatable=setmetatable + + module(...) --- Create new bit array. --- Returns a table p in which entries p[0] through p[floor((size+31)/32)] --- are set to an initialization value: 0 if 0 has been passed, -1 if 1 --- has been passed. -function new(size, initval) - if (type(size) ~= "number" or size < 0) then - error("bad argument #1 to newarray (must be a nonnegative number)", 2) - end - - if (initval ~= 0 and initval ~= 1) then - error("bad argument #2 to newarray (must be either 0 or 1)", 2) - end - - local p = {} - for i=0,(size+31)/32 do - p[i] = -initval - end - - return p -end -- Is bit i set in bit array ar? function isset(ar, i) @@ -45,3 +30,109 @@ function set1(ar, j) local jx = bit.rshift(j, 5) ar[jx] = bit.bor(ar[jx], bit.rol(0x00000001, j)) end + +local ops = { isset=isset, set0=set0, set1=set1 } +local mt +mt = { + __index=ops, + + -- set ops disguised as arithmetic ones... + + __mul = function(ar1, ar2) -- set intersection + assert(#ar1 == #ar2) + local p = {} + for i=0,#ar1 do + p[i] = bit.band(ar1[i], ar2[i]) + end + return setmetatable(p, mt) + end, + + __add = function(ar1, ar2) -- set union + assert(#ar1 == #ar2) + local p = {} + for i=0,#ar1 do + p[i] = bit.bor(ar1[i], ar2[i]) + end + return setmetatable(p, mt) + end, + + __sub = function(ar1, ar2) -- set difference + assert(#ar1 == #ar2) + local p = {} + for i=0,#ar1 do + p[i] = bit.band(ar1[i], bit.bnot(ar2[i])) + end + return setmetatable(p, mt) + end, + + -- serialization + __tostring = function(ar) + local maxidx=#ar + local size=maxidx+1 + + local hdr = "bitar.new('" + local ofs = #hdr + local totalstrlen = ofs+8*size+2 + local str = ffi.new("char [?]", totalstrlen) + + ffi.copy(str, hdr, ofs) + + for i=0,maxidx do + -- 'a' is ASCII 97 + for nib=0,7 do + str[ofs + 8*i + nib] = 97 + bit.band(bit.rshift(ar[i], 4*nib), 0x0000000f) + end + end + + ffi.copy(str+totalstrlen-2, "')", 2) + + return ffi.string(str, totalstrlen) + end, +} + +-- Create new bit array. +-- Returns a table p in which entries p[0] through p[floor((maxbidx+31)/32)] +-- are set to an initialization value: 0 if 0 has been passed, -1 if 1 +-- has been passed. +-- Storage: 4 bits/bit + O(1)? (per 32 bits: 64 bits key, 64 bits value) +function new(maxbidx, initval) + local p = {} + + if (type(maxbidx)=="string") then + -- string containing hex digits (a..p) given, internal + local lstr = maxbidx + + local numnibs = #lstr + assert(numnibs%8 == 0) + + local size = numnibs/8 + local maxidx = size-1 + + local str = ffi.new("char [?]", numnibs) + ffi.copy(str, lstr, numnibs) + + for i=0,maxidx do + p[i] = 0 + + for nib=0,7 do + local hexdig = str[8*i + nib] + assert(hexdig >= 97 and hexdig < 97+16) + p[i] = bit.bor(p[i], bit.lshift(hexdig-97, 4*nib)) + end + end + else + if (type(maxbidx) ~= "number" or not (maxbidx >= 0)) then + error("bad argument #1 to newarray (must be a nonnegative number)", 2) + end + + if (initval ~= 0 and initval ~= 1) then + error("bad argument #2 to newarray (must be either 0 or 1)", 2) + end + + for i=0,maxbidx/32 do + p[i] = -initval + end + end + + return setmetatable(p, mt) +end diff --git a/polymer/eduke32/source/lunatic/bittest.lua b/polymer/eduke32/source/lunatic/bittest.lua index de22b32d5..0130c4541 100755 --- a/polymer/eduke32/source/lunatic/bittest.lua +++ b/polymer/eduke32/source/lunatic/bittest.lua @@ -4,14 +4,14 @@ local string = require "string" -local getticks - local bit = require("bit") local bitar = require "bitar" local print = print local tonumber = tonumber +local getticks + if (string.dump) then -- stand-alone local os = require "os" @@ -27,8 +27,6 @@ end -- based on example from http://bitop.luajit.org/api.html -local isset, set0 = bitar.isset, bitar.set0 - local m = string.dump and tonumber(arg[1]) or 1e7 local ffiar_p, boundchk_p = false, false @@ -82,17 +80,35 @@ function sieve() local t = getticks() for i=2,m do - if (isset(p, i)) then + if (p:isset(i)) then count = count + 1 - for j=i+i,m,i do set0(p, j); end + for j=i+i,m,i do p:set0(j); end end end print(string.format("[%s] Found %d primes up to %d (%.02f ms)", ffiar_p and "ffi-ar"..(boundchk_p and ", bchk" or "") or "tab-ar", count, m, getticks()-t)) + + return p end if (string.dump) then - sieve() + local p = sieve() + local t = getticks() + + -- test serialization + local p2 = bitar.new(string.match(tostring(p), "'(.*)'")) + print(getticks()-t) + + for i=0,#p do + assert(p[i]==p2[i]) + end + + for i = 3,#p do + p[i] = nil + end + + print(p) + print(p-p) -- test set difference end diff --git a/polymer/eduke32/source/lunatic/defs.ilua b/polymer/eduke32/source/lunatic/defs.ilua index 461aae704..3c19a8bb0 100644 --- a/polymer/eduke32/source/lunatic/defs.ilua +++ b/polymer/eduke32/source/lunatic/defs.ilua @@ -548,6 +548,7 @@ local allowed_modules = { randgen = require("randgen"), geom = require("geom"), stat = require("stat"), + bitar = require("bitar"), } local package_loaded = {} diff --git a/polymer/eduke32/source/lunatic/dynsymlist b/polymer/eduke32/source/lunatic/dynsymlist index 94f26c96e..eec417c68 100644 --- a/polymer/eduke32/source/lunatic/dynsymlist +++ b/polymer/eduke32/source/lunatic/dynsymlist @@ -43,6 +43,7 @@ luaJIT_BC_con_lang; luaJIT_BC_geom; luaJIT_BC_randgen; luaJIT_BC_stat; +luaJIT_BC_bitar; rand_jkiss_u32; rand_jkiss_dbl;