Advertisement
Guest User

Untitled

a guest
Apr 6th, 2019
156
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 8.13 KB | None | 0 0
  1. --[[
  2.     BitBuffer
  3.    
  4.     read/write mode is determined by whether a string is passed(if string passed then it's in read mode)
  5.         -you can switch modes by setting buffer.mode='read'or'write'
  6.    
  7.     Methods are nice bc you don't have to prepend read/write, the version corresponding to the mode is automatically used
  8.    
  9.     Internally buffers are stored as base 2 arrays(maybe improve in future)
  10.     dump is base 256 string
  11.     DataStore outputs optimal(NOT OPTIMAL, NEEDS IMPROVEMENT)datastore saving string(bc not all chars save in datastore)
  12.         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
  13.     No way to know when buffer is done reading so you will need to manually store auxiliary info to keep track
  14.    
  15.     MSB
  16.    
  17.     strings store length internally(AVOID THEM WHENEVER POSSIBLE!!!)
  18.     double is the equivalent of lua number
  19.     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
  20.    
  21.     float&ufloat support inf,-inf,nan,and subnormals
  22.    
  23. --]]
  24.  
  25. local md={}
  26. md.__index=md
  27.  
  28. local chars={}--0 indexed
  29. for i=0,255 do
  30.     chars[i]=string.char(i)
  31.     chars[chars[i]]=i
  32. end
  33.  
  34. do
  35.     local ofst=string.byte'a'
  36.     function md:alphanum(c)--one character [a-z0-9]; useful for JobId
  37.         if self.mode=='read'then
  38.             local n=self:uhexad()
  39.             if n>9 then
  40.                 return string.char(ofst+n-9)
  41.             else
  42.                 return n..''
  43.             end
  44.         else
  45.             assert(#c==1)
  46.             local n=tonumber(c)
  47.             return n and self:uhexad(n)or self:uhexad(string.byte(c)-ofst+10)
  48.         end
  49.     end
  50. end
  51.  
  52. function md:string(s)--0-127(probably handles most cases)
  53.     if self.mode=='read'then
  54.         local len=self:uint()*7--more than enough: (' '):rep(2^30)=>'not enough memory'
  55.         local p=self.p
  56.         local t={}
  57.         local l=1
  58.         local x=0
  59.         for i=1,len do
  60.             x=x*2+self[p+i]
  61.             if i%7==0 then
  62.                 t[l]=chars[x]
  63.                 x=0
  64.                 l=l+1
  65.             end
  66.         end
  67.         self.p=p+len
  68.         return table.concat(t)
  69.     else
  70.         local len=#s
  71.         self:uint(len)
  72.         local n=self.n
  73.         for i=1,len do
  74.             local x=chars[s:sub(i,i)]
  75.             for i=7,1,-1 do
  76.                 self[n+i]=x%2
  77.                 x=(x-x%2)/2
  78.             end
  79.             n=n+7
  80.         end
  81.         self.n=n
  82.         return self
  83.     end
  84. end
  85. function md:string256(s)
  86.     if self.mode=='read'then
  87.         local len=self:uint()*8--more than enough: (' '):rep(2^30)=>'not enough memory'
  88.         local p=self.p
  89.         local t={}
  90.         local l=1
  91.         local x=0
  92.         for i=1,len do
  93.             x=x*2+self[p+i]
  94.             if i%8==0 then
  95.                 t[l]=chars[x]
  96.                 x=0
  97.                 l=l+1
  98.             end
  99.         end
  100.         self.p=p+len
  101.         return table.concat(t)
  102.     else
  103.         local len=#s
  104.         self:uint(len)
  105.         local n=self.n
  106.         for i=1,len do
  107.             local x=chars[s:sub(i,i)]
  108.             for i=8,1,-1 do
  109.                 self[n+i]=x%2
  110.                 x=(x-x%2)/2
  111.             end
  112.             n=n+8
  113.         end
  114.         self.n=n
  115.         return self
  116.     end
  117. end
  118. function md:unsigned(w,v)--[0,2^width-1]
  119.     if self.mode=='read'then
  120.         v=0
  121.         local p=self.p
  122.         for i=p+1,p+w do
  123.             v=v*2+self[i]
  124.         end
  125.         self.p=p+w
  126.         return v
  127.     else--width,val
  128.         local n=self.n
  129.         for i=n+w,n+1,-1 do
  130.             self[i]=v%2
  131.             v=(v-v%2)/2
  132.         end
  133.         self.n=n+w
  134.         return self
  135.     end
  136. end
  137. function md:signed(w,v)--[-2^(width-1)-1,2^(width-1)]twos complement to get extra Value
  138.     if self.mode=='read'then
  139.         v=self:unsigned(w)
  140.         return v>2^(w-1)and v-2^w or v
  141.     else
  142.         return self:unsigned(w,v<0 and v+2^w or v)
  143.     end
  144. end
  145. function md:bool(v)
  146.     if self.mode=='read'then
  147.         return self:unsigned(1)==1
  148.     else
  149.         return self:unsigned(1,v and 1 or 0)
  150.     end
  151. end
  152. --for more names see https://en.wikipedia.org/wiki/Units_of_information#Obsolete_and_unusual_units
  153. function md:dibit(v)return self:signed(2,v)end--(-2,2]
  154. function md:nibble(v)return self:signed(4,v)end--(-8,8]
  155. function md:hexad(v)return self:signed(6,v)end--(-32,32]
  156. function md:byte(v)return self:signed(8,v)end--(-128,128]
  157. function md:short(v)return self:signed(16,v)end--(-32768,32768]
  158. function md:int(v)return self:signed(32,v)end--(-2147483648,2147483648]
  159. function md:long(v)return self:signed(54,v)end--lua can only store up to 2^53: (-9007199254740992,9007199254740992]
  160. function md:udibit(v)return self:unsigned(2,v)end--[0,4)
  161. function md:unibble(v)return self:unsigned(4,v)end--[0,16)
  162. function md:uhexad(v)return self:signed(6,v)end--[0,64)
  163. function md:ubyte(v)return self:unsigned(8,v)end--[0,256)
  164. function md:ushort(v)return self:unsigned(16,v)end--[0,65536)
  165. function md:uint(v)return self:unsigned(32,v)end--[0,4294967296)
  166. function md:ulong(v)return self:unsigned(53,v)end--lua can only store up to 2^53: [0,9007199254740992)
  167.  
  168. function md:ufloat(wfrac,wexp,v)--the sign bit is saved,no extra precision is added
  169.     --https://stackoverflow.com/questions/7644699/how-are-floating-point-numbers-are-stored-in-memory
  170.     local bias=2^(wexp-1)-1
  171.     if self.mode=='read'then
  172.         local frac=self:unsigned(wfrac)
  173.         local exp=self:unsigned(wexp)
  174.         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)
  175.     else
  176.         local frac,exp=math.frexp(v)
  177.         if v==0 then
  178.             self:unsigned(wfrac,0)
  179.             self:unsigned(wexp,0)
  180.         elseif v==1/0 then
  181.             self:unsigned(wfrac,0)
  182.             self:unsigned(wexp,2^wexp-1)
  183.         elseif v~=v then
  184.             self:unsigned(wfrac,1)
  185.             self:unsigned(wexp,2^wexp-1)
  186.         elseif exp+bias<=1 then--subnormal: https://github.com/ToxicFrog/vstruct/blob/master/io/f.lua
  187.             frac=frac*2^(wfrac+exp+bias-1)
  188.             self:unsigned(wfrac,frac-frac%1)
  189.             self:unsigned(wexp,0)
  190.         else
  191.             frac=(frac-.5)*2^(wfrac+1)+.5
  192.             self:unsigned(wfrac,frac-frac%1)
  193.             self:unsigned(wexp,exp+bias-1)
  194.         end
  195.         return self
  196.     end
  197. end
  198. function md:float(wfrac,wexp,v)
  199.     if self.mode=='read'then
  200.         return(self:bool()and-1 or 1)*self:ufloat(wfrac,wexp)
  201.     else
  202.         local neg=v<0 or v==0 and 1/v<0
  203.         self:bool(neg)--because -0 is different from 0
  204.         return self:ufloat(wfrac,wexp,neg and-v or v)
  205.     end
  206. end
  207. --https://stackoverflow.com/questions/872544/
  208. function md:half(v)return self:float(10,5,v)end
  209. function md:single(v)return self:float(23,8,v)end
  210. function md:double(v)return self:float(52,11,v)end
  211. function md:uhalf(v)return self:ufloat(10,5,v)end
  212. function md:usingle(v)return self:ufloat(23,8,v)end
  213. function md:udouble(v)return self:ufloat(52,11,v)end
  214.  
  215. function md:dump()
  216.     local n=self.n
  217.     local t={}
  218.     local l=1
  219.     local x=0
  220.     for i=1,n+-n%8 do--pad to get base 256
  221.         x=x*2+(self[i]or 0)
  222.         if i%8==0 then
  223.             t[l]=chars[x]
  224.             x=0
  225.             l=l+1
  226.         end
  227.     end
  228.     return table.concat(t)
  229. end
  230. function md:base64()
  231.     if type(self)=='table'then
  232.         local n=self.n
  233.         local t={}
  234.         local l=1
  235.         local x=0
  236.         for i=1,n+-n%6 do
  237.             x=x*2+(self[i]or 0)
  238.             if i%6==0 then
  239.                 t[l]=chars[x+64]--offset for ds
  240.                 x=0
  241.                 l=l+1
  242.             end
  243.         end
  244.         return table.concat(t)
  245.     else--reading base64
  246.         local s=self
  247.         local n=0
  248.         local self={}
  249.         for i=1,#s do
  250.             local x=chars[s:sub(i,i)]-64
  251.             for i=6,1,-1 do
  252.                 self[n+i]=x%2
  253.                 x=(x-x%2)/2
  254.             end
  255.             n=n+6
  256.         end
  257.         self.p=0--last location read from
  258.         self.n=n
  259.         self.mode='read'
  260.         return setmetatable(self,md)
  261.     end
  262. end
  263. do
  264.     local offset=32
  265.     local base=96
  266.     local digs=math.floor(math.log(2^53)/math.log(base))
  267.     local bdigs=math.floor(math.log(base^digs)/math.log(2))
  268.     function md:ds()--datastore friendly chars
  269.         if type(self)=='table'then
  270.             local n=self.n
  271.             local t={}
  272.             local l=0
  273.             local x=0
  274.             for i=1,n+-n%bdigs do
  275.                 x=x*2+(self[i]or 0)
  276.                 if i%bdigs==0 then
  277.                     for j=digs,1,-1 do
  278.                         local d=x%base
  279.                         x=(x-d)/base
  280.                         t[l+j]=chars[d+offset]
  281.                     end
  282.                     l=l+digs
  283.                 end
  284.             end
  285.             return table.concat(t)
  286.         else
  287.             local s=self
  288.             local n=0
  289.             local self={}
  290.             local x=0
  291.             for i=1,#s do
  292.                 x=x*base+chars[s:sub(i,i)]-offset
  293.                 if i%digs==0 then
  294.                     for j=bdigs,1,-1 do
  295.                         local d=x%2
  296.                         x=(x-d)/2
  297.                         self[n+j]=d
  298.                     end
  299.                     n=n+bdigs
  300.                 end
  301.             end
  302.             self.p=0--last location read from
  303.             self.n=n
  304.             self.mode='read'
  305.             return setmetatable(self,md)
  306.         end
  307.     end
  308. end
  309. function md.new(s)
  310.     if s then--to be read from
  311.         local n=0
  312.         local self={}
  313.         for i=1,#s do
  314.             local x=chars[s:sub(i,i)]
  315.             for i=8,1,-1 do
  316.                 self[n+i]=x%2
  317.                 x=(x-x%2)/2
  318.             end
  319.             n=n+8
  320.         end
  321.         self.p=0--last location read from
  322.         self.n=n
  323.         self.mode='read'
  324.         return setmetatable(self,md)
  325.     else--to be written to
  326.         return setmetatable({p=0,n=0,mode='write',},md)
  327.     end
  328. end
  329.  
  330. return md
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement