Last active
September 24, 2018 16:07
-
-
Save remzmike/67520522c98ba7828d07 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- throttling/scheduling function wrappers | |
-- v01 - 4/26/2013 3:08:51 PM - tested in lua 5.1 and 5.2 | |
-- todo: allow optional string keys | |
local _registry = {} | |
function run_many(count, fn, ...) | |
return internal_run({fn=fn, count=count}, ...) | |
end | |
function run_once(fn, ...) | |
return run_many(1, fn, ...) | |
end | |
function run_every(interval, fn, ...) | |
return internal_run({fn=fn, interval=interval}, ...) | |
end | |
function run_later(seconds, fn, ...) | |
return internal_run({fn=fn, count=1, start=os.clock()+seconds}, ...) | |
end | |
function run_at(clock, fn, ...) | |
return internal_run({fn=fn, count=1, start=clock}, ...) | |
end | |
-- technically optional, but recommended | |
-- run checks at different places in code, make code more clear | |
-- key is key or fn | |
-- if args are passed, then they are used in latest call, else original args are used | |
function run_check(key, ...) | |
local data = _registry[key] | |
if data==nil then | |
print('attempted run_check with invalid key', ':', key) -- todo: fixitup | |
end | |
local n = select('#', ...) | |
local result | |
if n>0 then | |
result = internal_run(data.t, ...) | |
else | |
result = internal_run(data.t, unpack(data.args)) | |
end | |
-- automatic cleanup for count~=nil items (only when using run_check) | |
if data.count >= data.t.count then | |
print('autocleanup: '..tostring(key)) | |
unregister(key) | |
end | |
return result | |
end | |
function run_check_all(...) | |
local n = select('#', ...) | |
for k,v in pairs(_registry) do | |
data = _registry[k] | |
if n>0 then | |
internal_run(data.t, ...) | |
else | |
internal_run(data.t, unpack(data.args)) | |
end | |
end | |
end | |
-- mostly internal | |
function unregister(key) | |
_registry[key] = nil | |
print('key unregistered: '..tostring(key)) | |
end | |
-- fn = the function to run (required) | |
-- count = how many times to run, nil for infinite (optional, default:nil) | |
-- start = the time to start runs (optional, default:nil) | |
-- interval = the seconds between runs (optional, default:nil) | |
-- key = key to use instead of fn (optional, default:fn) | |
function internal_run(t, ...) | |
local fn = t.fn | |
local key = t.key or fn | |
local now = os.clock() | |
local data = _registry[key] | |
if data == nil then | |
local args = {} | |
local n = select('#', ...) | |
local v | |
for i=1,n do | |
v = select(i, ...) | |
table.insert(args, v) | |
end | |
-- the first t and args are stored in registry | |
data = {count=0, last=0, t=t, args=args} | |
_registry[key] = data | |
end | |
--assert(data~=nil, 'data==nil') | |
--assert(data.count~=nil, 'data.count==nil') | |
--assert(now~=nil, 'now==nil') | |
--assert(data.t~=nil, 'data.t==nil') | |
--assert(data.t.start~=nil, 'data.t.start==nil') | |
--assert(data.last~=nil, 'data.last==nil') | |
-- run | |
local countCheck = (t.count==nil or data.count < t.count) | |
local startCheck = (data.t.start==nil or now >= data.t.start) | |
local intervalCheck = (t.interval==nil or now-data.last >= t.interval) | |
--print('', 'countCheck', tostring(countCheck)) | |
--print('', 'startCheck', tostring(startCheck)) | |
--print('', 'intervalCheck', tostring(intervalCheck)) | |
--print('') | |
if countCheck and startCheck and intervalCheck then | |
data.count = data.count + 1 | |
data.last = now | |
return fn(...) -- default to using latest args | |
end | |
end | |
-- TESTS ----------------------------------------------------------------------- | |
local test=false | |
if test then | |
local function brutesleep(n) | |
local t0 = os.clock() | |
while os.clock() - t0 <= n do end | |
end | |
local all_tests = true | |
local start | |
if all_tests then | |
local f1 = function(...) print(...) end | |
for i=0,10 do | |
run_once(f1, "running once") | |
--brutesleep(0.2) | |
end | |
local f2 = function(...) print(...) end | |
for i=0,10 do | |
run_many(2, f2, "running two times", i) | |
--brutesleep(0.2) | |
end | |
local f3 = function(...) print(...) end | |
local start = os.clock() | |
while os.clock() - start < 4 do | |
--brutesleep(0.2) | |
run_every(1, f3, "running every second", os.clock()) | |
end | |
local f4 = function(...) print(...) end | |
local f5 = function(...) print(...) end | |
start = os.clock() | |
print('function will run in 3 seconds...') | |
while os.clock() - start < 7 do | |
--brutesleep(0.2) | |
run_later(3, f4, "run once after 3 seconds") | |
run_every(1, f5, _registry[f4].t.start, os.clock()) | |
end | |
local f4b = function(...) print(...) end | |
local f5b = function(...) print(...) end | |
start = os.clock() | |
local at = start+3 | |
print('function will run @ '..tostring(at)) | |
while os.clock() - start < 9 do | |
--brutesleep(0.2) | |
run_at(at, f4b, "run @ completed @ "..tostring(os.clock())) | |
run_every(1, f5b, _registry[f4b].t.start, os.clock()) | |
end | |
end | |
if all_tests then | |
local f6 = function(...) print(...) end | |
start = os.clock() | |
run_later(1.5, f6, "run this in 1.5 seconds, but this arg isn't seen") | |
local i = 0 | |
print('function will run when we check it late..') | |
while os.clock() - start <= 3 do | |
brutesleep(1) | |
i = i + 1 | |
print(i) | |
end | |
run_later(42, f6, "finally checked, latest args are used, first param is not, it's meaningless") | |
end | |
-- to make this less confusing, i introduce run_check | |
if all_tests then | |
local f7 = function(...) print(...) end | |
start = os.clock() | |
run_later(1.5, f7, "run this in 1.5 seconds, once checked, these are original args") | |
local i = 0 | |
print('-') | |
print('function will run when we check it late... using original args') | |
while os.clock() - start <= 2 do | |
brutesleep(1) | |
i = i + 1 | |
print(i) | |
end | |
run_check(f7) | |
end | |
-- you can also use latest args with run_check | |
if all_tests then | |
local f8 = function(...) print(...) end | |
start = os.clock() | |
run_later(1.5, f8, "this arg wont matter") | |
local i = 0 | |
print('-') | |
print('function will run when we check it late... using new args') | |
while os.clock() - start <= 2 do | |
brutesleep(1) | |
i = i + 1 | |
print(i) | |
end | |
run_check(f8, "these are the new args") | |
end | |
-- test that cleanup does not occur with non check calls | |
local f9 | |
if all_tests then | |
f9 = function(...) print(...) end | |
start = os.clock() | |
run_later(1.5, f9, "non-check cleanup check a") | |
local i = 0 | |
print('-') | |
print('function will run when we check it late...') | |
while os.clock() - start <= 2 do | |
brutesleep(1) | |
i = i + 1 | |
print(i) | |
end | |
run_later(1.5, f9, "non-check cleanup check b [GOOD]") | |
run_later(1.5, f9, "non-check cleanup check c") | |
end | |
if all_tests then | |
run_later(1.5, f9, "non-check cleanup check d") -- no error | |
end | |
-- cleanup occurs on check_calls where count~=nil | |
local f10 | |
if all_tests then | |
f10 = function(...) print(...) end | |
start = os.clock() | |
run_later(1.5, f10, "check cleanup a") | |
local i = 0 | |
print('-') | |
print('function will run when we check it late...') | |
while os.clock() - start <= 2 do | |
brutesleep(1) | |
i = i + 1 | |
print(i) | |
end | |
run_later(1.5, f10, "check cleanup b [GOOD]") | |
run_later(1.5, f10, "check cleanup c") | |
end | |
if all_tests then | |
run_later(1.5, f10, "check cleanup d") | |
assert(_registry[f10] ~= nil) | |
run_check(f10, "check cleanup e") | |
if (_registry[f10] == nil) then | |
print('cleanup test passed') | |
end | |
end | |
-- test return values | |
if all_tests then | |
print('-') | |
local f11 = function(msg,x,y) print(msg); return x+y end | |
print("test return values in 2 seconds") | |
run_later(2, f11, 'function completed', 4, 9) | |
start = os.clock() | |
while os.clock() - start <= 2 do | |
brutesleep(0.2) | |
result = run_check(f11) | |
if result ~= nil then | |
print('result : '..tostring(result)) | |
end | |
end | |
end | |
if all_tests then | |
print('- check all -') | |
run_check_all() | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment