SWIG: как обернуть std :: string & (std :: string, переданный по ссылке) - PullRequest
11 голосов
/ 20 сентября 2010

Я использую SWIG для доступа к коду C ++ из Java.

Какой самый простой способ показать параметр std :: string, переданный по неконстантной ссылке?

У меня есть примитивы, переданныепо ссылке, представленной в виде массивов Java, благодаря typemaps.i, а const std::string& - как java.lang.String, благодаря std_string.i.Но неконстантный std :: string & отображается как непрозрачный тип указателя SWIGTYPE_p_std__string.

Ток:

// C++ method                     -> // Java wrapper of C++ method
void foo( int & i )               -> public void foo( int[] i );    // OK
void bar( const std::string & s ) -> public void bar( String s );   // OK
void baz( std::string & s )       -> public void baz( SWIGTYPE_p_std__string s ); // :(

Желаемый:

void foo( int & i )               -> public void foo( int[] i );    // OK
void bar( const std::string & s ) -> public void bar( String s );   // OK
void baz( std::string & s )       -> public void baz( String[] s ); // OK

ОБНОВЛЕНИЕ : Я нашел решение , описанное ниже.Однако это заняло больше усилий, чем несколько секунд.Мне все еще интересно услышать о легких подходах.

1 Ответ

7 голосов
/ 30 сентября 2010

Лучший подход, который я смог найти, - написать свою собственную карту типов. Я надеялся на несколько простых инструкций SWIG.

Если кому-то еще это понадобится, вот как я это сделал. Имейте в виду, что я не эксперт SWIG.

Во-первых, вам нужно определить несколько типов карт, которые будут применяться к std :: string & arguments. Вы должны определить их только один раз. (Примечание: в некоторых конфигурациях могут потребоваться дополнительные карты типов).

%typemap(jni) std::string *INOUT, std::string &INOUT %{jobjectArray%}
%typemap(jtype) std::string *INOUT, std::string &INOUT "java.lang.String[]"
%typemap(jstype) std::string *INOUT, std::string &INOUT "java.lang.String[]"
%typemap(javain) std::string *INOUT, std::string &INOUT "$javainput"

%typemap(in) std::string *INOUT (std::string strTemp ), std::string &INOUT (std::string strTemp ) {
  if (!$input) {
    SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "array null");
    return $null;
  }
  if (JCALL1(GetArrayLength, jenv, $input) == 0) {
    SWIG_JavaThrowException(jenv, SWIG_JavaIndexOutOfBoundsException, "Array must contain at least 1 element");
    return $null;
  }

  jobject oInput = JCALL2(GetObjectArrayElement, jenv, $input, 0); 
  if ( NULL != oInput ) {
    jstring sInput = static_cast<jstring>( oInput );

    const char * $1_pstr = (const char *)jenv->GetStringUTFChars(sInput, 0); 
    if (!$1_pstr) return $null;
    strTemp.assign( $1_pstr );
    jenv->ReleaseStringUTFChars( sInput, $1_pstr);  
  }

  $1 = &strTemp;
}

%typemap(freearg) std::string *INOUT, std::string &INOUT ""

%typemap(argout) std::string *INOUT, std::string &INOUT
{ 
  jstring jStrTemp = jenv->NewStringUTF( strTemp$argnum.c_str() );
  JCALL3(SetObjectArrayElement, jenv, $input, 0, jStrTemp ); 
}

Далее, для каждого шаблона аргумента C ++, подобного этому ...

void foo( std::string & xyzzy );
void bar( std::string & xyzzy );
void baz( ..., std::string & xyzzy, ... );

... вы применяете приведенные выше карты с этой директивой SWIG:

%apply std::string &INOUT { std::string & xyzzy };

Полученные привязки выглядят так:

public void foo( java.lang.String[] xyzzy );
public void bar( java.lang.String[] xyzzy );
public void baz( ..., java.lang.String[] xyzzy, ... );

Каждый из них требует одноэлементного массива String. На входе первый элемент может быть нулевым. Если не ноль, это преобразовано в значение std :: string UTF-8 и передано функции C ++. При выходе значение std :: string, переданное по ссылке, преобразуется обратно из UTF-8 в строку Java.

...