首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >包装生成器SWIG (C++/ Perl ):如何在一维vector<double>in Perl中访问“祝福”对象?

包装生成器SWIG (C++/ Perl ):如何在一维vector<double>in Perl中访问“祝福”对象?
EN

Stack Overflow用户
提问于 2021-12-10 09:11:53
回答 2查看 85关注 0票数 1

我编写了一个C++库来从电子设计自动化工具中提取模拟数据(=带有(x,y)或(x,y,z)组件的简单向量)。更具体的说,这些数据代表了不同时间点的电信号。

C++库提供了几种方法。两个重要的问题是:

代码语言:javascript
复制
std::vector<std::string> getSignalNames() // Returns all signal names in the file
std::vector<std::vector<double>> getSignals() // Returns the actual data as M x N matrix (with M rows and N columns)

在C++中使用该库可以很好地工作,并产生预期的结果,例如:

代码语言:javascript
复制
getSignalNames():
  Signal1
  Signal2
getSignals():
  1 1 1 2
  2 1 2 3

Perl程序员要求我也向他们提供库,我决定使用包装生成器大口创建绑定。我通过本教程工作,并成功地建立了一个最小的工作示例。

基于这个示例,我为C++库编写了一个完整的SWIG接口文件。包装器的生成和构建过程运行顺利,我也可以使用getSignalNames(),没有任何问题:

代码语言:javascript
复制
// Perl snippet to read out signal names
my $parserPointer = new waveformparser::ScopeParser("input.file");
$signalNames = $parserPointer->getSignalNames();

foreach my $signalName ( @$signalNames ) {
    print "$signalName\n";
}
// Output:
Signal1
Signal2

但是,我在使用getSignals()的返回值时遇到了麻烦。

代码语言:javascript
复制
// Perl snippet to read out the actual signal data
my $parserPointer = new waveformparser::ScopeParser("input.file");
$signalData = $parserPointer->getSignals();

foreach my $rowAsHashRef ( @$signalData ) {
    print "reftype: " . reftype($rowAsHashRef) . "\n";
    print "keys: " . keys(%$rowAsHashRef) . "\n"
}
// Output:
reftype: HASH
keys: 0
reftype: HASH
keys: 0

正如您所看到的,在Perl中,每行都表示为散列,但是哈希中没有键。然而,在使用Perl的数据::Dumper时,我可以看到每一行的正确数据类型:

代码语言:javascript
复制
my $parserPointer = new waveformparser::ScopeParser("input.file");
$signalData = $parserPointer->getSignals();
print Dumper $signalData;
// Output:
$VAR1 = [
          bless( {}, 'waveformparser::vector_1d_double' ),
          bless( {}, 'waveformparser::vector_1d_double' )
];

也就是说,根据数据转储程序,每一行由几个列(即'waveformparser::vector_1d_double')组成,这些列在SWIG接口文件中定义如下:

代码语言:javascript
复制
...
%include "std_vector.i"
%template(vector_1d_double) std::vector<double>;
%template(vector_2d_double) std::vector<std::vector<double>>;
...

我现在的问题是:如何在Perl中访问这个“受祝福”(包装)的vector_1d_double 对象的元素?

我想,SWIG会为这样的对象提供方便的访问方法。也就是说,底层的C++数据类型只是一个简单的一维双重向量(std::vector<double>)。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2021-12-10 11:34:38

您需要为std::vector<std::vector<double>>编写一个输出类型图,以便将其转换为适当的Perl数组数组。下面是一个示例:

VecVec.i

代码语言:javascript
复制
%module VecVec
%typemap(out) std::vector<std::vector<double>> {
    AV *array = (AV *) newAV();
    auto vec_ptr = &$1;
    std::vector<std::vector<double>>& vec = *vec_ptr;
    for (const auto &item : vec) {
        AV *subarray = (AV *) newAV();
        for (const auto &subitem : item) {
            av_push(subarray, newSVnv((NV) subitem));
        }
        av_push(array, (SV*) newRV_noinc((SV*)subarray));
    }
    $result = newRV_noinc((SV*) array);
    sv_2mortal($result);
    argvi++;
}
%{
    #include "VecVec.h"

%}
%include "VecVec.h"

VecVec.h

代码语言:javascript
复制
#ifndef VEVEC_H_
#define VECVEC_H_
#include <vector>

class VecVec
{
public:
    VecVec() {}
    ~VecVec() {}
    std::vector<std::vector<double>> getSignals();
private:
};
#endif

VecVec.cpp

代码语言:javascript
复制
#include <string>
#include <vector>
#include <iostream>
#include "VecVec.h"

std::vector<std::vector<double>> VecVec::getSignals()
{
    std::vector<std::vector<double>> vec {
        {1, 2, 3},
        {4, 5, 6}
    };
    return vec;
}

然后用以下方法编译:

代码语言:javascript
复制
perl_include_dir=$(perl -MConfig -e'print $Config{archlib}')"/CORE"
swig -perl5 -c++ -I/usr/include VecVec.i
g++ -fPIC -c VecVec.cpp
g++ -I${perl_include_dir} -c -fPIC -g -o VecVec_wrap.o VecVec_wrap.cxx
g++ -shared -L. VecVec.o VecVec_wrap.o -o VecVec.so

并使用test.pl对模块进行测试。

代码语言:javascript
复制
use strict;
use warnings;
use Data::Dumper qw(Dumper);
use lib '.';
use VecVec;

my $p = VecVec::VecVec->new();
my $sig = $p->getSignals();
print Dumper($sig);

输出

代码语言:javascript
复制
$VAR1 = [
          [
            '1',
            '2',
            '3'
          ],
          [
            '4',
            '5',
            '6'
          ]
        ];
票数 2
EN

Stack Overflow用户

发布于 2021-12-10 23:59:35

回复:

我想,SWIG会为这样的对象提供方便的访问方法。也就是说,底层的C++数据类型仅仅是一个简单的双倍的一维向量(std:: vector )。

应该是这样的。在SWIG处理函数之前,您确实需要实例化这些模板,但是您需要展示一个最小的、可重复的示例,以确定为什么它不能工作。

我目前还不熟悉构建Perl扩展名,但是这里有一个非语言专用的SWIG .i文件,应该适用于Perl。我将用Python演示:

test.i

代码语言:javascript
复制
%module test

// Define templates before SWIG processes the code.
%include "std_vector.i"
%include "std_string.i"
%template(vector_string) std::vector<std::string>;
%template(vector_1d_double) std::vector<double>;
%template(vector_2d_double) std::vector<std::vector<double>>;

%inline %{
#include <vector>
#include <string>

std::vector<std::string> getSignalNames() {
    return {"abc","123"};
}

std::vector<std::vector<double>> getSignals() {
    return {{1.1,2.2},{3.3,4.4}};
}
%}

上面的所有内容都包含在一个独立的文件中。我使用swig -c++ -python test.i并将生成的test_wrap.cxx文件编译为Python扩展名。

演示:

代码语言:javascript
复制
>>> import test
>>> test.getSignalNames()
('abc', '123')
>>> test.getSignals()
((1.1, 2.2), (3.3, 4.4))

如果SWIG的Perl支持是可比的,那么这个.i文件应该适用于您,而无需定义您自己的输出类型映射。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/70302112

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档