Perl   发布时间:2022-04-07  发布网站:大佬教程  code.js-code.com
大佬教程收集整理的这篇文章主要介绍了STL映射在Perl中使用SWIG大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。
这是我的 question on SWIG mailing list的副本。

我试图使用stl容器在我的SWIG绑定。一切正常工作除了stl地图处理在Perl。在C方面,我有

std::map<std::string,std::string> Trymap(const std::map<std::string,std::string> &map) {
  std::map<std::string,std::string> modified(map);
  modified["7"] = "!";
  return modified;
}

SWIG配置看起来像这样

%module stl

%include "std_String.i"

%include "std_map.i"
%template(StringStringMap) std::map<std::string,std::string>;

%{
  #include "stl.h"
%}

%include "stl.h"

在我的Python脚本中,我可以这样调用Trymap

print Dict(stl.Trymap({'a': '4'}))

并获得美丽的输出

{'a': '4','7': '!'}

但是在Perl我调用

print Dumper stl::Trymap({'a' => '4'});

并得到一个错误

TypeError in method 'Trymap',argument 1 of type 'std::map< std::string,std::string > const &' at perl.pl line 7.

我可以做一些事情

@H_815_4@my $map = stl::Trymap(stl::stringStringMap->new()); print $map->get('7');

并获得’!’,但这不是一个选项,因为有很多遗留代码使用“Trymap”,期望正常的Perl哈希作为其输出。

我相信有一种方法工作,这是因为SWIG解决这个特别的问题很好地在Python和甚至在Perl如果我使用stl向量和字符串,但不是地图。

有什么办法来处理stl地图与Perl在SWIG?我使用最新的SWIG 2.0.7

@R_489_9531@E也许有一些问题perl5 / std_map.i。它太短=)

$ wc -l perl5/std_map.i python/std_map.i 
   74 perl5/std_map.i
  305 python/std_map.i

解决方法

我把你的C函数放入头文件作为内联函数进行测试。

然后,我能够构建一个SWIG界面,做你正在寻找的。它有两个关键部分。首先,我写了一个typemap,它将允许std :: map或perl哈希作为输入到期望std :: map的C函数。在后者的情况下,它从perl哈希构建临时映射以用作参数。 (这是方便,但可能较慢)。 typemap通过检查实际传入的内容来选择正确的行为。

解决方案的第二部分是将一些C map的成员函数映射到perl用于在哈希上重载操作的特殊函数。大多数这些是简单地用%rename实现,其中C函数和perl函数是兼容的,但是FIRSTKEY和NEXTKEY不很好地映射到C的迭代器,因此这些是使用%extend和(内部)另一个std :: map实现的存储我们包装的地图的迭代状态。

这里没有实现用于返回映射的特殊类型映射,然而通过现在实现的特殊操作存在额外的行为。

SWIG界面如下所示:

%module stl

%include <std_String.i>
%include <exception.i>

%rename(FETCH) std::map<std::string,std::string>::get;
%rename(STORE) std::map<std::string,std::string>::set;
%rename(EXISTS) std::map<std::string,std::string>::has_key;
%rename(Delete) std::map<std::string,std::string>::del;
%rename(SCALAR) std::map<std::string,std::string>::size;
%rename(CLEAR) std::map<std::string,std::string>::clear;

%{
#include <map>
#include <String>
// For iteration support,will leak if iteration stops before the end ever.
static std::map<void*,std::map<std::string,std::string>::const_iterator> iterstate;

const char *current(std::map<std::string,std::string>& map) {
  std::map<void*,std::string>::const_iterator>::iterator it = iterstate.find(&map);
  if (it != iterstate.end() && map.end() == it->second) {
    // clean up entry in the global map
    iterstate.erase(it);
    it = iterstate.end();
  }
  if (it == iterstate.end())
    return NULL;
  else
    return it->second->first.c_str();
}
%}

%extend std::map<std::string,std::string> {
  std::map<std::string,std::string> *TIEHASH() {
    return $self;
  }
  const char *FIRSTKEY() {
    iterstate[$self] = $self->begin();
    return current(*$self);
  }
  const char *NEXTKEY(const std::string&) {
    ++iterstate[$self];
    return current(*$self);
  }
}

%include <std_map.i>

%typemap(in,noblock=1) const std::map<std::string,std::string>& (void *argp=0,int res=0,$1_ltype tempmap=0) {
  res = SWIG_ConvertPtr($input,&argp,$descriptor,%convertptr_flags);
  if (!SWIG_IsOK(res)) {
    if (SvROK($input) && SvTYPE(SvRV($input)) == SVt_PVHV) {
      fprintf(stderr,"Convert HV to map\n");
      tempmap = new $1_basetype;
      HV *hv = (HV*)SvRV($input);
      HE *hentry;
      hv_iterinit(hv);
      while ((hentry = hv_iternext(hv))) {
        std::string *val=0;
        // TODO: handle errors here
        SWIG_AsPtr_std_String SWIG_PERL_Call_ARGS_2(HeVAL(hentry),&val);
        fprintf(stderr,"%s => %s\n",HeKEY(hentry),val->c_str());
        (*tempmap)[HeKEY(hentry)] = *val;
        delete val;
      }
      argp = tempmap;
    }
    else {
      %argument_fail(res,"$type",$symname,$argnum); 
    }
  }
  if (!argp) { %argument_nullref("$type",$argnum); }
  $1 = %reinterpret_cast(argp,$ltypE);
}

%typemap(freearg,std::string>& {
  delete tempmap$argnum;
}

%template(StringStringMap) std::map<std::string,std::string>;

%{
#include "stl.h"
%}

%include "stl.h"

然后我调整你的样本perl测试:

use Data::Dumper;
use stl;

my $v = stl::Trymap(stl::stringStringMap->new());
$v->{'a'} = '1';
print Dumper $v;
print Dumper stl::Trymap({'a' => '4'});
print Dumper stl::Trymap($v);


foreach my $key (keys %{$v}) {
  print "$key => $v->{$key}\n";
}

print $v->{'7'}."\n";

我能够成功运行:

Got map: 0x22bfb80
$VAR1 = bless( {
                 '7' => '!','a' => '1'
               },'stl::stringStringMap' );
Convert HV to map
a => 4
Got map: 0x22af710
In C++ map: a => 4
$VAR1 = bless( {
                 '7' => '!','a' => '4'
               },'stl::stringStringMap' );
Got map: 0x22bfb20
In C++ map: 7 => !
In C++ map: a => 1
$VAR1 = bless( {
                 '7' => '!','stl::stringStringMap' );
7 => !
a => 1
!

您还可以将此对象绑定到散列,例如:

use stl;

my $v = stl::Trymap(stl::stringStringMap->new());
print "$v\n";

tie %foo,"stl::stringStringMap",$v;

print $foo{'a'}."\n";
print tied(%foo)."\n";

理论上,你可以编写一个输出类型来在每次函数调用返回时自动设置这个关系,但是到目前为止,我还没有成功编写一个适用于绑定和SWIG运行时类型系统的类型。

应该注意,这不是生产就绪代码。有一个线程安全问题的内部地图和一些错误处理丢失,我知道。我还没有完全测试所有的哈希操作工作从perl一边超出你上面看到的。通过与swig_map_common宏交互,使它更通用也是很好的。最后,我不是一个perl guru的任何方式,我没有使用C API,所以在这方面的一些谨慎是顺序。

大佬总结

以上是大佬教程为你收集整理的STL映射在Perl中使用SWIG全部内容,希望文章能够帮你解决STL映射在Perl中使用SWIG所遇到的程序开发问题。

如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。