2

I find Swig failed to generate some temporary variables defined in typemap.

Here is the problem: I have defined a typemap as follow.

%define %bound_buffer_input(TYPEMAP, SIZE)
%typemap(in) (TYPEMAP, SIZE)
  (int res, Py_ssize_t size = 0, const void *buf = 0) {
  res = PyObject_AsReadBuffer($input, &buf, &size);
  if (res<0) {
    PyErr_Clear();
    %argument_fail(res, "(TYPEMAP, SIZE)", $symname, $argnum);
  }
  $1 = ($1_ltype) buf;
  $2 = ($2_ltype) size;
}
%enddef

And it is applied in 2 cases:

%bound_buffer_input(const uint8_t* key, size_t keyLength);
%bound_buffer_input(void* buf, size_t length);

For the first, it works well and generated correct codes. But for the second, it fails to generate correct variable name for the function : void* MF_WriteOne (void * qry, int datatype, void* buf, size_t length);

The code swig generates:

 {
    res3 = PyObject_AsReadBuffer(obj2, &buf3, &size3);
    if (res3<0) {
      PyErr_Clear();
      SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "MF_WriteOne" "', argument " "3"" of type '" "(void* buf, size_t length)""'");
    }
    arg3 = (void *) buf;
    arg4 = (size_t) size3;
  }

In the first line, the variable "buf" is correctly generated with the name "buf3", but for the 6th line the variable has the incorrect name "buf" instead of "buf3".

Later I change the name from "buf to buff" and find the variable are all under correct names.

Why happens such a strange thing?

Stan
  • 79
  • 3
  • As a general tip for asking/answering questions although your question is pretty clear it would be quicker and easier for others to test and answer your question if you made it a complete example rather than an almost complete one. (In my answer I added 5 more lines and made it something I really could pass to SWIG and then run in Python as is for testing). – Flexo Jul 08 '14 at 20:51

1 Answers1

1

The problem is that your typemap has a name clash. The name of the variable passed to the function is buf and the name of the variable (pre-automatic rename) is buf also.

SWIG is trying to be clever and use the contextually correct one, but that's not the behaviour you're hoping for. You can fix this in one of several ways:

  1. Rename one or both of the two bufs as you noted
  2. Change the name given to the macro, but use %apply to still match on buf as an argument name:

    %module test
    
    %define %bound_buffer_input(TYPEMAP, SIZE)
    %typemap(in) (TYPEMAP, SIZE)
      (int res, Py_ssize_t size = 0, const void *buf = 0) {
      res = PyObject_AsReadBuffer($input, &buf, &size);
      if (res<0) {
        PyErr_Clear();
        %argument_fail(res, "(TYPEMAP, SIZE)", $symname, $argnum);
      }
      $1 = ($1_ltype) buf;
      $2 = ($2_ltype) size;
    }
    %enddef
    
    %bound_buffer_input(const uint8_t* key, size_t keyLength);
    %bound_buffer_input(void* buffer, size_t length);
    
    %apply (void* buffer, size_t length) { (void* buf, size_t length) };
    
    %inline %{
    void test1(const uint8_t* key, size_t keyLength) {}
    void test2(void* buf, size_t length) {}
    %}
    
  3. Do the automatic rename of the locals yourself, manually, with noblock=1 in the typemap and no temporaries:

    %module test
    
    %define %bound_buffer_input(TYPEMAP, SIZE)
         %typemap(in,noblock=1) (TYPEMAP, SIZE) {
      int res$argnum;
      Py_ssize_t size$argnum = 0;
      const void *buf$argnum = 0;
      res$argnum = PyObject_AsReadBuffer($input, &buf$argnum, &size$argnum);
      if (res$argnum<0) {
        PyErr_Clear();
        %argument_fail(res$argnum, "(TYPEMAP, SIZE)", $symname, $argnum);
      }
      $1 = ($1_ltype) buf$argnum;
      $2 = ($2_ltype) size$argnum;
    }
    %enddef
    
    %bound_buffer_input(const uint8_t* key, size_t keyLength);
    %bound_buffer_input(void* buf, size_t length);
    
    %inline %{
    void test1(const uint8_t* key, size_t keyLength) {}
    void test2(void* buf, size_t length) {}
    %}
    

Finally, unless you're targeting Python 2.6 and older you should use Python's newer memory views instead

Community
  • 1
  • 1
Flexo
  • 87,323
  • 22
  • 191
  • 272
  • Thank you, Flexo :) The 3rd method seems a better way. Who knows the developper who maintaining this package after me prefer to use which variable name? haha. The program is 14 years old and kinda stick to python 2.6. That is why I cannot use memory view objects :S – Stan Jul 10 '14 at 08:47