Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- --[[
- BitBuffer
- read/write mode is determined by whether a string is passed(if string passed then it's in read mode)
- -you can switch modes by setting buffer.mode='read'or'write'
- Methods are nice bc you don't have to prepend read/write, the version corresponding to the mode is automatically used
- Internally buffers are stored as base 2 arrays(maybe improve in future)
- dump is base 256 string
- DataStore outputs optimal(NOT OPTIMAL, NEEDS IMPROVEMENT)datastore saving string(bc not all chars save in datastore)
- To see how chars are stored in datastore run this code: for i=1,255 do print(i,_G.http:JSONEncode{string.char(i)})end
- No way to know when buffer is done reading so you will need to manually store auxiliary info to keep track
- MSB
- strings store length internally(AVOID THEM WHENEVER POSSIBLE!!!)
- double is the equivalent of lua number
- long and uLong only store up to 2^53 (save you space) because lua can only reach that high so any more precision would be wasteful
- float&ufloat support inf,-inf,nan,and subnormals
- --]]
- local md={}
- md.__index=md
- local chars={}--0 indexed
- for i=0,255 do
- chars[i]=string.char(i)
- chars[chars[i]]=i
- end
- do
- local ofst=string.byte'a'
- function md:alphanum(c)--one character [a-z0-9]; useful for JobId
- if self.mode=='read'then
- local n=self:uhexad()
- if n>9 then
- return string.char(ofst+n-9)
- else
- return n..''
- end
- else
- assert(#c==1)
- local n=tonumber(c)
- return n and self:uhexad(n)or self:uhexad(string.byte(c)-ofst+10)
- end
- end
- end
- function md:string(s)--0-127(probably handles most cases)
- if self.mode=='read'then
- local len=self:uint()*7--more than enough: (' '):rep(2^30)=>'not enough memory'
- local p=self.p
- local t={}
- local l=1
- local x=0
- for i=1,len do
- x=x*2+self[p+i]
- if i%7==0 then
- t[l]=chars[x]
- x=0
- l=l+1
- end
- end
- self.p=p+len
- return table.concat(t)
- else
- local len=#s
- self:uint(len)
- local n=self.n
- for i=1,len do
- local x=chars[s:sub(i,i)]
- for i=7,1,-1 do
- self[n+i]=x%2
- x=(x-x%2)/2
- end
- n=n+7
- end
- self.n=n
- return self
- end
- end
- function md:string256(s)
- if self.mode=='read'then
- local len=self:uint()*8--more than enough: (' '):rep(2^30)=>'not enough memory'
- local p=self.p
- local t={}
- local l=1
- local x=0
- for i=1,len do
- x=x*2+self[p+i]
- if i%8==0 then
- t[l]=chars[x]
- x=0
- l=l+1
- end
- end
- self.p=p+len
- return table.concat(t)
- else
- local len=#s
- self:uint(len)
- local n=self.n
- for i=1,len do
- local x=chars[s:sub(i,i)]
- for i=8,1,-1 do
- self[n+i]=x%2
- x=(x-x%2)/2
- end
- n=n+8
- end
- self.n=n
- return self
- end
- end
- function md:unsigned(w,v)--[0,2^width-1]
- if self.mode=='read'then
- v=0
- local p=self.p
- for i=p+1,p+w do
- v=v*2+self[i]
- end
- self.p=p+w
- return v
- else--width,val
- local n=self.n
- for i=n+w,n+1,-1 do
- self[i]=v%2
- v=(v-v%2)/2
- end
- self.n=n+w
- return self
- end
- end
- function md:signed(w,v)--[-2^(width-1)-1,2^(width-1)]twos complement to get extra Value
- if self.mode=='read'then
- v=self:unsigned(w)
- return v>2^(w-1)and v-2^w or v
- else
- return self:unsigned(w,v<0 and v+2^w or v)
- end
- end
- function md:bool(v)
- if self.mode=='read'then
- return self:unsigned(1)==1
- else
- return self:unsigned(1,v and 1 or 0)
- end
- end
- --for more names see https://en.wikipedia.org/wiki/Units_of_information#Obsolete_and_unusual_units
- function md:dibit(v)return self:signed(2,v)end--(-2,2]
- function md:nibble(v)return self:signed(4,v)end--(-8,8]
- function md:hexad(v)return self:signed(6,v)end--(-32,32]
- function md:byte(v)return self:signed(8,v)end--(-128,128]
- function md:short(v)return self:signed(16,v)end--(-32768,32768]
- function md:int(v)return self:signed(32,v)end--(-2147483648,2147483648]
- function md:long(v)return self:signed(54,v)end--lua can only store up to 2^53: (-9007199254740992,9007199254740992]
- function md:udibit(v)return self:unsigned(2,v)end--[0,4)
- function md:unibble(v)return self:unsigned(4,v)end--[0,16)
- function md:uhexad(v)return self:signed(6,v)end--[0,64)
- function md:ubyte(v)return self:unsigned(8,v)end--[0,256)
- function md:ushort(v)return self:unsigned(16,v)end--[0,65536)
- function md:uint(v)return self:unsigned(32,v)end--[0,4294967296)
- function md:ulong(v)return self:unsigned(53,v)end--lua can only store up to 2^53: [0,9007199254740992)
- function md:ufloat(wfrac,wexp,v)--the sign bit is saved,no extra precision is added
- --https://stackoverflow.com/questions/7644699/how-are-floating-point-numbers-are-stored-in-memory
- local bias=2^(wexp-1)-1
- if self.mode=='read'then
- local frac=self:unsigned(wfrac)
- local exp=self:unsigned(wexp)
- return exp==0 and(frac==0 and 0 or frac*2^(1-bias-wfrac))or exp==2^wexp-1 and(frac==0 and 1/0 or 0/0)or 2^(exp-bias)*(frac/2^wfrac+1)
- else
- local frac,exp=math.frexp(v)
- if v==0 then
- self:unsigned(wfrac,0)
- self:unsigned(wexp,0)
- elseif v==1/0 then
- self:unsigned(wfrac,0)
- self:unsigned(wexp,2^wexp-1)
- elseif v~=v then
- self:unsigned(wfrac,1)
- self:unsigned(wexp,2^wexp-1)
- elseif exp+bias<=1 then--subnormal: https://github.com/ToxicFrog/vstruct/blob/master/io/f.lua
- frac=frac*2^(wfrac+exp+bias-1)
- self:unsigned(wfrac,frac-frac%1)
- self:unsigned(wexp,0)
- else
- frac=(frac-.5)*2^(wfrac+1)+.5
- self:unsigned(wfrac,frac-frac%1)
- self:unsigned(wexp,exp+bias-1)
- end
- return self
- end
- end
- function md:float(wfrac,wexp,v)
- if self.mode=='read'then
- return(self:bool()and-1 or 1)*self:ufloat(wfrac,wexp)
- else
- local neg=v<0 or v==0 and 1/v<0
- self:bool(neg)--because -0 is different from 0
- return self:ufloat(wfrac,wexp,neg and-v or v)
- end
- end
- --https://stackoverflow.com/questions/872544/
- function md:half(v)return self:float(10,5,v)end
- function md:single(v)return self:float(23,8,v)end
- function md:double(v)return self:float(52,11,v)end
- function md:uhalf(v)return self:ufloat(10,5,v)end
- function md:usingle(v)return self:ufloat(23,8,v)end
- function md:udouble(v)return self:ufloat(52,11,v)end
- function md:dump()
- local n=self.n
- local t={}
- local l=1
- local x=0
- for i=1,n+-n%8 do--pad to get base 256
- x=x*2+(self[i]or 0)
- if i%8==0 then
- t[l]=chars[x]
- x=0
- l=l+1
- end
- end
- return table.concat(t)
- end
- function md:base64()
- if type(self)=='table'then
- local n=self.n
- local t={}
- local l=1
- local x=0
- for i=1,n+-n%6 do
- x=x*2+(self[i]or 0)
- if i%6==0 then
- t[l]=chars[x+64]--offset for ds
- x=0
- l=l+1
- end
- end
- return table.concat(t)
- else--reading base64
- local s=self
- local n=0
- local self={}
- for i=1,#s do
- local x=chars[s:sub(i,i)]-64
- for i=6,1,-1 do
- self[n+i]=x%2
- x=(x-x%2)/2
- end
- n=n+6
- end
- self.p=0--last location read from
- self.n=n
- self.mode='read'
- return setmetatable(self,md)
- end
- end
- do
- local offset=32
- local base=96
- local digs=math.floor(math.log(2^53)/math.log(base))
- local bdigs=math.floor(math.log(base^digs)/math.log(2))
- function md:ds()--datastore friendly chars
- if type(self)=='table'then
- local n=self.n
- local t={}
- local l=0
- local x=0
- for i=1,n+-n%bdigs do
- x=x*2+(self[i]or 0)
- if i%bdigs==0 then
- for j=digs,1,-1 do
- local d=x%base
- x=(x-d)/base
- t[l+j]=chars[d+offset]
- end
- l=l+digs
- end
- end
- return table.concat(t)
- else
- local s=self
- local n=0
- local self={}
- local x=0
- for i=1,#s do
- x=x*base+chars[s:sub(i,i)]-offset
- if i%digs==0 then
- for j=bdigs,1,-1 do
- local d=x%2
- x=(x-d)/2
- self[n+j]=d
- end
- n=n+bdigs
- end
- end
- self.p=0--last location read from
- self.n=n
- self.mode='read'
- return setmetatable(self,md)
- end
- end
- end
- function md.new(s)
- if s then--to be read from
- local n=0
- local self={}
- for i=1,#s do
- local x=chars[s:sub(i,i)]
- for i=8,1,-1 do
- self[n+i]=x%2
- x=(x-x%2)/2
- end
- n=n+8
- end
- self.p=0--last location read from
- self.n=n
- self.mode='read'
- return setmetatable(self,md)
- else--to be written to
- return setmetatable({p=0,n=0,mode='write',},md)
- end
- end
- return md
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement