如何将多维映射从 C++ 转换为 Perl 中的散列

How to convert multidimensional map from c++ into hash in perl

我是 swig 的新手,我正在尝试将 C++ 映射转换为 Perl 中的散列。

有一个使用 c++ 的 Perl 扩展需要 return 多维数组或映射到 Perl。 我在 swig 接口文件中使用了模板,但结果为空。

swig 接口文件:

%include "exception.i"
%exception {

    try {
        $action
        } catch (const std::exception &e) {

        SWIG_exception_fail(SWIG_RuntimeError, e.what());
        }
    }

%module new_tr
%{
/* Put headers and other declarations here */
#include "new_tr.h"
%}
%include <std_map.i>

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

%include "new_tr.h"

cpp 文件

     std::map<int,  std::map<std::string,std::string>> Memberfunction::m;
    std::map<int,  std::map<std::string,std::string>> Memberfunction::getResult()
    {
        return m;
    }

perl 文件

use strict;
use new_tr;
use Data::Dumper;

my $new=new new_tr::some();
print Dumper($new->getResult());

当前输出:

$VAR1 = bless( {}, 'new_tr::StringStringMap' );

预期输出:(多维哈希)

$VAR1 = bless( 0 =>    { 
                                'Brown' => 'Manager', 
                                'Smith' => 'Salesman', 
                                'Albert' => 'Salesman',  
                            },  
            1 =>  { 
                                'Penfold' => 'Designer', 
                                'Evans' => 'Tea-person', 
                                'Jurgens' => 'Manager',  
                            }, 'new_tr::StringStringMap' );

这是一个示例,说明如何将 %typemap 用于嵌套的 std::map

new_tr.i:

%module new_tr
%typemap(out) std::map<int, std::map<std::string,std::string>> {
    HV *hash = (HV *) newHV();
    for (auto const& item : ) {
        HV *subhash;
        char *keysv;
        auto map = item.second;
        subhash = (HV *) newHV();
        for (auto const &item2 : map) {
            SV *sv;
            auto key2 = item2.first.c_str();
            auto value = item2.second.c_str();
            sv = newSVpvn( value, strlen(value) );
            hv_store (subhash, key2, strlen(key2), sv, 0);
        }
        auto key = std::to_string(item.first).c_str();
        hv_store (hash, key, strlen(key), (SV*) newRV_noinc((SV*)subhash), 0);
    }  
    $result = newRV_noinc((SV*) hash);
    sv_2mortal($result);
    argvi++;
} 
%{
#include "new_tr.h"
%}
%include "new_tr.h"

new_tr.h:

#include <map>
#include <string>
using ssmap = std::map<int,  std::map<std::string,std::string>>;
ssmap getResult();

new_tr.cxx:

#include "new_tr.h"

ssmap getResult()
{
    ssmap map = {
        {1, {{"Brown","Manager"}, {"Smith", "Salesman"}, {"Albert", "Salesman"}}},
        {2, {{"Penfold", "Designer"}, {"Evans", "Tea-person"}, {"Jurgens", "Manager"}}}
    };

    return map;
}

然后编译模块:

perl_include_dir=$(perl -MConfig -e'print $Config{archlib}')"/CORE"
swig -perl5 -c++ -I/usr/include new_tr.i 
g++ -fPIC -c new_tr.cxx
g++ -I${perl_include_dir} -c -fPIC -g -o new_tr_wrap.o new_tr_wrap.cxx
g++ -shared -L. new_tr.o new_tr_wrap.o -o new_tr.so

并使用 test.pl:

进行测试
use strict;
use warnings;
use Data::Dumper;
use lib '.';
use new_tr;

my $map = new_tr::getResult();
print Dumper( $map );

输出:

$VAR1 = {
          '1' => {
                   'Albert' => 'Salesman',
                   'Smith' => 'Salesman',
                   'Brown' => 'Manager'
                 },
          '2' => {
                   'Penfold' => 'Designer',
                   'Jurgens' => 'Manager',
                   'Evans' => 'Tea-person'
                 }
        };