From fed77c1b66063e4760665e9d71defe257886467f Mon Sep 17 00:00:00 2001 From: Ronan Collobert Date: Thu, 9 Feb 2012 12:14:19 +0100 Subject: finalizing wrap dok --- dok/index.dok | 216 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 212 insertions(+), 4 deletions(-) diff --git a/dok/index.dok b/dok/index.dok index fc7e9dd..715e7d2 100644 --- a/dok/index.dok +++ b/dok/index.dok @@ -134,6 +134,8 @@ properly the ''argtypes'' table. See the section [[#CInterface.argtypes]] for more details about defined types, and [[#CInterface.userargtypes|how to define additional ones]]. +=== Argument fields === + Apart the field ''name'', each list describing an argument can contain several optional fields: ''default'': this means the argument will optional in Lua, and the argument will be initialized @@ -156,6 +158,35 @@ recommended: use with care. While these optional fields are generic to any argument types, some types might define additional optional fields. Again, see [[#CInterface.argtypes]] for more details. +=== Handling multiple variants of arguments === + +Sometimes, one cannot describe fully the behavior one wants with only a set of possible arguments. +Take the example of the ''cos()'' function: we might want to apply it to a number, if the given argument +is a number, or to a Tensor, if the given argument is a Tensor. + +''wrap()'' can be called with extra pairs of ''cname, args'' if needed. (There are no limitations on the number extra paris). +For example, if you need to handle three cases, it might be + +interface:wrap(luaname, cname1, args1, cname2, args2, cname3, args3) + +For each given C function name ''cname'', the corresponding argument list ''args'' should match. +As a more concrete example, here is a way to generate a wrapper for ''cos()'', which would handle both numbers +and DoubleTensors. + +interface:wrap("cos", -- the Lua function name + +"THDoubleTensor_cos", { -- C function called for DoubleTensor +{name="DoubleTensor", default=true, returned=true}, -- returned tensor (if not present, we create an empty tensor) +{name="DoubleTensor"} -- input tensor +}, + +"cos", { -- the standard C math cos function +{name="double", creturned="true"}, -- returned value +{name="double"} -- input value +} +) + + ==== print(str) ==== {{anchor:CInterface.print}} @@ -321,9 +352,186 @@ check. E.g., expect a matrix of doubles. -===== Adding Your Own Types ===== +===== User Types ===== {{anchor:CInterface.userargtypes}} -arg.i -arg.__metatable -arg.args +Types available by default in ''CInterface'' might not be enough for your needs. Also, sometimes you might +need to change sliglty the behavior of existing types. In that sort of cases, you will need to +know more about what is going on under the hood. + +When you do a call to [[#CInterface.wrap|wrap()]], + +interface:wrap( + "numel", -- the Lua name + "numel", -- the C function name, here the same + -- now we describe the 'arguments' of the C function + -- (or possible returned values) + { + {name="DoubleTensor"}, + {name="int", creturned=true} -- this one is returned by the C function + } +) + +the method will examine each argument you provide. For example, let's consider: + +{name="int", creturned=true} + +Considering the argument field ''name'', **wrap** will check if the field +''interface.argtypes['int']'' exists or not. If it does not exist, an error will be raised. + +In order to describe what happens next, we will now denote + +arg = {name="int", creturned=true} + +First thing which is done is assigning ''interface.argtypes['int']'' as a metatable to ''arg'': + +setmetatable(arg, interface.argtypes[arg.name]) + +Then, a number of fields are populated in ''arg'' by **wrap**: + +arg.i = 2 -- argument index (in the argument list) in the wrap() call +arg.__metatable = interface.argtypes[arg.name] +arg.args = ... -- the full list of arguments given in the wrap() call + + + +[[#CInterface.wrap|wrap()]] will then call a several methods which are +assumed to be present in ''arg'' (see below for the list). Obviously, in +most cases, methods will be found in the metatable of ''arg'', that is in +''interface.argtypes[arg.name]''. However, if you need to override a method +behavior for one particular argument, this method could be defined in the +table describing the argument, when calling [[#CInterface.wrap|wrap()]]. + +The extra fields mentionned above (populated by **wrap**) can be used in the argument +methods to suit your needs (they are enough to handle most complex cases). + +We will now describe methods which must be defined for each type. We will +take as example ''boolean'', to make things more clear. If you want to see +more complex examples, you can have a look into the ''types.lua'' file, +provided by the **wrap** package. + +==== helpname(arg) ==== + +Returns a string describing (in a human readable fashion) the name of the given arg. + +Example: + +function helpname(arg) + return "boolean" +end + + +==== declare(arg) ==== + +Returns a C code string declaring the given arg. + +Example: + +function declare(arg) + return string.format("int arg%d = 0;", arg.i) +end + + +==== check(arg, idx) ==== + +Returns a C code string checking if the value at index ''idx'' on the Lua stack +corresponds to the argument type. The string will appended in a ''if()'', so it should +not contain a final '';''. + +Example: + +function check(arg, idx) + return string.format("lua_isboolean(L, %d)", idx) +end + + +==== read(arg, idx) ==== + +Returns a C code string converting the value a index ''idx'' on the Lua stack, into +the desired argument. This method will be called **only if** the C check given by +[[#CInterface.arg.check|check()]] succeeded. + +Example: + +function read(arg, idx) + return string.format("arg%d = lua_toboolean(L, %d);", arg.i, idx) +end + + +==== init(arg) ==== + +Returns a C code string initializing the argument by its default +value. This method will be called **only if** (1) ''arg'' has a ''default'' +field and (2) the C check given by [[#CInterface.arg.check|check()]] +failed (so the C code in [[#CInterface.arg.read|read()]] was not called). + +Example: + +function init(arg) + local default + if arg.default then + default = 1 + else + default = 0 + end + return string.format("arg%d = %s;", arg.i, default) +end + + +==== carg(arg) ==== + +Returns a C code string describing how to pass +the given ''arg'' as argument when calling the C function. + +In general, it is just the C arg name itself (except if you need to pass +the argument "by address", for example). + +Example: + +function carg(arg) + return string.format('arg%d', arg.i) +end + + +==== creturn(arg) ==== + +Returns a C code string describing how get the argument if it +is returned from the C function. + +In general, it is just the C arg name itself (except if you need to assign +a pointer value, for example). + + +function creturn(arg) + return string.format('arg%d', arg.i) +end + + +==== precall(arg) ==== + +Returns a C code string if you need to execute specific code related to +''arg'', before calling the C function. + +For e.g., if you created an object in the calls before, you might want to +put it on the Lua stack here, such that it is garbage collected by Lua, in case +the C function call fails. + + +function precall(arg) +-- nothing to do here, for boolean +end + + +==== postcall(arg) ==== + +Returns a C code string if you need to execute specific code related to +''arg'', after calling the C function. You can for e.g. push the argument +on the stack, if needed. + + +function postcall(arg) + if arg.creturned or arg.returned then + return string.format('lua_pushboolean(L, arg%d);', arg.i) + end +end + -- cgit v1.2.3