[英]Wrapper generator SWIG (C++/Perl): How to access "blessed" objects in a 1d vector<double>in Perl?
我編寫了一個 C++ 庫來從電子設計自動化 (EDA) 工具中提取仿真數據(= 帶有 (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 3
Perl 程序員要求我也向他們提供庫,我決定使用包裝器生成器 SWIG來創建綁定。 我完成了本教程,並且能夠成功設置一個最小的工作示例。
基於示例,我為 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 中的每一行都表示為 hash,但 Hash 中沒有鍵。 然而,當使用Perl 的 Data::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>
)。
您需要為std::vector<std::vector<double>>
編寫 output 類型映射以轉換為 arrays 的正確 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:
};
#endif
VecVec.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);
Output :
$VAR1 = [
[
'1',
'2',
'3'
],
[
'4',
'5',
'6'
]
];
回覆:
我想,SWIG 會為這些對象提供方便的訪問方法。 即,底層 C++ 數據類型只是一個簡單的雙精度一維向量(std::vector)。
它應該。 您確實需要在 SWIG 處理函數之前實例化模板,但您需要展示一個最小的、可重現的示例來確定它為什么不起作用。
我目前不熟悉構建 Perl 擴展,但這里有一個非語言特定的 SWIG.i 文件,它應該適用於 Perl。 我將使用 Python 進行演示:
測試.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 支持具有可比性,this.i 文件應該適合您,而無需定義您自己的 output 類型映射。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.