add math library, move lua code
This commit is contained in:
parent
f8ce5d6ae0
commit
7fde7d495b
1
.gitignore
vendored
1
.gitignore
vendored
@ -26,3 +26,4 @@ go.work
|
|||||||
/config.lua
|
/config.lua
|
||||||
test/
|
test/
|
||||||
/init.lua
|
/init.lua
|
||||||
|
/moonshark
|
||||||
|
@ -10,30 +10,36 @@ import (
|
|||||||
luajit "git.sharkk.net/Sky/LuaJIT-to-Go"
|
luajit "git.sharkk.net/Sky/LuaJIT-to-Go"
|
||||||
)
|
)
|
||||||
|
|
||||||
//go:embed sandbox.lua
|
//go:embed lua/sandbox.lua
|
||||||
var sandboxLuaCode string
|
var sandboxLuaCode string
|
||||||
|
|
||||||
//go:embed json.lua
|
//go:embed lua/json.lua
|
||||||
var jsonLuaCode string
|
var jsonLuaCode string
|
||||||
|
|
||||||
//go:embed sqlite.lua
|
//go:embed lua/sqlite.lua
|
||||||
var sqliteLuaCode string
|
var sqliteLuaCode string
|
||||||
|
|
||||||
//go:embed fs.lua
|
//go:embed lua/fs.lua
|
||||||
var fsLuaCode string
|
var fsLuaCode string
|
||||||
|
|
||||||
//go:embed util.lua
|
//go:embed lua/util.lua
|
||||||
var utilLuaCode string
|
var utilLuaCode string
|
||||||
|
|
||||||
//go:embed string.lua
|
//go:embed lua/string.lua
|
||||||
var stringLuaCode string
|
var stringLuaCode string
|
||||||
|
|
||||||
//go:embed table.lua
|
//go:embed lua/table.lua
|
||||||
var tableLuaCode string
|
var tableLuaCode string
|
||||||
|
|
||||||
//go:embed crypto.lua
|
//go:embed lua/crypto.lua
|
||||||
var cryptoLuaCode string
|
var cryptoLuaCode string
|
||||||
|
|
||||||
|
//go:embed lua/time.lua
|
||||||
|
var timeLuaCode string
|
||||||
|
|
||||||
|
//go:embed lua/math.lua
|
||||||
|
var mathLuaCode string
|
||||||
|
|
||||||
// ModuleInfo holds information about an embeddable Lua module
|
// ModuleInfo holds information about an embeddable Lua module
|
||||||
type ModuleInfo struct {
|
type ModuleInfo struct {
|
||||||
Name string // Module name
|
Name string // Module name
|
||||||
@ -52,6 +58,8 @@ var (
|
|||||||
{Name: "string", Code: stringLuaCode},
|
{Name: "string", Code: stringLuaCode},
|
||||||
{Name: "table", Code: tableLuaCode},
|
{Name: "table", Code: tableLuaCode},
|
||||||
{Name: "crypto", Code: cryptoLuaCode},
|
{Name: "crypto", Code: cryptoLuaCode},
|
||||||
|
{Name: "time", Code: timeLuaCode},
|
||||||
|
{Name: "math", Code: mathLuaCode},
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
802
core/runner/lua/math.lua
Normal file
802
core/runner/lua/math.lua
Normal file
@ -0,0 +1,802 @@
|
|||||||
|
--[[
|
||||||
|
math.lua - High-performance math library
|
||||||
|
]]--
|
||||||
|
|
||||||
|
local math_ext = {}
|
||||||
|
|
||||||
|
-- Import standard math functions
|
||||||
|
for name, func in pairs(_G.math) do
|
||||||
|
math_ext[name] = func
|
||||||
|
end
|
||||||
|
|
||||||
|
-- ======================================================================
|
||||||
|
-- CONSTANTS (higher precision)
|
||||||
|
-- ======================================================================
|
||||||
|
|
||||||
|
math_ext.pi = 3.14159265358979323846
|
||||||
|
math_ext.tau = 6.28318530717958647693 -- 2*pi
|
||||||
|
math_ext.e = 2.71828182845904523536
|
||||||
|
math_ext.phi = 1.61803398874989484820 -- Golden ratio
|
||||||
|
math_ext.sqrt2 = 1.41421356237309504880
|
||||||
|
math_ext.sqrt3 = 1.73205080756887729353
|
||||||
|
math_ext.ln2 = 0.69314718055994530942
|
||||||
|
math_ext.ln10 = 2.30258509299404568402
|
||||||
|
math_ext.infinity = 1/0
|
||||||
|
math_ext.nan = 0/0
|
||||||
|
|
||||||
|
-- ======================================================================
|
||||||
|
-- EXTENDED FUNCTIONS
|
||||||
|
-- ======================================================================
|
||||||
|
|
||||||
|
-- Cube root (handles negative numbers correctly)
|
||||||
|
function math_ext.cbrt(x)
|
||||||
|
return x < 0 and -(-x)^(1/3) or x^(1/3)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Hypotenuse of right-angled triangle
|
||||||
|
function math_ext.hypot(x, y)
|
||||||
|
return math.sqrt(x * x + y * y)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Check if value is NaN
|
||||||
|
function math_ext.isnan(x)
|
||||||
|
return x ~= x
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Check if value is finite
|
||||||
|
function math_ext.isfinite(x)
|
||||||
|
return x > -math_ext.infinity and x < math_ext.infinity
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Sign function (-1, 0, 1)
|
||||||
|
function math_ext.sign(x)
|
||||||
|
return x > 0 and 1 or (x < 0 and -1 or 0)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Clamp value between min and max
|
||||||
|
function math_ext.clamp(x, min, max)
|
||||||
|
return x < min and min or (x > max and max or x)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Linear interpolation
|
||||||
|
function math_ext.lerp(a, b, t)
|
||||||
|
return a + (b - a) * t
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Smooth step interpolation
|
||||||
|
function math_ext.smoothstep(a, b, t)
|
||||||
|
t = math_ext.clamp((t - a) / (b - a), 0, 1)
|
||||||
|
return t * t * (3 - 2 * t)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Map value from one range to another
|
||||||
|
function math_ext.map(x, in_min, in_max, out_min, out_max)
|
||||||
|
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Round to nearest integer
|
||||||
|
function math_ext.round(x)
|
||||||
|
return x >= 0 and math.floor(x + 0.5) or math.ceil(x - 0.5)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Round to specified decimal places
|
||||||
|
function math_ext.roundto(x, decimals)
|
||||||
|
local mult = 10 ^ (decimals or 0)
|
||||||
|
return math.floor(x * mult + 0.5) / mult
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Normalize angle to [-π, π]
|
||||||
|
function math_ext.normalize_angle(angle)
|
||||||
|
return angle - 2 * math_ext.pi * math.floor((angle + math_ext.pi) / (2 * math_ext.pi))
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Distance between points
|
||||||
|
function math_ext.distance(x1, y1, x2, y2)
|
||||||
|
local dx, dy = x2 - x1, y2 - y1
|
||||||
|
return math.sqrt(dx * dx + dy * dy)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- ======================================================================
|
||||||
|
-- RANDOM NUMBER FUNCTIONS
|
||||||
|
-- ======================================================================
|
||||||
|
|
||||||
|
-- Random float in range [min, max)
|
||||||
|
function math_ext.randomf(min, max)
|
||||||
|
if not min and not max then
|
||||||
|
return math.random()
|
||||||
|
elseif not max then
|
||||||
|
max = min
|
||||||
|
min = 0
|
||||||
|
end
|
||||||
|
return min + math.random() * (max - min)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Random integer in range [min, max]
|
||||||
|
function math_ext.randint(min, max)
|
||||||
|
if not max then
|
||||||
|
max = min
|
||||||
|
min = 1
|
||||||
|
end
|
||||||
|
return math.floor(math.random() * (max - min + 1) + min)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Random boolean with probability p (default 0.5)
|
||||||
|
function math_ext.randboolean(p)
|
||||||
|
p = p or 0.5
|
||||||
|
return math.random() < p
|
||||||
|
end
|
||||||
|
|
||||||
|
-- ======================================================================
|
||||||
|
-- STATISTICS FUNCTIONS
|
||||||
|
-- ======================================================================
|
||||||
|
|
||||||
|
-- Sum of values
|
||||||
|
function math_ext.sum(t)
|
||||||
|
if type(t) ~= "table" then return 0 end
|
||||||
|
|
||||||
|
local sum = 0
|
||||||
|
for i=1, #t do
|
||||||
|
if type(t[i]) == "number" then
|
||||||
|
sum = sum + t[i]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return sum
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Mean (average) of values
|
||||||
|
function math_ext.mean(t)
|
||||||
|
if type(t) ~= "table" or #t == 0 then return 0 end
|
||||||
|
|
||||||
|
local sum = 0
|
||||||
|
local count = 0
|
||||||
|
for i=1, #t do
|
||||||
|
if type(t[i]) == "number" then
|
||||||
|
sum = sum + t[i]
|
||||||
|
count = count + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return count > 0 and sum / count or 0
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Median of values
|
||||||
|
function math_ext.median(t)
|
||||||
|
if type(t) ~= "table" or #t == 0 then return 0 end
|
||||||
|
|
||||||
|
local nums = {}
|
||||||
|
local count = 0
|
||||||
|
for i=1, #t do
|
||||||
|
if type(t[i]) == "number" then
|
||||||
|
count = count + 1
|
||||||
|
nums[count] = t[i]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if count == 0 then return 0 end
|
||||||
|
|
||||||
|
table.sort(nums)
|
||||||
|
|
||||||
|
if count % 2 == 0 then
|
||||||
|
return (nums[count/2] + nums[count/2 + 1]) / 2
|
||||||
|
else
|
||||||
|
return nums[math.ceil(count/2)]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Variance of values
|
||||||
|
function math_ext.variance(t)
|
||||||
|
if type(t) ~= "table" then return 0 end
|
||||||
|
|
||||||
|
local count = 0
|
||||||
|
local m = math_ext.mean(t)
|
||||||
|
local sum = 0
|
||||||
|
|
||||||
|
for i=1, #t do
|
||||||
|
if type(t[i]) == "number" then
|
||||||
|
local dev = t[i] - m
|
||||||
|
sum = sum + dev * dev
|
||||||
|
count = count + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return count > 1 and sum / count or 0
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Standard deviation
|
||||||
|
function math_ext.stdev(t)
|
||||||
|
return math.sqrt(math_ext.variance(t))
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Population variance
|
||||||
|
function math_ext.pvariance(t)
|
||||||
|
if type(t) ~= "table" then return 0 end
|
||||||
|
|
||||||
|
local count = 0
|
||||||
|
local m = math_ext.mean(t)
|
||||||
|
local sum = 0
|
||||||
|
|
||||||
|
for i=1, #t do
|
||||||
|
if type(t[i]) == "number" then
|
||||||
|
local dev = t[i] - m
|
||||||
|
sum = sum + dev * dev
|
||||||
|
count = count + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return count > 0 and sum / count or 0
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Population standard deviation
|
||||||
|
function math_ext.pstdev(t)
|
||||||
|
return math.sqrt(math_ext.pvariance(t))
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Mode (most common value)
|
||||||
|
function math_ext.mode(t)
|
||||||
|
if type(t) ~= "table" or #t == 0 then return nil end
|
||||||
|
|
||||||
|
local counts = {}
|
||||||
|
local most_frequent = nil
|
||||||
|
local max_count = 0
|
||||||
|
|
||||||
|
for i=1, #t do
|
||||||
|
local v = t[i]
|
||||||
|
counts[v] = (counts[v] or 0) + 1
|
||||||
|
if counts[v] > max_count then
|
||||||
|
max_count = counts[v]
|
||||||
|
most_frequent = v
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return most_frequent
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Min and max simultaneously (faster than calling both separately)
|
||||||
|
function math_ext.minmax(t)
|
||||||
|
if type(t) ~= "table" or #t == 0 then return nil, nil end
|
||||||
|
|
||||||
|
local min, max
|
||||||
|
for i=1, #t do
|
||||||
|
if type(t[i]) == "number" then
|
||||||
|
min = t[i]
|
||||||
|
max = t[i]
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if min == nil then return nil, nil end
|
||||||
|
|
||||||
|
for i=1, #t do
|
||||||
|
if type(t[i]) == "number" then
|
||||||
|
if t[i] < min then min = t[i] end
|
||||||
|
if t[i] > max then max = t[i] end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return min, max
|
||||||
|
end
|
||||||
|
|
||||||
|
-- ======================================================================
|
||||||
|
-- VECTOR OPERATIONS (2D/3D vectors)
|
||||||
|
-- ======================================================================
|
||||||
|
|
||||||
|
-- 2D Vector operations
|
||||||
|
math_ext.vec2 = {
|
||||||
|
new = function(x, y)
|
||||||
|
return {x = x or 0, y = y or 0}
|
||||||
|
end,
|
||||||
|
|
||||||
|
copy = function(v)
|
||||||
|
return {x = v.x, y = v.y}
|
||||||
|
end,
|
||||||
|
|
||||||
|
add = function(a, b)
|
||||||
|
return {x = a.x + b.x, y = a.y + b.y}
|
||||||
|
end,
|
||||||
|
|
||||||
|
sub = function(a, b)
|
||||||
|
return {x = a.x - b.x, y = a.y - b.y}
|
||||||
|
end,
|
||||||
|
|
||||||
|
mul = function(a, b)
|
||||||
|
if type(b) == "number" then
|
||||||
|
return {x = a.x * b, y = a.y * b}
|
||||||
|
end
|
||||||
|
return {x = a.x * b.x, y = a.y * b.y}
|
||||||
|
end,
|
||||||
|
|
||||||
|
div = function(a, b)
|
||||||
|
if type(b) == "number" then
|
||||||
|
local inv = 1 / b
|
||||||
|
return {x = a.x * inv, y = a.y * inv}
|
||||||
|
end
|
||||||
|
return {x = a.x / b.x, y = a.y / b.y}
|
||||||
|
end,
|
||||||
|
|
||||||
|
dot = function(a, b)
|
||||||
|
return a.x * b.x + a.y * b.y
|
||||||
|
end,
|
||||||
|
|
||||||
|
length = function(v)
|
||||||
|
return math.sqrt(v.x * v.x + v.y * v.y)
|
||||||
|
end,
|
||||||
|
|
||||||
|
length_squared = function(v)
|
||||||
|
return v.x * v.x + v.y * v.y
|
||||||
|
end,
|
||||||
|
|
||||||
|
distance = function(a, b)
|
||||||
|
local dx, dy = b.x - a.x, b.y - a.y
|
||||||
|
return math.sqrt(dx * dx + dy * dy)
|
||||||
|
end,
|
||||||
|
|
||||||
|
distance_squared = function(a, b)
|
||||||
|
local dx, dy = b.x - a.x, b.y - a.y
|
||||||
|
return dx * dx + dy * dy
|
||||||
|
end,
|
||||||
|
|
||||||
|
normalize = function(v)
|
||||||
|
local len = math.sqrt(v.x * v.x + v.y * v.y)
|
||||||
|
if len > 1e-10 then
|
||||||
|
local inv_len = 1 / len
|
||||||
|
return {x = v.x * inv_len, y = v.y * inv_len}
|
||||||
|
end
|
||||||
|
return {x = 0, y = 0}
|
||||||
|
end,
|
||||||
|
|
||||||
|
rotate = function(v, angle)
|
||||||
|
local c, s = math.cos(angle), math.sin(angle)
|
||||||
|
return {
|
||||||
|
x = v.x * c - v.y * s,
|
||||||
|
y = v.x * s + v.y * c
|
||||||
|
}
|
||||||
|
end,
|
||||||
|
|
||||||
|
angle = function(v)
|
||||||
|
return math.atan2(v.y, v.x)
|
||||||
|
end,
|
||||||
|
|
||||||
|
lerp = function(a, b, t)
|
||||||
|
t = math_ext.clamp(t, 0, 1)
|
||||||
|
return {
|
||||||
|
x = a.x + (b.x - a.x) * t,
|
||||||
|
y = a.y + (b.y - a.y) * t
|
||||||
|
}
|
||||||
|
end,
|
||||||
|
|
||||||
|
reflect = function(v, normal)
|
||||||
|
local dot = v.x * normal.x + v.y * normal.y
|
||||||
|
return {
|
||||||
|
x = v.x - 2 * dot * normal.x,
|
||||||
|
y = v.y - 2 * dot * normal.y
|
||||||
|
}
|
||||||
|
end
|
||||||
|
}
|
||||||
|
|
||||||
|
-- 3D Vector operations
|
||||||
|
math_ext.vec3 = {
|
||||||
|
new = function(x, y, z)
|
||||||
|
return {x = x or 0, y = y or 0, z = z or 0}
|
||||||
|
end,
|
||||||
|
|
||||||
|
copy = function(v)
|
||||||
|
return {x = v.x, y = v.y, z = v.z}
|
||||||
|
end,
|
||||||
|
|
||||||
|
add = function(a, b)
|
||||||
|
return {x = a.x + b.x, y = a.y + b.y, z = a.z + b.z}
|
||||||
|
end,
|
||||||
|
|
||||||
|
sub = function(a, b)
|
||||||
|
return {x = a.x - b.x, y = a.y - b.y, z = a.z - b.z}
|
||||||
|
end,
|
||||||
|
|
||||||
|
mul = function(a, b)
|
||||||
|
if type(b) == "number" then
|
||||||
|
return {x = a.x * b, y = a.y * b, z = a.z * b}
|
||||||
|
end
|
||||||
|
return {x = a.x * b.x, y = a.y * b.y, z = a.z * b.z}
|
||||||
|
end,
|
||||||
|
|
||||||
|
div = function(a, b)
|
||||||
|
if type(b) == "number" then
|
||||||
|
local inv = 1 / b
|
||||||
|
return {x = a.x * inv, y = a.y * inv, z = a.z * inv}
|
||||||
|
end
|
||||||
|
return {x = a.x / b.x, y = a.y / b.y, z = a.z / b.z}
|
||||||
|
end,
|
||||||
|
|
||||||
|
dot = function(a, b)
|
||||||
|
return a.x * b.x + a.y * b.y + a.z * b.z
|
||||||
|
end,
|
||||||
|
|
||||||
|
cross = function(a, b)
|
||||||
|
return {
|
||||||
|
x = a.y * b.z - a.z * b.y,
|
||||||
|
y = a.z * b.x - a.x * b.z,
|
||||||
|
z = a.x * b.y - a.y * b.x
|
||||||
|
}
|
||||||
|
end,
|
||||||
|
|
||||||
|
length = function(v)
|
||||||
|
return math.sqrt(v.x * v.x + v.y * v.y + v.z * v.z)
|
||||||
|
end,
|
||||||
|
|
||||||
|
length_squared = function(v)
|
||||||
|
return v.x * v.x + v.y * v.y + v.z * v.z
|
||||||
|
end,
|
||||||
|
|
||||||
|
distance = function(a, b)
|
||||||
|
local dx, dy, dz = b.x - a.x, b.y - a.y, b.z - a.z
|
||||||
|
return math.sqrt(dx * dx + dy * dy + dz * dz)
|
||||||
|
end,
|
||||||
|
|
||||||
|
distance_squared = function(a, b)
|
||||||
|
local dx, dy, dz = b.x - a.x, b.y - a.y, b.z - a.z
|
||||||
|
return dx * dx + dy * dy + dz * dz
|
||||||
|
end,
|
||||||
|
|
||||||
|
normalize = function(v)
|
||||||
|
local len = math.sqrt(v.x * v.x + v.y * v.y + v.z * v.z)
|
||||||
|
if len > 1e-10 then
|
||||||
|
local inv_len = 1 / len
|
||||||
|
return {x = v.x * inv_len, y = v.y * inv_len, z = v.z * inv_len}
|
||||||
|
end
|
||||||
|
return {x = 0, y = 0, z = 0}
|
||||||
|
end,
|
||||||
|
|
||||||
|
lerp = function(a, b, t)
|
||||||
|
t = math_ext.clamp(t, 0, 1)
|
||||||
|
return {
|
||||||
|
x = a.x + (b.x - a.x) * t,
|
||||||
|
y = a.y + (b.y - a.y) * t,
|
||||||
|
z = a.z + (b.z - a.z) * t
|
||||||
|
}
|
||||||
|
end,
|
||||||
|
|
||||||
|
reflect = function(v, normal)
|
||||||
|
local dot = v.x * normal.x + v.y * normal.y + v.z * normal.z
|
||||||
|
return {
|
||||||
|
x = v.x - 2 * dot * normal.x,
|
||||||
|
y = v.y - 2 * dot * normal.y,
|
||||||
|
z = v.z - 2 * dot * normal.z
|
||||||
|
}
|
||||||
|
end
|
||||||
|
}
|
||||||
|
|
||||||
|
-- ======================================================================
|
||||||
|
-- MATRIX OPERATIONS (2x2 and 3x3 matrices)
|
||||||
|
-- ======================================================================
|
||||||
|
|
||||||
|
math_ext.mat2 = {
|
||||||
|
-- Create a new 2x2 matrix
|
||||||
|
new = function(a, b, c, d)
|
||||||
|
return {
|
||||||
|
{a or 1, b or 0},
|
||||||
|
{c or 0, d or 1}
|
||||||
|
}
|
||||||
|
end,
|
||||||
|
|
||||||
|
-- Create identity matrix
|
||||||
|
identity = function()
|
||||||
|
return {{1, 0}, {0, 1}}
|
||||||
|
end,
|
||||||
|
|
||||||
|
-- Matrix multiplication
|
||||||
|
mul = function(a, b)
|
||||||
|
return {
|
||||||
|
{
|
||||||
|
a[1][1] * b[1][1] + a[1][2] * b[2][1],
|
||||||
|
a[1][1] * b[1][2] + a[1][2] * b[2][2]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
a[2][1] * b[1][1] + a[2][2] * b[2][1],
|
||||||
|
a[2][1] * b[1][2] + a[2][2] * b[2][2]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end,
|
||||||
|
|
||||||
|
-- Determinant
|
||||||
|
det = function(m)
|
||||||
|
return m[1][1] * m[2][2] - m[1][2] * m[2][1]
|
||||||
|
end,
|
||||||
|
|
||||||
|
-- Inverse matrix
|
||||||
|
inverse = function(m)
|
||||||
|
local det = m[1][1] * m[2][2] - m[1][2] * m[2][1]
|
||||||
|
if math.abs(det) < 1e-10 then
|
||||||
|
return nil -- Matrix is not invertible
|
||||||
|
end
|
||||||
|
|
||||||
|
local inv_det = 1 / det
|
||||||
|
return {
|
||||||
|
{m[2][2] * inv_det, -m[1][2] * inv_det},
|
||||||
|
{-m[2][1] * inv_det, m[1][1] * inv_det}
|
||||||
|
}
|
||||||
|
end,
|
||||||
|
|
||||||
|
-- Rotation matrix
|
||||||
|
rotation = function(angle)
|
||||||
|
local cos, sin = math.cos(angle), math.sin(angle)
|
||||||
|
return {
|
||||||
|
{cos, -sin},
|
||||||
|
{sin, cos}
|
||||||
|
}
|
||||||
|
end,
|
||||||
|
|
||||||
|
-- Apply matrix to vector
|
||||||
|
transform = function(m, v)
|
||||||
|
return {
|
||||||
|
x = m[1][1] * v.x + m[1][2] * v.y,
|
||||||
|
y = m[2][1] * v.x + m[2][2] * v.y
|
||||||
|
}
|
||||||
|
end,
|
||||||
|
|
||||||
|
-- Scale matrix
|
||||||
|
scale = function(sx, sy)
|
||||||
|
sy = sy or sx
|
||||||
|
return {
|
||||||
|
{sx, 0},
|
||||||
|
{0, sy}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
}
|
||||||
|
|
||||||
|
math_ext.mat3 = {
|
||||||
|
-- Create identity matrix 3x3
|
||||||
|
identity = function()
|
||||||
|
return {
|
||||||
|
{1, 0, 0},
|
||||||
|
{0, 1, 0},
|
||||||
|
{0, 0, 1}
|
||||||
|
}
|
||||||
|
end,
|
||||||
|
|
||||||
|
-- Create a 2D transformation matrix (translation, rotation, scale)
|
||||||
|
transform = function(x, y, angle, sx, sy)
|
||||||
|
sx = sx or 1
|
||||||
|
sy = sy or sx
|
||||||
|
local cos, sin = math.cos(angle), math.sin(angle)
|
||||||
|
return {
|
||||||
|
{cos * sx, -sin * sy, x},
|
||||||
|
{sin * sx, cos * sy, y},
|
||||||
|
{0, 0, 1}
|
||||||
|
}
|
||||||
|
end,
|
||||||
|
|
||||||
|
-- Matrix multiplication
|
||||||
|
mul = function(a, b)
|
||||||
|
local result = {
|
||||||
|
{0, 0, 0},
|
||||||
|
{0, 0, 0},
|
||||||
|
{0, 0, 0}
|
||||||
|
}
|
||||||
|
|
||||||
|
for i = 1, 3 do
|
||||||
|
for j = 1, 3 do
|
||||||
|
for k = 1, 3 do
|
||||||
|
result[i][j] = result[i][j] + a[i][k] * b[k][j]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return result
|
||||||
|
end,
|
||||||
|
|
||||||
|
-- Apply matrix to point (homogeneous coordinates)
|
||||||
|
transform_point = function(m, v)
|
||||||
|
local x = m[1][1] * v.x + m[1][2] * v.y + m[1][3]
|
||||||
|
local y = m[2][1] * v.x + m[2][2] * v.y + m[2][3]
|
||||||
|
local w = m[3][1] * v.x + m[3][2] * v.y + m[3][3]
|
||||||
|
|
||||||
|
if math.abs(w) < 1e-10 then
|
||||||
|
return {x = 0, y = 0}
|
||||||
|
end
|
||||||
|
|
||||||
|
return {x = x / w, y = y / w}
|
||||||
|
end,
|
||||||
|
|
||||||
|
-- Translation matrix
|
||||||
|
translation = function(x, y)
|
||||||
|
return {
|
||||||
|
{1, 0, x},
|
||||||
|
{0, 1, y},
|
||||||
|
{0, 0, 1}
|
||||||
|
}
|
||||||
|
end,
|
||||||
|
|
||||||
|
-- Rotation matrix
|
||||||
|
rotation = function(angle)
|
||||||
|
local cos, sin = math.cos(angle), math.sin(angle)
|
||||||
|
return {
|
||||||
|
{cos, -sin, 0},
|
||||||
|
{sin, cos, 0},
|
||||||
|
{0, 0, 1}
|
||||||
|
}
|
||||||
|
end,
|
||||||
|
|
||||||
|
-- Scale matrix
|
||||||
|
scale = function(sx, sy)
|
||||||
|
sy = sy or sx
|
||||||
|
return {
|
||||||
|
{sx, 0, 0},
|
||||||
|
{0, sy, 0},
|
||||||
|
{0, 0, 1}
|
||||||
|
}
|
||||||
|
end,
|
||||||
|
|
||||||
|
-- Determinant
|
||||||
|
det = function(m)
|
||||||
|
return m[1][1] * (m[2][2] * m[3][3] - m[2][3] * m[3][2]) -
|
||||||
|
m[1][2] * (m[2][1] * m[3][3] - m[2][3] * m[3][1]) +
|
||||||
|
m[1][3] * (m[2][1] * m[3][2] - m[2][2] * m[3][1])
|
||||||
|
end
|
||||||
|
}
|
||||||
|
|
||||||
|
-- ======================================================================
|
||||||
|
-- GEOMETRY FUNCTIONS
|
||||||
|
-- ======================================================================
|
||||||
|
|
||||||
|
math_ext.geometry = {
|
||||||
|
-- Distance from point to line
|
||||||
|
point_line_distance = function(px, py, x1, y1, x2, y2)
|
||||||
|
local dx, dy = x2 - x1, y2 - y1
|
||||||
|
local len_sq = dx * dx + dy * dy
|
||||||
|
|
||||||
|
if len_sq < 1e-10 then
|
||||||
|
return math_ext.distance(px, py, x1, y1)
|
||||||
|
end
|
||||||
|
|
||||||
|
local t = ((px - x1) * dx + (py - y1) * dy) / len_sq
|
||||||
|
t = math_ext.clamp(t, 0, 1)
|
||||||
|
|
||||||
|
local nearestX = x1 + t * dx
|
||||||
|
local nearestY = y1 + t * dy
|
||||||
|
|
||||||
|
return math_ext.distance(px, py, nearestX, nearestY)
|
||||||
|
end,
|
||||||
|
|
||||||
|
-- Check if point is inside polygon
|
||||||
|
point_in_polygon = function(px, py, vertices)
|
||||||
|
local inside = false
|
||||||
|
local n = #vertices / 2
|
||||||
|
|
||||||
|
for i = 1, n do
|
||||||
|
local x1, y1 = vertices[i*2-1], vertices[i*2]
|
||||||
|
local x2, y2
|
||||||
|
|
||||||
|
if i == n then
|
||||||
|
x2, y2 = vertices[1], vertices[2]
|
||||||
|
else
|
||||||
|
x2, y2 = vertices[i*2+1], vertices[i*2+2]
|
||||||
|
end
|
||||||
|
|
||||||
|
if ((y1 > py) ~= (y2 > py)) and
|
||||||
|
(px < (x2 - x1) * (py - y1) / (y2 - y1) + x1) then
|
||||||
|
inside = not inside
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return inside
|
||||||
|
end,
|
||||||
|
|
||||||
|
-- Area of a triangle
|
||||||
|
triangle_area = function(x1, y1, x2, y2, x3, y3)
|
||||||
|
return math.abs((x1 * (y2 - y3) + x2 * (y3 - y1) + x3 * (y1 - y2)) / 2)
|
||||||
|
end,
|
||||||
|
|
||||||
|
-- Check if point is inside triangle
|
||||||
|
point_in_triangle = function(px, py, x1, y1, x2, y2, x3, y3)
|
||||||
|
local area = math_ext.geometry.triangle_area(x1, y1, x2, y2, x3, y3)
|
||||||
|
local area1 = math_ext.geometry.triangle_area(px, py, x2, y2, x3, y3)
|
||||||
|
local area2 = math_ext.geometry.triangle_area(x1, y1, px, py, x3, y3)
|
||||||
|
local area3 = math_ext.geometry.triangle_area(x1, y1, x2, y2, px, py)
|
||||||
|
|
||||||
|
return math.abs(area - (area1 + area2 + area3)) < 1e-10
|
||||||
|
end,
|
||||||
|
|
||||||
|
-- Check if two line segments intersect
|
||||||
|
line_intersect = function(x1, y1, x2, y2, x3, y3, x4, y4)
|
||||||
|
local d = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1)
|
||||||
|
|
||||||
|
if math.abs(d) < 1e-10 then
|
||||||
|
return false, nil, nil -- Lines are parallel
|
||||||
|
end
|
||||||
|
|
||||||
|
local ua = ((x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3)) / d
|
||||||
|
local ub = ((x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3)) / d
|
||||||
|
|
||||||
|
if ua >= 0 and ua <= 1 and ub >= 0 and ub <= 1 then
|
||||||
|
local x = x1 + ua * (x2 - x1)
|
||||||
|
local y = y1 + ua * (y2 - y1)
|
||||||
|
return true, x, y
|
||||||
|
end
|
||||||
|
|
||||||
|
return false, nil, nil
|
||||||
|
end,
|
||||||
|
|
||||||
|
-- Closest point on line segment to point
|
||||||
|
closest_point_on_segment = function(px, py, x1, y1, x2, y2)
|
||||||
|
local dx, dy = x2 - x1, y2 - y1
|
||||||
|
local len_sq = dx * dx + dy * dy
|
||||||
|
|
||||||
|
if len_sq < 1e-10 then
|
||||||
|
return x1, y1
|
||||||
|
end
|
||||||
|
|
||||||
|
local t = ((px - x1) * dx + (py - y1) * dy) / len_sq
|
||||||
|
t = math_ext.clamp(t, 0, 1)
|
||||||
|
|
||||||
|
return x1 + t * dx, y1 + t * dy
|
||||||
|
end
|
||||||
|
}
|
||||||
|
|
||||||
|
-- ======================================================================
|
||||||
|
-- INTERPOLATION FUNCTIONS
|
||||||
|
-- ======================================================================
|
||||||
|
|
||||||
|
math_ext.interpolation = {
|
||||||
|
-- Cubic Bezier interpolation
|
||||||
|
bezier = function(t, p0, p1, p2, p3)
|
||||||
|
t = math_ext.clamp(t, 0, 1)
|
||||||
|
local t2 = t * t
|
||||||
|
local t3 = t2 * t
|
||||||
|
local mt = 1 - t
|
||||||
|
local mt2 = mt * mt
|
||||||
|
local mt3 = mt2 * mt
|
||||||
|
|
||||||
|
return p0 * mt3 + 3 * p1 * mt2 * t + 3 * p2 * mt * t2 + p3 * t3
|
||||||
|
end,
|
||||||
|
|
||||||
|
-- Catmull-Rom spline interpolation
|
||||||
|
catmull_rom = function(t, p0, p1, p2, p3)
|
||||||
|
t = math_ext.clamp(t, 0, 1)
|
||||||
|
local t2 = t * t
|
||||||
|
local t3 = t2 * t
|
||||||
|
|
||||||
|
return 0.5 * (
|
||||||
|
(2 * p1) +
|
||||||
|
(-p0 + p2) * t +
|
||||||
|
(2 * p0 - 5 * p1 + 4 * p2 - p3) * t2 +
|
||||||
|
(-p0 + 3 * p1 - 3 * p2 + p3) * t3
|
||||||
|
)
|
||||||
|
end,
|
||||||
|
|
||||||
|
-- Hermite interpolation
|
||||||
|
hermite = function(t, p0, p1, m0, m1)
|
||||||
|
t = math_ext.clamp(t, 0, 1)
|
||||||
|
local t2 = t * t
|
||||||
|
local t3 = t2 * t
|
||||||
|
local h00 = 2 * t3 - 3 * t2 + 1
|
||||||
|
local h10 = t3 - 2 * t2 + t
|
||||||
|
local h01 = -2 * t3 + 3 * t2
|
||||||
|
local h11 = t3 - t2
|
||||||
|
|
||||||
|
return h00 * p0 + h10 * m0 + h01 * p1 + h11 * m1
|
||||||
|
end,
|
||||||
|
|
||||||
|
-- Quadratic Bezier interpolation
|
||||||
|
quadratic_bezier = function(t, p0, p1, p2)
|
||||||
|
t = math_ext.clamp(t, 0, 1)
|
||||||
|
local mt = 1 - t
|
||||||
|
return mt * mt * p0 + 2 * mt * t * p1 + t * t * p2
|
||||||
|
end,
|
||||||
|
|
||||||
|
-- Step interpolation
|
||||||
|
step = function(t, edge, x)
|
||||||
|
return t < edge and 0 or x
|
||||||
|
end,
|
||||||
|
|
||||||
|
-- Smoothstep interpolation
|
||||||
|
smoothstep = function(edge0, edge1, x)
|
||||||
|
local t = math_ext.clamp((x - edge0) / (edge1 - edge0), 0, 1)
|
||||||
|
return t * t * (3 - 2 * t)
|
||||||
|
end,
|
||||||
|
|
||||||
|
-- Smootherstep interpolation (Ken Perlin)
|
||||||
|
smootherstep = function(edge0, edge1, x)
|
||||||
|
local t = math_ext.clamp((x - edge0) / (edge1 - edge0), 0, 1)
|
||||||
|
return t * t * t * (t * (t * 6 - 15) + 10)
|
||||||
|
end
|
||||||
|
}
|
||||||
|
|
||||||
|
return math_ext
|
@ -69,25 +69,116 @@ local connection_mt = {
|
|||||||
|
|
||||||
-- Create a new table
|
-- Create a new table
|
||||||
create_table = function(self, table_name, ...)
|
create_table = function(self, table_name, ...)
|
||||||
local columns = {...}
|
local columns = {}
|
||||||
|
local indices = {}
|
||||||
|
|
||||||
|
-- Process all arguments
|
||||||
|
for _, def in ipairs({...}) do
|
||||||
|
if type(def) == "string" then
|
||||||
|
-- Check if it's an index definition
|
||||||
|
local index_type, index_def = def:match("^(UNIQUE%s+INDEX:|INDEX:)(.+)")
|
||||||
|
|
||||||
|
if index_def then
|
||||||
|
-- Parse index definition: INDEX:idx_name(col1,col2)
|
||||||
|
local index_name, columns_str = index_def:match("([%w_]+)%(([^)]+)%)")
|
||||||
|
|
||||||
|
if index_name and columns_str then
|
||||||
|
-- Split columns by comma
|
||||||
|
local index_columns = {}
|
||||||
|
for col in columns_str:gmatch("[^,]+") do
|
||||||
|
table.insert(index_columns, col:match("^%s*(.-)%s*$")) -- Trim whitespace
|
||||||
|
end
|
||||||
|
|
||||||
|
table.insert(indices, {
|
||||||
|
name = index_name,
|
||||||
|
columns = index_columns,
|
||||||
|
unique = (index_type == "UNIQUE INDEX:")
|
||||||
|
})
|
||||||
|
end
|
||||||
|
else
|
||||||
|
-- Regular column definition
|
||||||
|
table.insert(columns, def)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
if #columns == 0 then
|
if #columns == 0 then
|
||||||
error("connection:create_table: no columns specified", 2)
|
error("connection:create_table: no columns specified", 2)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Create the table
|
||||||
local query = string.format("CREATE TABLE IF NOT EXISTS %s (%s)",
|
local query = string.format("CREATE TABLE IF NOT EXISTS %s (%s)",
|
||||||
table_name, table.concat(columns, ", "))
|
table_name, table.concat(columns, ", "))
|
||||||
|
|
||||||
return self:exec(query)
|
local result = self:exec(query)
|
||||||
|
|
||||||
|
-- Create indices
|
||||||
|
if #indices > 0 then
|
||||||
|
self:begin()
|
||||||
|
|
||||||
|
for _, idx in ipairs(indices) do
|
||||||
|
local unique = idx.unique and "UNIQUE " or ""
|
||||||
|
|
||||||
|
local index_query = string.format(
|
||||||
|
"CREATE %sINDEX IF NOT EXISTS %s ON %s (%s)",
|
||||||
|
unique,
|
||||||
|
idx.name,
|
||||||
|
table_name,
|
||||||
|
table.concat(idx.columns, ", ")
|
||||||
|
)
|
||||||
|
|
||||||
|
self:exec(index_query)
|
||||||
|
end
|
||||||
|
|
||||||
|
self:commit()
|
||||||
|
end
|
||||||
|
|
||||||
|
return result
|
||||||
end,
|
end,
|
||||||
|
|
||||||
-- Insert a row or multiple rows
|
-- Insert a row or multiple rows
|
||||||
insert = function(self, table_name, data)
|
insert = function(self, table_name, data, columns)
|
||||||
if type(data) ~= "table" then
|
if type(data) ~= "table" then
|
||||||
error("connection:insert: data must be a table", 2)
|
error("connection:insert: data must be a table", 2)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Single row
|
if columns and type(columns) == "table" then
|
||||||
|
local placeholders = {}
|
||||||
|
for _ in ipairs(columns) do
|
||||||
|
table.insert(placeholders, "?")
|
||||||
|
end
|
||||||
|
|
||||||
|
local query = string.format(
|
||||||
|
"INSERT INTO %s (%s) VALUES (%s)",
|
||||||
|
table_name,
|
||||||
|
table.concat(columns, ", "),
|
||||||
|
table.concat(placeholders, ", ")
|
||||||
|
)
|
||||||
|
|
||||||
|
local use_transaction = #data > 1 and type(data[1]) == "table"
|
||||||
|
|
||||||
|
if use_transaction then
|
||||||
|
self:begin()
|
||||||
|
end
|
||||||
|
|
||||||
|
local affected = 0
|
||||||
|
|
||||||
|
if #data > 0 and type(data[1]) == "table" then
|
||||||
|
for _, row in ipairs(data) do
|
||||||
|
local result = self:exec(query, row)
|
||||||
|
affected = affected + result
|
||||||
|
end
|
||||||
|
else
|
||||||
|
affected = self:exec(query, data)
|
||||||
|
end
|
||||||
|
|
||||||
|
if use_transaction then
|
||||||
|
self:commit()
|
||||||
|
end
|
||||||
|
|
||||||
|
return affected
|
||||||
|
end
|
||||||
|
|
||||||
if data[1] == nil and next(data) ~= nil then
|
if data[1] == nil and next(data) ~= nil then
|
||||||
local columns = {}
|
local columns = {}
|
||||||
local placeholders = {}
|
local placeholders = {}
|
||||||
@ -109,8 +200,8 @@ local connection_mt = {
|
|||||||
return self:exec(query, params)
|
return self:exec(query, params)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Multiple rows
|
|
||||||
if #data > 0 and type(data[1]) == "table" then
|
if #data > 0 and type(data[1]) == "table" then
|
||||||
|
self:begin()
|
||||||
local affected = 0
|
local affected = 0
|
||||||
|
|
||||||
for _, row in ipairs(data) do
|
for _, row in ipairs(data) do
|
||||||
@ -118,6 +209,7 @@ local connection_mt = {
|
|||||||
affected = affected + result
|
affected = affected + result
|
||||||
end
|
end
|
||||||
|
|
||||||
|
self:commit()
|
||||||
return affected
|
return affected
|
||||||
end
|
end
|
||||||
|
|
130
core/runner/lua/time.lua
Normal file
130
core/runner/lua/time.lua
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
--[[
|
||||||
|
time.lua - High performance timing functions
|
||||||
|
]]--
|
||||||
|
|
||||||
|
local ffi = require('ffi')
|
||||||
|
local is_windows = (ffi.os == "Windows")
|
||||||
|
|
||||||
|
-- Define C structures and functions based on platform
|
||||||
|
if is_windows then
|
||||||
|
ffi.cdef[[
|
||||||
|
typedef struct {
|
||||||
|
int64_t QuadPart;
|
||||||
|
} LARGE_INTEGER;
|
||||||
|
int QueryPerformanceCounter(LARGE_INTEGER* lpPerformanceCount);
|
||||||
|
int QueryPerformanceFrequency(LARGE_INTEGER* lpFrequency);
|
||||||
|
]]
|
||||||
|
else
|
||||||
|
ffi.cdef[[
|
||||||
|
typedef long time_t;
|
||||||
|
typedef struct timeval {
|
||||||
|
long tv_sec;
|
||||||
|
long tv_usec;
|
||||||
|
} timeval;
|
||||||
|
int gettimeofday(struct timeval* tv, void* tz);
|
||||||
|
time_t time(time_t* t);
|
||||||
|
]]
|
||||||
|
end
|
||||||
|
|
||||||
|
local time = {}
|
||||||
|
local has_initialized = false
|
||||||
|
local start_time, timer_freq
|
||||||
|
|
||||||
|
-- Initialize timing system based on platform
|
||||||
|
local function init()
|
||||||
|
if has_initialized then return end
|
||||||
|
|
||||||
|
if ffi.os == "Windows" then
|
||||||
|
local frequency = ffi.new("LARGE_INTEGER")
|
||||||
|
ffi.C.QueryPerformanceFrequency(frequency)
|
||||||
|
timer_freq = tonumber(frequency.QuadPart)
|
||||||
|
|
||||||
|
local counter = ffi.new("LARGE_INTEGER")
|
||||||
|
ffi.C.QueryPerformanceCounter(counter)
|
||||||
|
start_time = tonumber(counter.QuadPart)
|
||||||
|
else
|
||||||
|
-- Nothing special needed for Unix platform init
|
||||||
|
start_time = ffi.C.time(nil)
|
||||||
|
end
|
||||||
|
|
||||||
|
has_initialized = true
|
||||||
|
end
|
||||||
|
|
||||||
|
-- PHP-compatible microtime implementation
|
||||||
|
function time.microtime(get_as_float)
|
||||||
|
init()
|
||||||
|
|
||||||
|
if ffi.os == "Windows" then
|
||||||
|
local counter = ffi.new("LARGE_INTEGER")
|
||||||
|
ffi.C.QueryPerformanceCounter(counter)
|
||||||
|
local now = tonumber(counter.QuadPart)
|
||||||
|
local seconds = math.floor((now - start_time) / timer_freq)
|
||||||
|
local microseconds = ((now - start_time) % timer_freq) * 1000000 / timer_freq
|
||||||
|
|
||||||
|
if get_as_float then
|
||||||
|
return seconds + microseconds / 1000000
|
||||||
|
else
|
||||||
|
return string.format("0.%06d %d", microseconds, seconds)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
local tv = ffi.new("struct timeval")
|
||||||
|
ffi.C.gettimeofday(tv, nil)
|
||||||
|
|
||||||
|
if get_as_float then
|
||||||
|
return tonumber(tv.tv_sec) + tonumber(tv.tv_usec) / 1000000
|
||||||
|
else
|
||||||
|
return string.format("0.%06d %d", tv.tv_usec, tv.tv_sec)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- High-precision monotonic timer (returns seconds with microsecond precision)
|
||||||
|
function time.monotonic()
|
||||||
|
init()
|
||||||
|
|
||||||
|
if ffi.os == "Windows" then
|
||||||
|
local counter = ffi.new("LARGE_INTEGER")
|
||||||
|
ffi.C.QueryPerformanceCounter(counter)
|
||||||
|
local now = tonumber(counter.QuadPart)
|
||||||
|
return (now - start_time) / timer_freq
|
||||||
|
else
|
||||||
|
local tv = ffi.new("struct timeval")
|
||||||
|
ffi.C.gettimeofday(tv, nil)
|
||||||
|
return tonumber(tv.tv_sec) - start_time + tonumber(tv.tv_usec) / 1000000
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Benchmark function that measures execution time
|
||||||
|
function time.benchmark(func, iterations, warmup)
|
||||||
|
iterations = iterations or 1000
|
||||||
|
warmup = warmup or 10
|
||||||
|
|
||||||
|
-- Warmup
|
||||||
|
for i=1, warmup do func() end
|
||||||
|
|
||||||
|
local start = time.microtime(true)
|
||||||
|
for i=1, iterations do
|
||||||
|
func()
|
||||||
|
end
|
||||||
|
local finish = time.microtime(true)
|
||||||
|
|
||||||
|
local elapsed = (finish - start) * 1000000 -- Convert to microseconds
|
||||||
|
return elapsed / iterations
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Simple sleep function using coroutine yielding
|
||||||
|
function time.sleep(seconds)
|
||||||
|
if type(seconds) ~= "number" or seconds <= 0 then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local start = time.monotonic()
|
||||||
|
while time.monotonic() - start < seconds do
|
||||||
|
-- Use coroutine.yield to avoid consuming CPU
|
||||||
|
coroutine.yield()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
_G.microtime = time.microtime
|
||||||
|
|
||||||
|
return time
|
Loading…
x
Reference in New Issue
Block a user