簡體   English   中英

包裝器生成器 SWIG (C++/Perl):如何訪問一維向量中的“祝福”對象<double>在 Perl 中?</double>

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM