Austin Schuh | e89fa2d | 2019-08-14 20:24:23 -0700 | [diff] [blame^] | 1 | local m = {} -- the module table |
| 2 | |
| 3 | local mt = {} -- the module metatable |
| 4 | |
| 5 | -- given a binary array, set a metamethod to return its length |
| 6 | -- (e.g., #binaryArray, calls this) |
| 7 | function mt:__len() |
| 8 | return self.size |
| 9 | end |
| 10 | |
| 11 | -- Create a new binary array of an initial size |
| 12 | function m.New(sizeOrString) |
| 13 | -- the array storage itself |
| 14 | local o = {} |
| 15 | |
| 16 | if type(sizeOrString) == "string" then |
| 17 | o.str = sizeOrString |
| 18 | o.size = #sizeOrString |
| 19 | elseif type(sizeOrString) == "number" then |
| 20 | o.data = {} |
| 21 | o.size = sizeOrString |
| 22 | else |
| 23 | error("Expect a integer size value or string to construct a binary array") |
| 24 | end |
| 25 | -- set the inheritance |
| 26 | setmetatable(o, {__index = mt, __len = mt.__len}) |
| 27 | return o |
| 28 | end |
| 29 | |
| 30 | -- Get a slice of the binary array from start to end position |
| 31 | function mt:Slice(startPos, endPos) |
| 32 | startPos = startPos or 0 |
| 33 | endPos = endPos or self.size |
| 34 | local d = self.data |
| 35 | if d then |
| 36 | -- if the self.data is defined, we are building the buffer |
| 37 | -- in a Lua table |
| 38 | |
| 39 | -- new table to store the slice components |
| 40 | local b = {} |
| 41 | |
| 42 | -- starting with the startPos, put all |
| 43 | -- values into the new table to be concat later |
| 44 | -- updated the startPos based on the size of the |
| 45 | -- value |
| 46 | while startPos < endPos do |
| 47 | local v = d[startPos] or '/0' |
| 48 | table.insert(b, v) |
| 49 | startPos = startPos + #v |
| 50 | end |
| 51 | |
| 52 | -- combine the table of strings into one string |
| 53 | -- this is faster than doing a bunch of concats by themselves |
| 54 | return table.concat(b) |
| 55 | else |
| 56 | -- n.b start/endPos are 0-based incoming, so need to convert |
| 57 | -- correctly. in python a slice includes start -> end - 1 |
| 58 | return self.str:sub(startPos+1, endPos) |
| 59 | end |
| 60 | end |
| 61 | |
| 62 | -- Grow the binary array to a new size, placing the exisiting data |
| 63 | -- at then end of the new array |
| 64 | function mt:Grow(newsize) |
| 65 | -- the new table to store the data |
| 66 | local newT = {} |
| 67 | |
| 68 | -- the offset to be applied to existing entries |
| 69 | local offset = newsize - self.size |
| 70 | |
| 71 | -- loop over all the current entries and |
| 72 | -- add them to the new table at the correct |
| 73 | -- offset location |
| 74 | local d = self.data |
| 75 | for i,data in pairs(d) do |
| 76 | newT[i + offset] = data |
| 77 | end |
| 78 | |
| 79 | -- update this storage with the new table and size |
| 80 | self.data = newT |
| 81 | self.size = newsize |
| 82 | end |
| 83 | |
| 84 | -- memorization for padding strings |
| 85 | local pads = {} |
| 86 | |
| 87 | -- pad the binary with n \0 bytes at the starting position |
| 88 | function mt:Pad(n, startPos) |
| 89 | -- use memorization to avoid creating a bunch of strings |
| 90 | -- all the time |
| 91 | local s = pads[n] |
| 92 | if not s then |
| 93 | s = string.rep('\0', n) |
| 94 | pads[n] = s |
| 95 | end |
| 96 | |
| 97 | -- store the padding string at the start position in the |
| 98 | -- Lua table |
| 99 | self.data[startPos] = s |
| 100 | end |
| 101 | |
| 102 | -- Sets the binary array value at the specified position |
| 103 | function mt:Set(value, position) |
| 104 | self.data[position] = value |
| 105 | end |
| 106 | |
| 107 | -- locals for slightly faster access |
| 108 | local sunpack = string.unpack |
| 109 | local spack = string.pack |
| 110 | |
| 111 | -- Pack the data into a binary representation |
| 112 | function m.Pack(fmt, ...) |
| 113 | return spack(fmt, ...) |
| 114 | end |
| 115 | |
| 116 | -- Unpack the data from a binary representation in |
| 117 | -- a Lua value |
| 118 | function m.Unpack(fmt, s, pos) |
| 119 | return sunpack(fmt, s.str, pos + 1) |
| 120 | end |
| 121 | |
| 122 | -- Return the binary array module |
| 123 | return m |