Permalink
Cannot retrieve contributors at this time
Name already in use
A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
luamarca/bench/arguments.lua
Go to fileThis commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
296 lines (256 sloc)
7.23 KB
This file contains 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
| local select, tostring, assert, type, error | |
| = select, tostring, assert, type, error | |
| -------------------------------------------------------------------------------- | |
| local run_plain_assert = function(a, b, c) | |
| assert(type(a) == "number") | |
| assert(type(b) == "boolean") | |
| assert(type(c) == "string") | |
| end | |
| -------------------------------------------------------------------------------- | |
| local run_assert_is | |
| do | |
| local make_assert_is = function(typename) | |
| return function(v, msg) | |
| if type(v) == typename then | |
| return v | |
| end | |
| error( | |
| (msg or "assertion failed") | |
| .. ": expected `" .. typename .. "', got `" | |
| .. type(v) .. "'", | |
| 3 | |
| ) | |
| end | |
| end | |
| local assert_is_number = make_assert_is("number") | |
| local assert_is_boolean = make_assert_is("boolean") | |
| local assert_is_string = make_assert_is("string") | |
| run_assert_is = function(a, b, c) | |
| assert_is_number(a) | |
| assert_is_boolean(b) | |
| assert_is_string(c) | |
| end | |
| end | |
| -------------------------------------------------------------------------------- | |
| local run_arguments_select_simple | |
| do | |
| local arguments_select = function(...) | |
| local nargs = select("#", ...) | |
| for i = 1, nargs, 2 do | |
| local expected_type, value = select(i, ...) | |
| if type(value) ~= expected_type then | |
| error( | |
| "bad argument #" .. ((i + 1) / 2) | |
| .. " type: expected `" .. expected_type | |
| .. "', got `" .. type(value) .. "'", | |
| 3 | |
| ) | |
| end | |
| end | |
| end | |
| run_arguments_select_simple = function(a, b, c) | |
| arguments_select( | |
| "number", a, | |
| "boolean", b, | |
| "string", c | |
| ) | |
| end | |
| end | |
| -------------------------------------------------------------------------------- | |
| local run_arguments_recursive_simple | |
| do | |
| -- Simplified lua-nucleo version, equivalent to the others. | |
| local function impl(arg_n, expected_type, value, ...) | |
| -- Points error on function, calling function which calls *arguments() | |
| if type(value) ~= expected_type then | |
| error( | |
| "argument #"..arg_n..": expected `"..tostring(expected_type) | |
| .. "', got `"..type(value).."'", | |
| 3 + arg_n | |
| ) | |
| end | |
| -- If have at least one more type, check it | |
| return ((...) ~= nil) and impl(arg_n + 1, ...) or true | |
| end | |
| local arguments_recursive = function(...) | |
| local nargs = select('#', ...) | |
| return (nargs > 0) | |
| and impl(1, ...) | |
| or true | |
| end | |
| run_arguments_recursive_simple = function(a, b, c) | |
| arguments_recursive( | |
| "number", a, | |
| "boolean", b, | |
| "string", c | |
| ) | |
| end | |
| end | |
| -------------------------------------------------------------------------------- | |
| local run_arguments_recursive_lua_nucleo | |
| do | |
| -- Taken directly from lua-nucleo | |
| local lua51_types = | |
| { | |
| ["nil"] = true; | |
| ["boolean"] = true; | |
| ["number"] = true; | |
| ["string"] = true; | |
| ["table"] = true; | |
| ["function"] = true; | |
| ["thread"] = true; | |
| ["userdata"] = true; | |
| } | |
| local function impl(is_optional, arg_n, expected_type, value, ...) | |
| -- Points error on function, calling function which calls *arguments() | |
| if type(value) ~= expected_type then | |
| if not lua51_types[expected_type] then | |
| error( | |
| "argument #"..arg_n..": bad expected type `"..tostring(expected_type).."'", | |
| 3 + arg_n | |
| ) | |
| end | |
| if not is_optional or value ~= nil then | |
| error( | |
| (is_optional and "optional" or "") | |
| .. "argument #"..arg_n..": expected `"..tostring(expected_type) | |
| .. "', got `"..type(value).."'", | |
| 3 + arg_n | |
| ) | |
| end | |
| end | |
| -- If have at least one more type, check it | |
| return ((...) ~= nil) and impl(is_optional, arg_n + 1, ...) or true | |
| end | |
| local arguments_recursive = function(...) | |
| local nargs = select('#', ...) | |
| return (nargs > 0) | |
| and ( | |
| (nargs % 2 == 0) | |
| and impl(false, 1, ...) -- Not optional | |
| or error("arguments: bad call, dangling argument detected") | |
| ) | |
| or true | |
| end | |
| run_arguments_recursive_lua_nucleo = function(a, b, c) | |
| arguments_recursive( | |
| "number", a, | |
| "boolean", b, | |
| "string", c | |
| ) | |
| end | |
| end | |
| -------------------------------------------------------------------------------- | |
| -- TODO: Add a version with full-blown validation. | |
| local run_arguments_unroll_simple | |
| do | |
| -- TODO: Put a code-generation metatable over cache | |
| -- and pre-populate it for cases with (1-10) * 2 arguments. | |
| -- If __index sees odd number, it should crash | |
| -- with dangling argument error. | |
| local arguments_cache = | |
| { | |
| [6] = function(t1, v1, t2, v2, t3, v3) | |
| if type(v1) ~= t1 then | |
| error( | |
| "argument #1: expected `"..tostring(t1) | |
| .. "', got `"..type(v1).."'", | |
| 4 | |
| ) | |
| end | |
| if type(v2) ~= t2 then | |
| error( | |
| "argument #2: expected `"..tostring(t2) | |
| .. "', got `"..type(v2).."'", | |
| 4 | |
| ) | |
| end | |
| if type(v3) ~= t3 then | |
| error( | |
| "argument #3: expected `"..tostring(t3) | |
| .. "', got `"..type(v3).."'", | |
| 4 | |
| ) | |
| end | |
| end; | |
| } | |
| local arguments = function(...) | |
| local n = select("#", ...) | |
| -- Assuming cache is pre-populated for all possible use-cases | |
| return assert(arguments_cache[n])(...) | |
| end | |
| run_arguments_unroll_simple = function(a, b, c) | |
| arguments( | |
| "number", a, | |
| "boolean", b, | |
| "string", c | |
| ) | |
| end | |
| end | |
| -------------------------------------------------------------------------------- | |
| local run_arguments_hardcoded_simple | |
| do | |
| -- Not much real-word meaning, just for comparison with | |
| -- run_arguments_unroll_simple. | |
| local hardcoded_arguments_6 = function(t1, v1, t2, v2, t3, v3) | |
| if type(v1) ~= t1 then | |
| error( | |
| "argument #1: expected `"..tostring(t1) | |
| .. "', got `"..type(v1).."'", | |
| 2 | |
| ) | |
| end | |
| if type(v2) ~= t2 then | |
| error( | |
| "argument #2: expected `"..tostring(t2) | |
| .. "', got `"..type(v2).."'", | |
| 2 | |
| ) | |
| end | |
| if type(v3) ~= t3 then | |
| error( | |
| "argument #3: expected `"..tostring(t3) | |
| .. "', got `"..type(v3).."'", | |
| 2 | |
| ) | |
| end | |
| end | |
| run_arguments_hardcoded_simple = function(a, b, c) | |
| hardcoded_arguments_6( | |
| "number", a, | |
| "boolean", b, | |
| "string", c | |
| ) | |
| end | |
| end | |
| -------------------------------------------------------------------------------- | |
| local bench = { } | |
| bench.plain_assert = function() | |
| run_plain_assert(42, true, "aaa") | |
| end | |
| bench.assert_is = function() | |
| run_assert_is(42, true, "aaa") | |
| end | |
| bench.assert_is_alloc = function() | |
| -- Imitating args table allocation. | |
| -- Needed to compensate plain Lua interpreter | |
| -- compatibility mode. | |
| local a, b, c = { }, { }, { } | |
| run_assert_is(42, true, "aaa") | |
| end | |
| bench.args_select_simple = function() | |
| run_arguments_select_simple(42, true, "aaa") | |
| end | |
| bench.args_recursive_simp = function() | |
| run_arguments_recursive_simple(42, true, "aaa") | |
| end | |
| bench.args_recursive_ln = function() | |
| run_arguments_recursive_lua_nucleo(42, true, "aaa") | |
| end | |
| bench.args_unroll_simple = function() | |
| run_arguments_unroll_simple(42, true, "aaa") | |
| end | |
| bench.args_hard_simple = function() | |
| run_arguments_hardcoded_simple(42, true, "aaa") | |
| end | |
| return bench |