我编写了一个C++库来从电子设计自动化工具中提取模拟数据(=带有(x,y)或(x,y,z)组件的简单向量)。更具体的说,这些数据代表了不同时间点的电信号。
C++库提供了几种方法。两个重要的问题是:
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++中使用该库可以很好地工作,并产生预期的结果,例如:
getSignalNames():
Signal1
Signal2
getSignals():
1 1 1 2
2 1 2 3Perl程序员要求我也向他们提供库,我决定使用包装生成器大口创建绑定。我通过本教程工作,并成功地建立了一个最小的工作示例。
基于这个示例,我为C++库编写了一个完整的SWIG接口文件。包装器的生成和构建过程运行顺利,我也可以使用getSignalNames(),没有任何问题:
// 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()的返回值时遇到了麻烦。
// 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时,我可以看到每一行的正确数据类型:
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接口文件中定义如下:
...
%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>)。
发布于 2021-12-10 11:34:38
您需要为std::vector<std::vector<double>>编写一个输出类型图,以便将其转换为适当的Perl数组数组。下面是一个示例:
VecVec.i
%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
#ifndef VEVEC_H_
#define VECVEC_H_
#include <vector>
class VecVec
{
public:
VecVec() {}
~VecVec() {}
std::vector<std::vector<double>> getSignals();
private:
};
#endifVecVec.cpp
#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;
}然后用以下方法编译:
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对模块进行测试。
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);输出
$VAR1 = [
[
'1',
'2',
'3'
],
[
'4',
'5',
'6'
]
];发布于 2021-12-10 23:59:35
回复:
我想,SWIG会为这样的对象提供方便的访问方法。也就是说,底层的C++数据类型仅仅是一个简单的双倍的一维向量(std:: vector )。
应该是这样的。在SWIG处理函数之前,您确实需要实例化这些模板,但是您需要展示一个最小的、可重复的示例,以确定为什么它不能工作。
我目前还不熟悉构建Perl扩展名,但是这里有一个非语言专用的SWIG .i文件,应该适用于Perl。我将用Python演示:
test.i
%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扩展名。
演示:
>>> import test
>>> test.getSignalNames()
('abc', '123')
>>> test.getSignals()
((1.1, 2.2), (3.3, 4.4))如果SWIG的Perl支持是可比的,那么这个.i文件应该适用于您,而无需定义您自己的输出类型映射。
https://stackoverflow.com/questions/70302112
复制相似问题