Merge pull request #508 from MihailRis/bytearray-upgrade
Bytearray upgrade
This commit is contained in:
@@ -0,0 +1,215 @@
|
||||
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 trim_buffer(self)
|
||||
if self.size == self.capacity then
|
||||
return
|
||||
end
|
||||
local size = self.size
|
||||
local prev = self.bytes
|
||||
self.bytes = malloc(size)
|
||||
FFI.copy(self.bytes, prev, self.size)
|
||||
self.capacity = size
|
||||
free(prev)
|
||||
end
|
||||
|
||||
local function count_elements(b)
|
||||
local elems = 1
|
||||
if _type(b) ~= "number" then
|
||||
elems = #b
|
||||
end
|
||||
return elems
|
||||
end
|
||||
|
||||
local function append(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
|
||||
|
||||
local function insert(self, index, b)
|
||||
if b == nil then
|
||||
b = index
|
||||
index = self.size + 1
|
||||
end
|
||||
if index <= 0 or index > self.size + 1 then
|
||||
return
|
||||
end
|
||||
local elems = count_elements(b)
|
||||
if self.size + elems > self.capacity then
|
||||
grow_buffer(self, elems)
|
||||
end
|
||||
for i=self.size, index - 1, -1 do
|
||||
self.bytes[i + elems] = self.bytes[i]
|
||||
end
|
||||
if _type(b) == "number" then
|
||||
self.bytes[index - 1] = b
|
||||
else
|
||||
for i=1, #b do
|
||||
self.bytes[index + i - 2] = b[i]
|
||||
end
|
||||
end
|
||||
self.size = self.size + elems
|
||||
end
|
||||
|
||||
local function remove(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 - 1, self.size - elems - 1 do
|
||||
self.bytes[i] = self.bytes[i + elems]
|
||||
end
|
||||
self.size = self.size - elems
|
||||
end
|
||||
|
||||
local function clear(self)
|
||||
self.size = 0
|
||||
end
|
||||
|
||||
local function reserve(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 function get_capacity(self)
|
||||
return self.capacity
|
||||
end
|
||||
|
||||
local bytearray_methods = {
|
||||
append=append,
|
||||
insert=insert,
|
||||
remove=remove,
|
||||
trim=trim_buffer,
|
||||
clear=clear,
|
||||
reserve=reserve,
|
||||
get_capacity=get_capacity,
|
||||
}
|
||||
|
||||
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 == self.size + 1 then
|
||||
return append(self, value)
|
||||
elseif 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,
|
||||
__ipairs = function(self)
|
||||
local i = 0
|
||||
return function()
|
||||
i = i + 1
|
||||
if i <= self.size then
|
||||
return i, self.bytes[i - 1]
|
||||
end
|
||||
end
|
||||
end
|
||||
}
|
||||
|
||||
local bytearray_type = FFI.metatype("bytearray_t", bytearray_mt)
|
||||
|
||||
local FFIBytearray = {
|
||||
__call = function (n)
|
||||
local t = type(n)
|
||||
if t == "string" then
|
||||
local buffer = malloc(#n)
|
||||
FFI.copy(buffer, n, #n)
|
||||
return bytearray_type(buffer, #n, #n)
|
||||
elseif t == "table" then
|
||||
local capacity = math.max(#n, MIN_CAPACITY)
|
||||
local buffer = malloc(capacity)
|
||||
for i=1,#n do
|
||||
buffer[i - 1] = n[i]
|
||||
end
|
||||
return bytearray_type(buffer, #n, capacity)
|
||||
end
|
||||
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,
|
||||
}
|
||||
table.merge(FFIBytearray, bytearray_methods)
|
||||
|
||||
local function FFIBytearray_as_string(bytes)
|
||||
local t = type(bytes)
|
||||
if t == "cdata" then
|
||||
return FFI.string(bytes.bytes, bytes.size)
|
||||
elseif t == "table" then
|
||||
local buffer = FFI.new("unsigned char[?]", #bytes)
|
||||
for i=1, #bytes do
|
||||
buffer[i - 1] = bytes[i]
|
||||
end
|
||||
return FFI.string(buffer, #bytes)
|
||||
else
|
||||
error("Bytearray expected, got "..type(bytes))
|
||||
end
|
||||
end
|
||||
|
||||
return {
|
||||
FFIBytearray = setmetatable(FFIBytearray, FFIBytearray),
|
||||
FFIBytearray_as_string = FFIBytearray_as_string
|
||||
}
|
||||
@@ -263,6 +263,11 @@ entities.get_all = function(uids)
|
||||
return stdcomp.get_all(uids)
|
||||
end
|
||||
end
|
||||
local bytearray = require "core:internal/bytearray"
|
||||
Bytearray = bytearray.FFIBytearray
|
||||
Bytearray_as_string = bytearray.FFIBytearray_as_string
|
||||
Bytearray_construct = Bytearray.__call
|
||||
ffi = nil
|
||||
|
||||
math.randomseed(time.uptime() * 1536227939)
|
||||
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
local _ffi = ffi
|
||||
ffi = nil
|
||||
|
||||
-- Lua has no parallelizm, also _set_data does not call any lua functions so
|
||||
-- may be reused one global ffi buffer per lua_State
|
||||
local canvas_ffi_buffer
|
||||
@@ -8,14 +5,14 @@ local canvas_ffi_buffer_size = 0
|
||||
|
||||
function __vc_Canvas_set_data(self, data)
|
||||
if type(data) == "cdata" then
|
||||
self:_set_data(tostring(_ffi.cast("uintptr_t", data)))
|
||||
self:_set_data(tostring(ffi.cast("uintptr_t", data)))
|
||||
end
|
||||
local width = self.width
|
||||
local height = self.height
|
||||
|
||||
local size = width * height * 4
|
||||
if size > canvas_ffi_buffer_size then
|
||||
canvas_ffi_buffer = _ffi.new(
|
||||
canvas_ffi_buffer = ffi.new(
|
||||
string.format("unsigned char[%s]", size)
|
||||
)
|
||||
canvas_ffi_buffer_size = size
|
||||
@@ -23,7 +20,7 @@ function __vc_Canvas_set_data(self, data)
|
||||
for i=0, size - 1 do
|
||||
canvas_ffi_buffer[i] = data[i + 1]
|
||||
end
|
||||
self:_set_data(tostring(_ffi.cast("uintptr_t", canvas_ffi_buffer)))
|
||||
self:_set_data(tostring(ffi.cast("uintptr_t", canvas_ffi_buffer)))
|
||||
end
|
||||
|
||||
function crc32(bytes, chksum)
|
||||
@@ -31,14 +28,14 @@ function crc32(bytes, chksum)
|
||||
|
||||
local length = #bytes
|
||||
if type(bytes) == "table" then
|
||||
local buffer_len = _ffi.new('int[1]', length)
|
||||
local buffer = _ffi.new(
|
||||
local buffer_len = ffi.new('int[1]', length)
|
||||
local buffer = ffi.new(
|
||||
string.format("char[%s]", length)
|
||||
)
|
||||
for i=1, length do
|
||||
buffer[i - 1] = bytes[i]
|
||||
end
|
||||
bytes = _ffi.string(buffer, buffer_len[0])
|
||||
bytes = ffi.string(buffer, buffer_len[0])
|
||||
end
|
||||
return _crc32(bytes, chksum)
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user