add new Bytearray class
This commit is contained in:
parent
7a7ac54b5d
commit
4260742d6e
141
res/modules/internal/bytearray.lua
Normal file
141
res/modules/internal/bytearray.lua
Normal file
@ -0,0 +1,141 @@
|
||||
local MIN_CAPACITY = 8
|
||||
local _type = type
|
||||
local FFI = ffi
|
||||
|
||||
FFI.cdef[[
|
||||
void* malloc(size_t);
|
||||
void free(void*);
|
||||
typedef struct {
|
||||
unsigned char* bytes;
|
||||
int size;
|
||||
int capacity;
|
||||
} bytearray_t;
|
||||
]]
|
||||
|
||||
local malloc = FFI.C.malloc
|
||||
local free = FFI.C.free
|
||||
|
||||
local function grow_buffer(self, elems)
|
||||
local new_capacity = math.ceil(self.capacity / 0.75 + elems)
|
||||
local prev = self.bytes
|
||||
self.bytes = malloc(new_capacity)
|
||||
FFI.copy(self.bytes, prev, self.size)
|
||||
self.capacity = new_capacity
|
||||
free(prev)
|
||||
end
|
||||
|
||||
local function count_elements(b)
|
||||
local elems = 1
|
||||
if _type(b) ~= "number" then
|
||||
elems = #b
|
||||
end
|
||||
return elems
|
||||
end
|
||||
|
||||
local bytearray_methods = {
|
||||
append=function(self, b)
|
||||
local elems = count_elements(b)
|
||||
if self.size + elems > self.capacity then
|
||||
grow_buffer(self, elems)
|
||||
end
|
||||
if _type(b) == "number" then
|
||||
self.bytes[self.size] = b
|
||||
else
|
||||
for i=1, #b do
|
||||
self.bytes[self.size + i - 1] = b[i]
|
||||
end
|
||||
end
|
||||
self.size = self.size + elems
|
||||
end,
|
||||
insert=function(self, index, b)
|
||||
local elems = count_elements(b)
|
||||
if self.size + elems >= self.capacity then
|
||||
grow_buffer(self, elems)
|
||||
end
|
||||
if _type(b) == "number" then
|
||||
self.bytes[index] = b
|
||||
else
|
||||
for i=1, #b do
|
||||
self.bytes[index + i - 1] = b[i]
|
||||
end
|
||||
end
|
||||
self.size = self.size + elems
|
||||
end,
|
||||
remove=function(self, index, elems)
|
||||
if index <= 0 or index > self.size then
|
||||
return
|
||||
end
|
||||
if elems == nil then
|
||||
elems = 1
|
||||
end
|
||||
if index + elems > self.size then
|
||||
elems = self.size - index + 1
|
||||
end
|
||||
for i=index, self.size - elems do
|
||||
self.bytes[i] = self.bytes[i + elems]
|
||||
end
|
||||
self.size = self.size - elems
|
||||
end,
|
||||
clear=function(self)
|
||||
self.size = 0
|
||||
end,
|
||||
reserve=function(self, new_capacity)
|
||||
if new_capacity <= self.capacity then
|
||||
return
|
||||
end
|
||||
local prev = self.bytes
|
||||
self.bytes = malloc(new_capacity)
|
||||
FFI.copy(self.bytes, prev, self.size)
|
||||
self.capacity = new_capacity
|
||||
free(prev)
|
||||
end,
|
||||
}
|
||||
|
||||
local bytearray_mt = {
|
||||
__index = function(self, key)
|
||||
if _type(key) == "string" then
|
||||
return bytearray_methods[key]
|
||||
end
|
||||
if key <= 0 or key > self.size then
|
||||
return
|
||||
end
|
||||
return self.bytes[key - 1]
|
||||
end,
|
||||
__newindex = function(self, key, value)
|
||||
if key <= 0 or key > self.size then
|
||||
return
|
||||
end
|
||||
self.bytes[key - 1] = value
|
||||
end,
|
||||
__tostring = function(self)
|
||||
return string.format("FFIBytearray[%s]{...}", tonumber(self.size))
|
||||
end,
|
||||
__len = function(self)
|
||||
return tonumber(self.size)
|
||||
end,
|
||||
__gc = function(self)
|
||||
free(self.bytes)
|
||||
end
|
||||
}
|
||||
|
||||
local utf8tostring = utf8.tostring
|
||||
|
||||
function utf8.tostring(bytes)
|
||||
local type = _type(bytes)
|
||||
if type == "cdata" then
|
||||
return FFI.string(bytes.bytes, bytes.size)
|
||||
else
|
||||
return utf8tostring(bytes)
|
||||
end
|
||||
end
|
||||
|
||||
local bytearray_type = FFI.metatype("bytearray_t", bytearray_mt)
|
||||
|
||||
return function (n)
|
||||
n = n or 0
|
||||
if n < MIN_CAPACITY then
|
||||
return bytearray_type(malloc(MIN_CAPACITY), n, MIN_CAPACITY)
|
||||
else
|
||||
return bytearray_type(malloc(n), n, n)
|
||||
end
|
||||
end
|
||||
Loading…
x
Reference in New Issue
Block a user