[lua-cwrap] 01/05: Imported Upstream version 0~20160222-gdbd0a62

Zhou Mo cdluminate-guest at moszumanska.debian.org
Fri Jun 3 06:27:54 UTC 2016


This is an automated email from the git hooks/post-receive script.

cdluminate-guest pushed a commit to branch master
in repository lua-cwrap.

commit 7ceae469e38c1239b6850254d8b7a5b65200e398
Author: Zhou Mo <cdluminate at gmail.com>
Date:   Thu Jun 2 03:29:10 2016 +0000

    Imported Upstream version 0~20160222-gdbd0a62
---
 CMakeLists.txt             |  11 ++
 COPYRIGHT.txt              |  36 +++++
 README.md                  |  17 +++
 cinterface.lua             | 368 +++++++++++++++++++++++++++++++++++++++++++++
 doc/argumenttypes.md       |  88 +++++++++++
 doc/example.md             |  42 ++++++
 doc/highlevelinterface.md  | 215 ++++++++++++++++++++++++++
 doc/index.md               |  19 +++
 doc/usertypes.md           | 192 +++++++++++++++++++++++
 init.lua                   |   7 +
 mkdocs.yml                 |  12 ++
 rocks/cwrap-scm-1.rockspec |  32 ++++
 types.lua                  | 183 ++++++++++++++++++++++
 13 files changed, 1222 insertions(+)

diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..db4010e
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,11 @@
+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)
+
diff --git a/COPYRIGHT.txt b/COPYRIGHT.txt
new file mode 100644
index 0000000..c9cc784
--- /dev/null
+++ b/COPYRIGHT.txt
@@ -0,0 +1,36 @@
+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.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..87a2f0b
--- /dev/null
+++ b/README.md
@@ -0,0 +1,17 @@
+# 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).
diff --git a/cinterface.lua b/cinterface.lua
new file mode 100644
index 0000000..ebf1171
--- /dev/null
+++ b/cinterface.lua
@@ -0,0 +1,368 @@
+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
diff --git a/doc/argumenttypes.md b/doc/argumenttypes.md
new file mode 100644
index 0000000..4a8ab55
--- /dev/null
+++ b/doc/argumenttypes.md
@@ -0,0 +1,88 @@
+<a name="CInterface.argtypes"></a>
+## 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.
diff --git a/doc/example.md b/doc/example.md
new file mode 100644
index 0000000..29e179a
--- /dev/null
+++ b/doc/example.md
@@ -0,0 +1,42 @@
+## 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: <tensor> 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!
diff --git a/doc/highlevelinterface.md b/doc/highlevelinterface.md
new file mode 100644
index 0000000..ff394f3
--- /dev/null
+++ b/doc/highlevelinterface.md
@@ -0,0 +1,215 @@
+## 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`.
+
+<a name="CInterface.new"></a>
+### new() ###
+
+Returns a new `CInterface`.
+
+<a name="CInterface.wrap"></a>
+### 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
+}
+)
+```
+
+<a name="CInterface.print"></a>
+### 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;
+]])
+```
+
+<a name="CInterface.luaname2wrapname"></a>
+### 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);
+]])
+```
+
+<a name="CInterface.tostring"></a>
+### tostring() ###
+
+Returns a string containing all the code generated by the `CInterface`
+until now. Note that the history is not erased.
+
+<a name="CInterface.tofile"></a>
+### 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.
+
+<a name="CInterface.clearhhistory"></a>
+### clearhistory() ###
+
+Forget about all the code generated by the `CInterface` until now.
+
diff --git a/doc/index.md b/doc/index.md
new file mode 100644
index 0000000..ba7b612
--- /dev/null
+++ b/doc/index.md
@@ -0,0 +1,19 @@
+# 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).
+
+
diff --git a/doc/usertypes.md b/doc/usertypes.md
new file mode 100644
index 0000000..5f7ac09
--- /dev/null
+++ b/doc/usertypes.md
@@ -0,0 +1,192 @@
+<a name="CInterface.userargtypes"></a>
+## 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.
+
+<a name='CInterface.arg.helpname'></a>
+### 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
+```
+
+<a name='CInterface.arg.declare'></a>
+### 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
+```
+
+<a name='CInterface.arg.check'></a>
+### 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
+```
+
+<a name='CInterface.arg.read'></a>
+### 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
+```
+
+<a name='CInterface.arg.init'></a>
+### 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
+```
+
+<a name='CInterface.arg.carg'></a>
+### 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
+```
+
+<a name='CInterface.arg.creturn'></a>
+### 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
+```
+
+<a name='CInterface.arg.precall'></a>
+### 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
+```
+
+<a name='CInterface.arg.postcall'></a>
+### 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
+```
+
diff --git a/init.lua b/init.lua
new file mode 100644
index 0000000..dabe086
--- /dev/null
+++ b/init.lua
@@ -0,0 +1,7 @@
+local cwrap = {}
+
+cwrap.types = require 'cwrap.types'
+cwrap.CInterface = require 'cwrap.cinterface'
+cwrap.CInterface.argtypes = cwrap.types
+
+return cwrap
diff --git a/mkdocs.yml b/mkdocs.yml
new file mode 100644
index 0000000..2f5e07c
--- /dev/null
+++ b/mkdocs.yml
@@ -0,0 +1,12 @@
+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]
diff --git a/rocks/cwrap-scm-1.rockspec b/rocks/cwrap-scm-1.rockspec
new file mode 100644
index 0000000..faec4e5
--- /dev/null
+++ b/rocks/cwrap-scm-1.rockspec
@@ -0,0 +1,32 @@
+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"
+      }
+   }
+}
diff --git a/types.lua b/types.lua
new file mode 100644
index 0000000..fb0cb3c
--- /dev/null
+++ b/types.lua
@@ -0,0 +1,183 @@
+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

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-science/packages/lua-cwrap.git



More information about the debian-science-commits mailing list