From eb7427676a2f09556f9d5f19a1a6392fd945e8bc Mon Sep 17 00:00:00 2001 From: Peter Melnichenko Date: Thu, 6 Oct 2016 16:51:04 +0300 Subject: Rewrite util.sortedpairs to avoid using coroutines util.sortedpairs is used in luarocks loader since @6dc745a. Openresty does not like coroutines being used from inside `require`, resulting in "attempt to yield across C-call boundary" error. New version of util.sortedpairs uses a prepared array of ordered keys instead of coroutines. Ref #620. --- src/luarocks/util.lua | 79 ++++++++++++++++++++++++++++----------------------- 1 file changed, 43 insertions(+), 36 deletions(-) (limited to 'src') diff --git a/src/luarocks/util.lua b/src/luarocks/util.lua index 532bea8b..c9fb7d63 100644 --- a/src/luarocks/util.lua +++ b/src/luarocks/util.lua @@ -357,52 +357,59 @@ local function default_sort(a, b) end end --- The iterator function used internally by util.sortedpairs. +--- A table iterator generator that returns elements sorted by key, +-- to be used in "for" loops. -- @param tbl table: The table to be iterated. --- @param sort_function function or nil: An optional comparison function --- to be used by table.sort when sorting keys. --- @see sortedpairs -local function sortedpairs_iterator(tbl, sort_function) - local ks = util.keys(tbl) - if not sort_function or type(sort_function) == "function" then - table.sort(ks, sort_function or default_sort) - for _, k in ipairs(ks) do - coroutine.yield(k, tbl[k]) - end +-- @param sort_function function or table or nil: An optional comparison function +-- to be used by table.sort when sorting keys, or an array listing an explicit order +-- for keys. If a value itself is an array, it is taken so that the first element +-- is a string representing the field name, and the second element is a priority table +-- for that key, which is returned by the iterator as the third value after the key +-- and the value. +-- @return function: the iterator function. +function util.sortedpairs(tbl, sort_function) + sort_function = sort_function or default_sort + local keys = util.keys(tbl) + local sub_orders = {} + + if type(sort_function) == "function" then + table.sort(keys, sort_function) else local order = sort_function - local done = {} - for _, k in ipairs(order) do - local sub_order - if type(k) == "table" then - sub_order = k[2] - k = k[1] + local ordered_keys = {} + local all_keys = keys + keys = {} + + for _, order_entry in ipairs(order) do + local key, sub_order + if type(order_entry) == "table" then + key = order_entry[1] + sub_order = order_entry[2] + else + key = order_entry end - if tbl[k] then - done[k] = true - coroutine.yield(k, tbl[k], sub_order) + + if tbl[key] then + ordered_keys[key] = true + sub_orders[key] = sub_order + table.insert(keys, key) end end - table.sort(ks, default_sort) - for _, k in ipairs(ks) do - if not done[k] then - coroutine.yield(k, tbl[k]) + + table.sort(all_keys, default_sort) + for _, key in ipairs(all_keys) do + if not ordered_keys[key] then + table.insert(keys, key) end end end -end ---- A table iterator generator that returns elements sorted by key, --- to be used in "for" loops. --- @param tbl table: The table to be iterated. --- @param sort_function function or table or nil: An optional comparison function --- to be used by table.sort when sorting keys, or an array listing an explicit order --- for keys. If a value itself is an array, it is taken so that the first element --- is a string representing the field name, and the second element is a priority table --- for that key. --- @return function: the iterator function. -function util.sortedpairs(tbl, sort_function) - return coroutine.wrap(function() sortedpairs_iterator(tbl, sort_function) end) + local i = 1 + return function() + local key = keys[i] + i = i + 1 + return key, tbl[key], sub_orders[key] + end end function util.lua_versions() -- cgit v1.2.3-55-g6feb