From 4e9899dbb51397cd2da21377f7dfe40a9a24ed5c Mon Sep 17 00:00:00 2001 From: Adrian Perez de Castro Date: Sun, 3 Jul 2016 22:21:33 +0300 Subject: [PATCH] Simplify matrix.eventable for the common use cases This removes the support for passing values to eventable.functions() and eventable.object() which are bound to be passed to handlers. On top of simplifying the code overall, this also avoids having three different implementations of the fire() function. In the existing code, the only case in which a handler argument is fixed is for objects which pass themselves. This use case is covered by eventable.object(), so the removed code was not realy ever used. --- matrix/eventable.lua | 154 +++++++++++++++---------------------------- 1 file changed, 54 insertions(+), 100 deletions(-) diff --git a/matrix/eventable.lua b/matrix/eventable.lua index e273d95..a1a7e09 100644 --- a/matrix/eventable.lua +++ b/matrix/eventable.lua @@ -8,6 +8,7 @@ local _select, _pack, _unpack = select, table.pack, table.unpack or unpack if not _pack then + -- Provide a table.pack() implementation for Lua 5.1 and LuaJIT. _pack = function (...) local n = _select("#", ...) local r = { n = n } @@ -18,28 +19,15 @@ if not _pack then end end -local function _expack (args, ...) - local r = { n = args.n } - local n = _select("#", ...) - for i = 1, args.n do - r[i] = args[i] - end - for i = 1, n do - r[r.n + i] = _select(i, ...) - end - r.n = r.n + n - return _unpack(r) -end - local log = (function () local env_value = os.getenv("MATRIX_EVENTABLE_DEBUG_LOG") if env_value and #env_value > 0 and env_value ~= "0" then local out, _tostring = io.stderr, tostring return function (...) out:write("[eventable]") - local args = _pack(...) - for i = 1, args.n do - out:write(" " .. _tostring(args[i])) + local n = _select("#", ...) + for i = 1, n do + out:write(" " .. _tostring(_select(i, ...))) end out:write("\n") out:flush() @@ -49,100 +37,66 @@ local log = (function () end end)() -local function eventable_functions (...) - local event_map = {} - - local hook = function (event, handler) - log("hook:", event, handler) - if not handler then - event_map[event] = nil - else - if not event_map[event] then - event_map[event] = {} - end - local handlers = event_map[event] - handlers[#handlers + 1] = handler - end - end - - local unhook = function (event, handler) - log("unhook:", event, handler) - local old_handlers = event_map[event] - if old_handlers then - local handlers = {} - for i = 1, #old_handlers do - local h = old_handlers[i] - if h ~= handler then - handlers[#handlers + 1] = h - end - end - event_map[event] = handlers - end - end - - local fire - - local nargs = _select("#", ...) - if nargs == 0 then - -- Simplest version, no arguments. - fire = function (event, ...) - log("fire: " .. event .. ":", ...) - local handlers = event_map[event] - if handlers then - for i = 1, #handlers do - local ret = _pack(handlers[i](...)) - if ret.n > 0 then - return _unpack(ret) - end - end - end - end - elseif nargs == 1 then - -- Common single-argument case: optimized. - local arg = _select(1, ...) - fire = function (event, ...) - log("fire: " .. event .. ":", arg, ...) - local handlers = event_map[event] - if handlers then - for i = 1, #handlers do - local ret = _pack(handlers[i](arg, ...)) - if ret.n > 0 then - return _unpack(ret) - end - end - end - end +local function do_hook(event_map, event, handler) + log("hook:", event, handler) + if not handler then + event_map[event] = nil else - -- Generic multi-argument case. - local args = _pack(...) - fire = function (event, ...) - log("fire: " .. event .. ":", _expack(args, ...)) - local handlers = event_map[event] - if handlers then - for i = 1, #handlers do - local ret = _pack(handlers[i](_expack(args, ...))) - if ret.n > 0 then - return _unpack(ret) - end - end - end + if not event_map[event] then + event_map[event] = {} end + local handlers = event_map[event] + handlers[#handlers + 1] = handler end - - return fire, hook, unhook end -local function eventable_object(obj) - local fire, hook, unhook = eventable_functions() - function obj:fire(name, ...) - return fire(name, self, ...) +local function do_unhook(event_map, event, handler) + log("unhook:", event, handler) + local old_handlers = event_map[event] + if old_handlers then + local handlers = {} + for i = 1, #old_handlers do + local h = old_handlers[i] + if h ~= handler then + handlers[#handlers + 1] = h + end + end + event_map[event] = handlers + end +end + +local function do_fire(event_map, event, ...) + log("fire: " .. event .. ":", ...) + local handlers = event_map[event] + if handlers then + for i = 1, #handlers do + local ret = _pack(handlers[i](...)) + if ret.n > 0 then + return _unpack(ret) + end + end + end +end + +local function eventable_functions (event_map) + if not event_map then event_map = {} end + return function (e, ...) return do_fire(event_map, e, ...) end, + function (e, h) return do_hook(event_map, e, h) end, + function (e, h) return do_unhook(event_map, e, h) end +end + +local function eventable_object(obj, event_map) + if not obj then obj = {} end + if not event_map then event_map = {} end + function obj:fire(e, ...) + return do_fire(event_map, e, self, ...) end function obj:hook(...) - hook(...) + do_hook(event_map, ...) return self -- Allow chaining end function obj:unhook(...) - unhook(...) + do_unhook(event_map, ...) return self -- Allow chaining end return obj