pax_global_header 0000666 0000000 0000000 00000000064 12662664226 0014526 g ustar 00root root 0000000 0000000 52 comment=dbd0a623dc4dfb4b8169d5aecc6dd9aec2f22792
CMakeLists.txt 0000664 0000000 0000000 00000000437 12662664226 0013636 0 ustar 00root root 0000000 0000000 CMAKE_MINIMUM_REQUIRED(VERSION 2.6 FATAL_ERROR)
CMAKE_POLICY(VERSION 2.6)
SET(src "")
SET(luasrc
${CMAKE_CURRENT_SOURCE_DIR}/init.lua
${CMAKE_CURRENT_SOURCE_DIR}/cinterface.lua
${CMAKE_CURRENT_SOURCE_DIR}/types.lua)
INSTALL(FILES ${luasrc} DESTINATION ${LUADIR}/cwrap)
COPYRIGHT.txt 0000664 0000000 0000000 00000004001 12662664226 0013176 0 ustar 00root root 0000000 0000000 Copyright (c) 2011-2014 Idiap Research Institute (Ronan Collobert)
Copyright (c) 2012-2014 Deepmind Technologies (Koray Kavukcuoglu)
Copyright (c) 2011-2012 NEC Laboratories America (Koray Kavukcuoglu)
Copyright (c) 2011-2013 NYU (Clement Farabet)
Copyright (c) 2006-2010 NEC Laboratories America (Ronan Collobert, Leon Bottou, Iain Melvin, Jason Weston)
Copyright (c) 2006 Idiap Research Institute (Samy Bengio)
Copyright (c) 2001-2004 Idiap Research Institute (Ronan Collobert, Samy Bengio, Johnny Mariethoz)
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the names of Deepmind Technologies, NYU, NEC Laboratories America
and IDIAP Research Institute nor the names of its contributors may be
used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
README.md 0000664 0000000 0000000 00000001435 12662664226 0012354 0 ustar 00root root 0000000 0000000 # CWrap package #
The __cwrap__ package helps you to automate the generation of Lua/C wrappers
around existing C functions, such that these functions would be callable
from Lua. This package is used by the __torch__ package, but does not depend on
anything, and could be used by anyone using Lua.
The documentation is organized as follows :
* [Example Use Case](doc/example.md)
* [High Level Interface](doc/highlevelinterface.md)
* [Argument Types](doc/argumenttypes.md)
* [User Types](doc/usertypes.md)
__DISCLAIMER__ Before going any further, we assume the reader has a good
knowledge of how to interface C functions with Lua. A good start would be
the [Lua reference manual](http://www.lua.org/manual/5.1), or the book
[Programming in Lua](http://www.inf.puc-rio.br/~roberto/pil2).
cinterface.lua 0000664 0000000 0000000 00000026136 12662664226 0013710 0 ustar 00root root 0000000 0000000 local CInterface = {}
function CInterface.new()
self = {}
self.txt = {}
self.registry = {}
self.defaultArguments = {}
setmetatable(self, {__index=CInterface})
return self
end
function CInterface:luaname2wrapname(name)
return string.format("wrapper_%s", name)
end
function CInterface:print(str)
table.insert(self.txt, str)
end
function CInterface:registerDefaultArgument(code)
table.insert(self.defaultArguments, code)
end
function CInterface:wrap(luaname, ...)
local txt = self.txt
local varargs = {...}
assert(#varargs > 0 and #varargs % 2 == 0, 'must provide both the C function name and the corresponding arguments')
-- add function to the registry
table.insert(self.registry, {name=luaname, wrapname=self:luaname2wrapname(luaname)})
self:__addchelpers()
table.insert(txt, string.format("static int %s(lua_State *L)", self:luaname2wrapname(luaname)))
table.insert(txt, "{")
table.insert(txt, "int narg = lua_gettop(L);")
for i, defaultArgCode in ipairs(self.defaultArguments) do
table.insert(txt, defaultArgCode(string.format("default_arg%d", i)))
end
if #varargs == 2 then
local cfuncname = varargs[1]
local args = varargs[2]
local helpargs, cargs, argcreturned = self:__writeheaders(txt, args)
self:__writechecks(txt, args)
table.insert(txt, 'else')
table.insert(txt, '{')
table.insert(txt, string.format('char type_buf[512];'))
table.insert(txt, string.format('str_arg_types(L, type_buf, 512);'))
table.insert(txt, string.format('luaL_error(L, "invalid arguments: %%s\\nexpected arguments: %s", type_buf);',
table.concat(helpargs, ' ')))
table.insert(txt, '}')
self:__writecall(txt, args, cfuncname, cargs, argcreturned)
else
local allcfuncname = {}
local allargs = {}
local allhelpargs = {}
local allcargs = {}
local allargcreturned = {}
table.insert(txt, "int argset = 0;")
for k=1,#varargs/2 do
allcfuncname[k] = varargs[(k-1)*2+1]
allargs[k] = varargs[(k-1)*2+2]
end
local argoffset = 0
for k=1,#varargs/2 do
allhelpargs[k], allcargs[k], allargcreturned[k] = self:__writeheaders(txt, allargs[k], argoffset)
argoffset = argoffset + #allargs[k]
end
for k=1,#varargs/2 do
self:__writechecks(txt, allargs[k], k)
end
table.insert(txt, 'else')
local allconcathelpargs = {}
for k=1,#varargs/2 do
table.insert(allconcathelpargs, table.concat(allhelpargs[k], ' '))
end
table.insert(txt, '{')
table.insert(txt, string.format('char type_buf[512];'))
table.insert(txt, string.format('str_arg_types(L, type_buf, 512);'))
table.insert(txt, string.format('luaL_error(L, "invalid arguments: %%s\\nexpected arguments: %s", type_buf);',
table.concat(allconcathelpargs, ' | ')))
table.insert(txt, '}')
for k=1,#varargs/2 do
if k == 1 then
table.insert(txt, string.format('if(argset == %d)', k))
else
table.insert(txt, string.format('else if(argset == %d)', k))
end
table.insert(txt, '{')
self:__writecall(txt, allargs[k], allcfuncname[k], allcargs[k], allargcreturned[k])
table.insert(txt, '}')
end
table.insert(txt, 'return 0;')
end
table.insert(txt, '}')
table.insert(txt, '')
end
function CInterface:__addchelpers()
if not self.__chelpers_added then
local txt = self.txt
table.insert(txt, '#ifndef _CWRAP_STR_ARG_TYPES_4821726c1947cdf3eebacade98173939')
table.insert(txt, '#define _CWRAP_STR_ARG_TYPES_4821726c1947cdf3eebacade98173939')
table.insert(txt, '#include "string.h"')
table.insert(txt, 'static void str_arg_types(lua_State *L, char *buf, int n) {')
table.insert(txt, ' int i;')
table.insert(txt, ' int nargs = lua_gettop(L);')
table.insert(txt, ' if (nargs == 0) {')
table.insert(txt, ' snprintf(buf, n, "no arguments provided");')
table.insert(txt, ' return;')
table.insert(txt, ' }')
table.insert(txt, ' for (i = 1; i <= nargs; i++) {')
table.insert(txt, ' int l;')
table.insert(txt, ' const char *torch_type = luaT_typename(L, i);')
table.insert(txt, ' if(torch_type && !strncmp(torch_type, "torch.", 6)) torch_type += 6;')
table.insert(txt, ' if (torch_type) l = snprintf(buf, n, "%s ", torch_type);')
table.insert(txt, ' else if(lua_isnil(L, i)) l = snprintf(buf, n, "%s ", "nil");')
table.insert(txt, ' else if(lua_isboolean(L, i)) l = snprintf(buf, n, "%s ", "boolean");')
table.insert(txt, ' else if(lua_isnumber(L, i)) l = snprintf(buf, n, "%s ", "number");')
table.insert(txt, ' else if(lua_isstring(L, i)) l = snprintf(buf, n, "%s ", "string");')
table.insert(txt, ' else if(lua_istable(L, i)) l = snprintf(buf, n, "%s ", "table");')
table.insert(txt, ' else if(lua_isuserdata(L, i)) l = snprintf(buf, n, "%s ", "userdata");')
table.insert(txt, ' else l = snprintf(buf, n, "%s ", "???");')
table.insert(txt, ' if (l >= n) return;')
table.insert(txt, ' buf += l;')
table.insert(txt, ' n -= l;')
table.insert(txt, ' }')
table.insert(txt, '}')
table.insert(txt, '#endif')
self.__chelpers_added = true
end
end
function CInterface:register(name)
local txt = self.txt
table.insert(txt, string.format('static const struct luaL_Reg %s [] = {', name))
for _,reg in ipairs(self.registry) do
table.insert(txt, string.format('{"%s", %s},', reg.name, reg.wrapname))
end
table.insert(txt, '{NULL, NULL}')
table.insert(txt, '};')
table.insert(txt, '')
self.registry = {}
end
function CInterface:clearhistory()
self.txt = {}
self.registry = {}
self.defaultArguments = {}
end
function CInterface:tostring()
return table.concat(self.txt, '\n')
end
function CInterface:tofile(filename)
local f = io.open(filename, 'w')
f:write(table.concat(self.txt, '\n'))
f:close()
end
local function bit(p)
return 2 ^ (p - 1) -- 1-based indexing
end
local function hasbit(x, p)
return x % (p + p) >= p
end
local function beautify(txt)
local indent = 0
for i=1,#txt do
if txt[i]:match('}') then
indent = indent - 2
end
if indent > 0 then
txt[i] = string.rep(' ', indent) .. txt[i]
end
if txt[i]:match('{') then
indent = indent + 2
end
end
end
local function tableinsertcheck(tbl, stuff)
if stuff and not stuff:match('^%s*$') then
table.insert(tbl, stuff)
end
end
function CInterface:__writeheaders(txt, args, argoffset)
local argtypes = self.argtypes
local helpargs = {}
local cargs = {}
local argcreturned
argoffset = argoffset or 0
for i,arg in ipairs(args) do
arg.i = i+argoffset
arg.args = args -- in case we want to do stuff depending on other args
assert(argtypes[arg.name], 'unknown type ' .. arg.name)
setmetatable(arg, {__index=argtypes[arg.name]})
arg.__metatable = argtypes[arg.name]
tableinsertcheck(txt, arg:declare())
local helpname = arg:helpname()
if arg.returned then
helpname = string.format('*%s*', helpname)
end
if arg.invisible and arg.default == nil then
error('Invisible arguments must have a default! How could I guess how to initialize it?')
end
if arg.default ~= nil then
if not arg.invisible then
table.insert(helpargs, string.format('[%s]', helpname))
end
elseif not arg.creturned then
table.insert(helpargs, helpname)
end
if arg.creturned then
if argcreturned then
error('A C function can only return one argument!')
end
if arg.default ~= nil then
error('Obviously, an "argument" returned by a C function cannot have a default value')
end
if arg.returned then
error('Options "returned" and "creturned" are incompatible')
end
argcreturned = arg
else
table.insert(cargs, arg:carg())
end
end
return helpargs, cargs, argcreturned
end
function CInterface:__writechecks(txt, args, argset)
local argtypes = self.argtypes
local multiargset = argset
argset = argset or 1
local nopt = 0
for i,arg in ipairs(args) do
if arg.default ~= nil and not arg.invisible then
nopt = nopt + 1
end
end
for variant=0,(2^nopt)-1 do
local opt = 0
local currentargs = {}
local optargs = {}
local hasvararg = false
for i,arg in ipairs(args) do
if arg.invisible then
table.insert(optargs, arg)
elseif arg.default ~= nil then
opt = opt + 1
if hasbit(variant, bit(opt)) then
table.insert(currentargs, arg)
else
table.insert(optargs, arg)
end
elseif not arg.creturned then
table.insert(currentargs, arg)
end
end
for _,arg in ipairs(args) do
if arg.vararg then
if hasvararg then
error('Only one argument can be a "vararg"!')
end
hasvararg = true
end
end
if hasvararg and not currentargs[#currentargs].vararg then
error('Only the last argument can be a "vararg"')
end
local compop
if hasvararg then
compop = '>='
else
compop = '=='
end
if variant == 0 and argset == 1 then
table.insert(txt, string.format('if(narg %s %d', compop, #currentargs))
else
table.insert(txt, string.format('else if(narg %s %d', compop, #currentargs))
end
for stackidx, arg in ipairs(currentargs) do
table.insert(txt, string.format("&& %s", arg:check(stackidx)))
end
table.insert(txt, ')')
table.insert(txt, '{')
if multiargset then
table.insert(txt, string.format('argset = %d;', argset))
end
for stackidx, arg in ipairs(currentargs) do
tableinsertcheck(txt, arg:read(stackidx))
end
for _,arg in ipairs(optargs) do
tableinsertcheck(txt, arg:init())
end
table.insert(txt, '}')
end
end
function CInterface:__writecall(txt, args, cfuncname, cargs, argcreturned)
local argtypes = self.argtypes
for i = 1, #self.defaultArguments do
table.insert(cargs, i, string.format('default_arg%d', i))
end
for _,arg in ipairs(args) do
tableinsertcheck(txt, arg:precall())
end
if argcreturned then
table.insert(txt, string.format('%s = %s(%s);', argtypes[argcreturned.name].creturn(argcreturned), cfuncname, table.concat(cargs, ',')))
else
table.insert(txt, string.format('%s(%s);', cfuncname, table.concat(cargs, ',')))
end
for _,arg in ipairs(args) do
tableinsertcheck(txt, arg:postcall())
end
local nret = 0
if argcreturned then
nret = nret + 1
end
for _,arg in ipairs(args) do
if arg.returned then
nret = nret + 1
end
end
table.insert(txt, string.format('return %d;', nret))
end
return CInterface
doc/ 0000775 0000000 0000000 00000000000 12662664226 0011637 5 ustar 00root root 0000000 0000000 doc/argumenttypes.md 0000664 0000000 0000000 00000007575 12662664226 0015106 0 ustar 00root root 0000000 0000000
## Argument Types ##
Any `CInterface` is initialized with a default `argtypes` list, at
creation. This list tells to `CInterface` how to handle type names given
to the [wrap()](higherlevelinterface.md#CInterface.wrap) method. The user can add more types to
this list, if wanted (see [the next section](usertypes.md#CInterface.userargtypes)).
### Standard C types ###
Standard type names include `unsigned char`, `char`, `short`,
`int`, `long`, `float` and `double`. They define the corresponding
C types, which are converted to/from
[lua_Number](http://www.lua.org/manual/5.1/manual.html#lua_Number).
Additionaly, `byte` is an equivalent naming for `unsigned char`, and
`boolean` is interpreted as a boolean in Lua, and an int in C.
`real` will also be converted to/from a `lua_Number`, while assuming that
it is defined in C as `float` or `double`.
Finally, `index` defines a long C value, which is going to be
automatically incremented by 1 when going from C to Lua, and decremented by
1, when going from Lua to C. This matches Lua policy of having table
indices starting at 1, and C array indices starting at 0.
For all these number values, the `default` field (when defining the
argument in [wrap()](higherlevelinterface.md##CInterface.wrap)) can take two types: either a
number or a function (taking the argument table as argument, and returning a string).
Note that in case of an `index` type, the given default value (or result
given by the default initialization function) will be decremented by 1 when
initializing the corresponging C `long` variable.
Here is an example of defining arguments with a default value:
```lua
{name="int", default=0}
```
defines an optional argument which will of type `int` in C (lua_Number in Lua), and will take
the value `0` if it is not present when calling the Lua function. A more complicated (but typical) example
would be:
```lua
{name="int", default=function(arg)
return string.format("%s", arg.args[1]:carg())
end}
```
In this case, the argument will be set to the value of the first argument in the Lua function call, if not
present at call time.
### Torch Tensor types ###
`CInterface` also defines __Torch__ tensor types: `ByteTensor`,
`CharTensor`, `ShortTensor`, `IntTensor`, `LongTensor`,
`FloatTensor` and `DoubleTensor`, which corresponds to their
`THByteTensor`, etc... counterparts. All of them assume that the
[luaT](..:luaT) Tensor id (here for ByteTensor)
```
const void *torch_ByteTensor_id;
```
is defined beforehand, and properly initialized.
Additionally, if you use C-templating style which is present in the TH library, you might want
to use the `Tensor` typename, which assumes that `THTensor` is properly defined, as well as
the macro `THTensor_()` and `torch_()` (see the TH library for more details).
Another extra typename of interest is `IndexTensor`, which corresponds to a `THLongTensor` in C. Values in this
LongTensor will be incremented/decremented when going from/to C/Lua to/from Lua/C.
Tensor typenames `default` value in [wrap()](higherlevelinterface.md#CInterface.wrap) can take take two types:
* A boolean. If `true`, the tensor will be initialized as empty, if not present at the Lua function call
* A number (index). If not present at the Lua function call, the tensor will be initialized as _pointing_ to the argument at the given index (which must be a tensor of same type!).
For e.g, the list of arguments:
```lua
{
{name=DoubleTensor, default=3},
{name=double, default=1.0},
{name=DoubleTensor}
}
```
The first two arguments are optional. The first one is a DoubleTensor which
will point on the last (3rd) argument if not given. The second argument
will be initialized to `1.0` if not provided.
Tensor typenames can also take an additional field `dim` (a number) which will force a dimension
check. E.g.,
```lua
{name=DoubleTensor, dim=2}
```
expect a matrix of doubles.
doc/example.md 0000664 0000000 0000000 00000002552 12662664226 0013620 0 ustar 00root root 0000000 0000000 ## Example Use Case
As an example is often better than lengthy explanations, let's consider the
case of a function
```c
int numel(THDoubleTensor *t);
```
which returns the number of elements of `t`.
Writing a complete wrapper of this function would look like:
```c
static int wrapper_numel(lua_State *L)
{
THDoubleTensor *t;
/* always good to check the number of arguments */
if(lua_gettop(L) != 1)
error("invalid number of arguments: expected");
/* check if we have a tensor on the stack */
/* we use the luaT library, which deals with Torch objects */
/* we assume the torch_DoubleTensor_id has been already initialized */
t = luaT_checkudata(L, 1, torch_DoubleTensor_id);
/* push result on stack */
lua_pushnumber(L, numel(t));
/* the number of returned variables */
return 1;
}
```
For anybody familiar with the Lua C API, this should look very simple (and
_it is simple_, Lua has been designed for that!). Nevertheless, the
wrapper contains about 7 lines of C code, for a quite simple
function. Writing wrappers for C functions with multiple arguments, where
some of them might be optional, can become very quickly a tedious task. The
__wrap__ package is here to help the process. Remember however that even
though you might be able to treat most complex cases with __wrap__,
sometimes it is also good to do everything by hand yourself!
doc/highlevelinterface.md 0000664 0000000 0000000 00000017013 12662664226 0016013 0 ustar 00root root 0000000 0000000 ## High Level Interface ##
__wrap__ provides only one class: `CInterface`. Considering our easy example, a typical usage
would be:
```lua
require 'wrap'
interface = wrap.CInterface.new()
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
}
)
print(interface:tostring())
```
`CInterface` contains only few methods. [wrap()](highlevelinterface.md#CInterface.wrap) is
the most important one. [tostring()](highlevelinterface.md#CInterface.tostring) returns a
string containing all the code produced until now. The wrapper generated
by __wrap__ is quite similar to what one would write by hand:
```c
static int wrapper_numel(lua_State *L)
{
int narg = lua_gettop(L);
THDoubleTensor *arg1 = NULL;
int arg2 = 0;
if(narg == 1
&& (arg1 = luaT_toudata(L, 1, torch_DoubleTensor_id))
)
{
}
else
luaL_error(L, "expected arguments: DoubleTensor");
arg2 = numel(arg1);
lua_pushnumber(L, (lua_Number)arg2);
return 1;
}
```
We know describe the methods provided by `CInterface`.
### new() ###
Returns a new `CInterface`.
### wrap(luaname, cfunction, arguments, ...) ###
Tells the `CInterface` to generate a wrapper around the C function
`cfunction`. The function will be called from Lua under the name
`luaname`. The Lua _list_ `arguments` must also be provided. It
describes _all_ the arguments of the C function `cfunction`.
Optionally, if the C function returns a value and one would like to return
it in Lua, this additional value can be also described in the argument
list.
```lua
{
{name="DoubleTensor"},
{name="int", creturned=true} -- this one is returned by the C function
}
```
Each argument is described also as a list. The list must at least contain
the field `name`, which tells to `CInterface` what type of argument you
want to define. In the above example,
```lua
{name="DoubleTensor"}
```
indicates to `CInterface` that the first argument of `numel()` is of type `DoubleTensor`.
Arguments are defined into a table `CInterface.argtypes`, defined at the
creation of the interface. Given a `typename`, the corresponding field
in `interface.argtypes[typename]` must exist, such that `CInterface`
knows how to handle the specified argument. A lot of types are already
created by default, but the user can define more if needed, by filling
properly the `argtypes` table. See the section [[argumenttypes.md#CInterface.argtypes]]
for more details about defined types, and
[how to define additional ones](usertypes.md#CInterface.userargtypes).
#### 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
with the given default value if not present in the Lua function call. The `default` value might
have different meanings, depending on the argument type (see [[argumenttypes.md#CInterface.argtypes]] for more details).
`invisible`: the argument will invisible _from Lua_. This special option requires `default` to be set,
such that `CInterface` knows by what initialize this invisible argument.
`returned`: if set to `true`, the argument will be returned by the Lua function. Note that several
values might be returned at the same time in Lua.
`creturned`: if `true`, tells to `CInterface` that this 'argument' is
in fact the value returned by the C function. This 'argument' cannot have
a `default` value. Also, as in C one can return only one value, only one
'argument' can contain this field! Mixing arguments which are `returned`
and arguments which are `creturned` with `CInterface` is not
recommended: use with care.
While these optional fields are generic to any argument types, some types might define additional optional fields.
Again, see [[argumenttypes.md#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
```lua
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.
```lua
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) ###
Add some hand-crafted code to the existing generated code. You might want to do that if your wrapper
requires manual tweaks. For e.g., in the example above, the "id" related to `torch.DoubleTensor`
needs to be defined beforehand:
```lua
interface:print([[
const void* torch_DoubleTensor_id;
]])
```
### luaname2wrapname(name) ###
This method defines the name of each generated wrapping function (like
`wrapper_numel` in the example above), given the Lua name of a function
(say `numel`). In general, this has little importance, as the wrapper is
a static function which is not going to be called outside the scope of the
wrap file. However, if you generate some complex wrappers, you might want
to have a control on this to avoid name clashes. The default is
```lua
function CInterface:luaname2wrapname(name)
return string.format("wrapper_%s", name)
end
```
Changing it to something else can be easily done with (still following the example above)
```lua
function interface:luaname2wrapname(name)
return string.format("my_own_naming_%s", name)
end
```
### register(name) ###
Produces C code defining a
[luaL_Reg](http://www.lua.org/manual/5.1/manual.html#luaL_Reg) structure
(which will have the given `name`). In the above example, calling
```lua
interface:register('myfuncs')
```
will generate the following additional code:
```c
static const struct luaL_Reg myfuncs [] = {
{"numel", wrapper_numel},
{NULL, NULL}
};
```
This structure is meant to be passed as argument to
[luaL_register](http://www.lua.org/manual/5.1/manual.html#luaL_register),
such that Lua will be aware of your new functions. For e.g., the following
would declare `mylib.numel` in Lua:
```lua
interface:print([[
luaL_register(L, "mylib", myfuncs);
]])
```
### tostring() ###
Returns a string containing all the code generated by the `CInterface`
until now. Note that the history is not erased.
### tofile(filename) ###
Write in the file (named after `filename`) all the code generated by the
`CInterface` until now. Note that the history is not erased.
### clearhistory() ###
Forget about all the code generated by the `CInterface` until now.
doc/index.md 0000664 0000000 0000000 00000001417 12662664226 0013273 0 ustar 00root root 0000000 0000000 # CWrap package #
The __cwrap__ package helps you to automate the generation of Lua/C wrappers
around existing C functions, such that these functions would be callable
from Lua. This package is used by the __torch__ package, but does not depend on
anything, and could be used by anyone using Lua.
The documentation is organized as follows :
* [Example Use Case](example.md)
* [High Level Interface](highlevelinterface.md)
* [Argument Types](argumenttypes.md)
* [User Types](usertypes.md)
__DISCLAIMER__ Before going any further, we assume the reader has a good
knowledge of how to interface C functions with Lua. A good start would be
the [Lua reference manual](http://www.lua.org/manual/5.1), or the book
[Programming in Lua](http://www.inf.puc-rio.br/~roberto/pil2).
doc/usertypes.md 0000664 0000000 0000000 00000012707 12662664226 0014233 0 ustar 00root root 0000000 0000000
## User Types ##
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 [wrap()](highlevelinterface.md#CInterface.wrap),
```lua
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:
```lua
{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
```lua
arg = {name="int", creturned=true}
```
First thing which is done is assigning `interface.argtypes['int']` as a metatable to `arg`:
```lua
setmetatable(arg, interface.argtypes[arg.name])
```
Then, a number of fields are populated in `arg` by __wrap__:
```lua
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
```
[wrap()](highlevelinterface.md#CInterface.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 [wrap()](highlevelinterface.md#CInterface.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:
```lua
function helpname(arg)
return "boolean"
end
```
### declare(arg) ###
Returns a C code string declaring the given arg.
Example:
```lua
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:
```lua
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
[check()](#CInterface.arg.check) succeeded.
Example:
```lua
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 [check()](#CInterface.arg.check)
failed (so the C code in [read()](#CInterface.arg.read) was not called).
Example:
```lua
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:
```lua
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).
```lua
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.
```lua
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.
```lua
function postcall(arg)
if arg.creturned or arg.returned then
return string.format('lua_pushboolean(L, arg%d);', arg.i)
end
end
```
init.lua 0000664 0000000 0000000 00000000232 12662664226 0012535 0 ustar 00root root 0000000 0000000 local cwrap = {}
cwrap.types = require 'cwrap.types'
cwrap.CInterface = require 'cwrap.cinterface'
cwrap.CInterface.argtypes = cwrap.types
return cwrap
mkdocs.yml 0000664 0000000 0000000 00000000500 12662664226 0013070 0 ustar 00root root 0000000 0000000 site_name: cwrap
theme : simplex
repo_url : https://github.com/torch/cwrap
use_directory_urls : false
markdown_extensions: [extra]
docs_dir : doc
pages:
- [index.md, CWrap]
- [example.md, Example Use Case]
- [highlevelinterface.md, High Level Interface]
- [argumenttypes.md, Argument Types]
- [usertypes.md, User Types]
rocks/ 0000775 0000000 0000000 00000000000 12662664226 0012213 5 ustar 00root root 0000000 0000000 rocks/cwrap-scm-1.rockspec 0000664 0000000 0000000 00000001055 12662664226 0016001 0 ustar 00root root 0000000 0000000 package = "cwrap"
version = "scm-1"
source = {
url = "git://github.com/torch/cwrap.git",
}
description = {
summary = "Advanced automatic wrapper for C functions",
detailed = [[
]],
homepage = "https://github.com/torch/cwrap",
license = "BSD"
}
dependencies = {
"lua >= 5.1",
}
build = {
type = "builtin",
modules = {
["cwrap.init"] = "init.lua",
["cwrap.cinterface"] = "cinterface.lua",
["cwrap.types"] = "types.lua",
},
install = {
lua = {
["cwrap.README"] = "README.md"
}
}
}
types.lua 0000664 0000000 0000000 00000012504 12662664226 0012743 0 ustar 00root root 0000000 0000000 local argtypes = {}
local function interpretdefaultvalue(arg)
local default = arg.default
if type(default) == 'boolean' then
if default then
return '1'
else
return '0'
end
elseif type(default) == 'number' then
return tostring(default)
elseif type(default) == 'string' then
return default
elseif type(default) == 'function' then
default = default(arg)
assert(type(default) == 'string', 'a default function must return a string')
return default
elseif type(default) == 'nil' then
return nil
else
error('unknown default type value')
end
end
argtypes.index = {
helpname = function(arg)
return "index"
end,
declare = function(arg)
-- if it is a number we initialize here
local default = tonumber(interpretdefaultvalue(arg)) or 1
return string.format("long arg%d = %d;", arg.i, tonumber(default)-1)
end,
check = function(arg, idx)
return string.format("lua_isnumber(L, %d)", idx)
end,
read = function(arg, idx)
return string.format("arg%d = (long)lua_tonumber(L, %d)-1;", arg.i, idx)
end,
init = function(arg)
-- otherwise do it here
if arg.default then
local default = interpretdefaultvalue(arg)
if not tonumber(default) then
return string.format("arg%d = %s-1;", arg.i, default)
end
end
end,
carg = function(arg)
return string.format('arg%d', arg.i)
end,
creturn = function(arg)
return string.format('arg%d', arg.i)
end,
precall = function(arg)
if arg.returned then
return string.format('lua_pushnumber(L, (lua_Number)arg%d+1);', arg.i)
end
end,
postcall = function(arg)
if arg.creturned then
return string.format('lua_pushnumber(L, (lua_Number)arg%d+1);', arg.i)
end
end
}
for _,typename in ipairs({"real", "unsigned char", "char", "short", "int", "long", "float", "double"}) do
argtypes[typename] = {
helpname = function(arg)
return typename
end,
declare = function(arg)
-- if it is a number we initialize here
local default = tonumber(interpretdefaultvalue(arg)) or 0
return string.format("%s arg%d = %g;", typename, arg.i, default)
end,
check = function(arg, idx)
return string.format("lua_isnumber(L, %d)", idx)
end,
read = function(arg, idx)
return string.format("arg%d = (%s)lua_tonumber(L, %d);", arg.i, typename, idx)
end,
init = function(arg)
-- otherwise do it here
if arg.default then
local default = interpretdefaultvalue(arg)
if not tonumber(default) then
return string.format("arg%d = %s;", arg.i, default)
end
end
end,
carg = function(arg)
return string.format('arg%d', arg.i)
end,
creturn = function(arg)
return string.format('arg%d', arg.i)
end,
precall = function(arg)
if arg.returned then
return string.format('lua_pushnumber(L, (lua_Number)arg%d);', arg.i)
end
end,
postcall = function(arg)
if arg.creturned then
return string.format('lua_pushnumber(L, (lua_Number)arg%d);', arg.i)
end
end
}
end
argtypes.byte = argtypes['unsigned char']
argtypes.boolean = {
helpname = function(arg)
return "boolean"
end,
declare = function(arg)
-- if it is a number we initialize here
local default = tonumber(interpretdefaultvalue(arg)) or 0
return string.format("int arg%d = %d;", arg.i, tonumber(default))
end,
check = function(arg, idx)
return string.format("lua_isboolean(L, %d)", idx)
end,
read = function(arg, idx)
return string.format("arg%d = lua_toboolean(L, %d);", arg.i, idx)
end,
init = function(arg)
-- otherwise do it here
if arg.default then
local default = interpretdefaultvalue(arg)
if not tonumber(default) then
return string.format("arg%d = %s;", arg.i, default)
end
end
end,
carg = function(arg)
return string.format('arg%d', arg.i)
end,
creturn = function(arg)
return string.format('arg%d', arg.i)
end,
precall = function(arg)
if arg.returned then
return string.format('lua_pushboolean(L, arg%d);', arg.i)
end
end,
postcall = function(arg)
if arg.creturned then
return string.format('lua_pushboolean(L, arg%d);', arg.i)
end
end
}
return argtypes