2011-11-16 15 views
11

Java uygulamamın kullanabilmesi için SWIG kullanarak Java'ya dönüştürdüğüm bazı yerel C++ kodları var. Özellikle std :: vektörünü döndüren bazı fonksiyonlar vardır. İşte benim arabirim dosyasının bir parçacık İşte: SWIG (v1.3.29) oluşturulan C++ Java Vektör sınıfı düzgün davranmıyor

%include "std_vector.i" 
namespace std { 
    %template(Vector) vector<double>; 
    %template(Matrix) vector<vector<double> >; 
} 

%include "std_string.i" 

std_string.i ve std_vector.i

ben kullanıyorum yudum in my yapı alındı. Benim ilk sürprizim, Java çıktısının SWIG'in Vector sınıfının "kendi" versiyonunu içermesiydi ( java.util.Vector'un aksine). Asıl mesele şu ki, bu fonksiyonlardan dönen Vektörler işe yaramaz. Örneğin, içeriğini get() (bazen programı kilitleyerek) veya negatif değerler döndüren size() işlevini kullanarak alamıyorum. Ben Vector s veri içerdiğini biliyorum çünkü ben sadece Vector s (tekrar yerel C++ kodu) ile yineleme ve içeriğini bir virgülle ayrılmış String değeri döndüren aynı işlevlerin 'Dize' sürümlerini kodladım. Bu geçerli bir geçici çözüm olsa da, sonuç olarak Vectors'u almam ve kullanabilmem için düzgün çalışmamı isterim. Herhangi bir yardım/ipucu çok takdir edilecektir.

+0

Bir SWIG kullanıcısı değil, fakat std_vector.i'ye baktığımda (bunun çevrimiçi sürümlerini zaten bulabilirim), 'size()' 'imzasız bir int 'olması gerekiyordu ve SWIG'nin bunu çevirmesi gerekiyordu. Java 'uzun' için. Negatif boyutlar alıyorsanız, saf saçmalık mı, yoksa imzasız olarak imzalıyor gibi mi görünüyorlar? –

cevap

14

Java'da std::vector sarma için uygun taban türü java.util.AbstractList'dur. java.util.Vector'u bir temel olarak kullanmanız garip olurdu çünkü iki depolama alanıyla, bir tane std::vector, biri de java.util.Vector.

you can't have AbstractList<double> in Java, bu (double ilkel türüdür oysa Object den Double devralır) AbstractList<Double> olmak zorunda çünkü yudum olsa sizin için bu yapmaz nedenidir.

Tüm bunları, bir araya getirdiğimi söyledikten sonra, std::vector<double> ve std::vector<std::vector<double> >'u Java'da güzel bir şekilde sarar. Tamamlanmadı, ancak Java'daki yineleme stilini ve öğeler üzerinde set()/get()'u destekler. Başka şeyleri nasıl/ne zaman istediğiniz gibi uygulayacağınızı göstermek için yeterli olmalıdır.

Arabirim dosyasında gittiğimiz bölümlerde konuşacağız, ancak temel olarak hepsi sıralı ve tamamlanmış olacak. Bizim modülü num tanımlayan num.i ile başlayarak

: test etmek için

%module num 

%{ 
#include <vector> 
#include <stdexcept> 

std::vector<double> testVec() { 
    return std::vector<double>(10,1.0); 
} 

std::vector<std::vector<double> > testMat() { 
    return std::vector<std::vector<double> >(10, testVec()); 
} 
%} 

%pragma(java) jniclasscode=%{ 
    static { 
    try { 
     System.loadLibrary("num"); 
    } catch (UnsatisfiedLinkError e) { 
     System.err.println("Native code library failed to load. \n" + e); 
     System.exit(1); 
    } 
    } 
%} 

Biz fonksiyonların oluşturulan num_wrap.cxx ve iki uygulamaları için #include s var (onlar sadece dışarı burada onları koymak ayrı bir dosyada olabilir laziness/kolaylık).

Ayrıca, paylaşılan nesne/DLL'nin arabirimin kullanıcısı için saydam olarak yüklenmesine neden olmak için Java SWIG arabirimlerinde kullanmaktan hoşlandığım %pragma(java) jniclasscode= ile bir numara da var.

Arabirim dosyasında sonraki kısım, std::vector parçalarının sarılmasıdır. SWIG söyler

namespace std { 

    template<class T> class vector { 
     public: 
     typedef size_t size_type; 
     typedef T value_type; 
     typedef const value_type& const_reference; 
     %rename(size_impl) size; 
     vector(); 
     vector(size_type n); 
     size_type size() const; 
     size_type capacity() const; 
     void reserve(size_type n); 
     %rename(isEmpty) empty; 
     bool empty() const; 
     void clear(); 
     void push_back(const value_type& x); 
     %extend { 
      const_reference get_impl(int i) throw (std::out_of_range) { 
       // at will throw if needed, swig will handle 
       return self->at(i); 
      } 
      void set_impl(int i, const value_type& val) throw (std::out_of_range) { 
       // at can throw 
       self->at(i) = val; 
      } 
     } 
    }; 
} 

ana değişim burada %rename(size_impl) size;, bunun yerine size_impl olarak std::vector den size() ortaya çıkarmak için: Biz birkaç değişiklik yapmak gerekir çünkü std_vector.i kullanmıyorum.Java std::vector sürümü daha olası int olmayacak bir size_type döndürür gibi bir int dönmek size beklediğini çünkü bunu yapmak gerekir.

%typemap(javabase) std::vector<double> "java.util.AbstractList<Double>" 
%typemap(javainterface) std::vector<double> "java.util.RandomAccess" 
%typemap(javacode) std::vector<double> %{ 
    public Double get(int idx) { 
    return get_impl(idx); 
    } 
    public int size() { 
    return (int)size_impl(); 
    } 
    public Double set(int idx, Double d) { 
    Double old = get_impl(idx); 
    set_impl(idx, d.doubleValue()); 
    return old; 
    } 

%} 

%typemap(javabase) std::vector<std::vector<double> > "java.util.AbstractList<Vector>" 
%typemap(javainterface) std::vector<std::vector<double> > "java.util.RandomAccess" 
%typemap(javacode) std::vector<std::vector<double> > %{ 
    public Vector get(int idx) { 
    return get_impl(idx); 
    } 
    public int size() { 
    return (int)size_impl(); 
    } 
    public Vector set(int idx, Vector v) { 
    Vector old = get_impl(idx); 
    set_impl(idx, v); 
    return old; 
    } 

%} 

Bu bir üs ayarlar: arayüz dosyasında

Sonraki kadar biz uygulamak istiyoruz yanı sıra uyumsuz türleri ile fonksiyonlar arasındaki şeyleri zorlamak için bazı ekstra Java kod yazarken neyi temel sınıf ve arayüzleri söylemek std::vector<std::vector<double> > için std::vector<double> ve java.util.AbstractList<Vector> için java.util.AbstractList<Double> sınıf (Vector arayüzün Java tarafında std::vector<double> arayacaktır budur).

Ayrıca, Java tarafında, double ile Double dönüşümünü ve geri dönmesini sağlayan get ve set uygulamalarını da sağlıyoruz. arayüzde

Son olarak biz ekleyin:

namespace std { 
    %template(Vector) std::vector<double>; 
    %template(Matrix) std::vector<vector<double> >; 
} 

std::vector<double> testVec(); 
std::vector<std::vector<double> > testMat(); 

Bu Matrix olarak std::vector<vector<double> > için benzer Vector olarak (belirli tip) std::vector<double> bakın ve SWIG söyler. Ayrıca, SWIG'e iki test fonksiyonumuzu göstermesini söyleriz.

import java.util.AbstractList; 

public class test { 
    public static void main(String[] argv) { 
    Vector v = num.testVec(); 
    AbstractList<Double> l = v; 
    for (Double d: l) { 
     System.out.println(d); 
    } 
    Matrix m = num.testMat(); 
    m.get(5).set(5, new Double(5.0)); 
    for (Vector col: m) { 
     for (Double d: col) { 
     System.out.print(d + " "); 
     } 
     System.out.println(); 
    } 
    } 
} 

inşa etmek ve yaptığımız bu çalıştırın: Java

Sonraki kadar, test.java, basit main biraz kodumuzu egzersiz

swig -java -c++ num.i 
g++ -Wall -Wextra num_wrap.cxx -shared -I/usr/lib/jvm/java-6-sun/include -I/usr/lib/jvm/java-6-sun/include/linux/ -o libnum.so 

javac test.java && LD_LIBRARY_PATH=. java test 

Ben sürümü 4.4 g ++ ile bu test ve Linux/x86 üzerinde SWIG 1.3.40.

num.i tam sürümü here bulunabilir, ancak her zaman parçanın her birini tek bir dosyaya yapıştırarak bu yanıttan her zaman yeniden oluşturulabilir. Ben AbstractList den uygulanmadı ettik

şeyler:

  1. add() - push_back() yoluyla uygulanabilir, varsayılan olarak uyumlu bir şeyi uygulamak için çalışır hatta std_vector.i ama Doubledouble vs ile çalışmıyor sorun veya AbstractList belirtilen dönüş türü maç
  2. remove() (modCount artırmayı unutmayın etmeyin) - büyük değil std::vector zamanı karmaşıklığı açısından, ama imkansız değil ya (aynı şekildeile uygulamak)
  3. Başka bir Collection gerektiren bir kurucunun kullanılması önerilir, ancak burada uygulanmamıştır. Aynı yerde set() ve get() uygulanabilir, ancak oluşturulan kurucuyu doğru şekilde adlandırmak için $javaclassname gerekir.
  4. this gibi, size_type ->int dönüşümünün size() numaralı sürümde olduğunu kontrol etmek isteyebilirsiniz.
+0

Bu çarpışma sorununu anlamak için umut olsa da, oldukça güzel ve gerçekten etkileyici. Ben 32-bit mimarileri üzerinde çalışan bir uygulamanın Linux64 sürümünde çökmeler görüyorum ve ben std_vector.i kendisi olası gizlenen hatalar hakkında merak ediyorum. –

+0

@ ErnestFriedman-Hill - SWIG sürümümde std_vector.i dosyasında böyle bir davranışa neden olabilecek bir şey göremiyorum. Benim tahminim, yerel Java türleri ile sarılmış C++ 'nın başka bir yerinde ya da muhtemelen başka yerlerde daha sık görülen bir sorun arasında yanlış bir haritalama olacaktır. Korkarım ki bundan çok daha fazla bilgili bir tahminde bulunamam. Bunu kısa bir süre önce bir Linux/x86_64 makinesinde test edeceğim. Umarım yazdıklarım, SWIG kullanarak Java için C++ kapsayıcılarını sarmalarına bakmak için yararlı olacaktır. – Flexo

+0

@ ErnestFriedman-Hill - Bildirdiğiniz sorunu yeniden oluşturamıyorum - belki de bunun için minimal bir çalışma örneği koyabilir misiniz? Kilitlenme problemini daha açık bir şekilde gösteren küçük bir modül çok yardımcı olacaktır. – Flexo

4

Ben aynı konuda sahip olduğum için bu soruya lütuf teklif eden kişiyim. Sonunda gerçek çözümü bulduğumu bildirmek için biraz utanıyorum - ve bu da SWIG el kitabında! Düzeltme, oluşturulan kodu derlerken g++ için -fno-strict-aliasing bayrağını kullanmaktır - bu kadar basittir. Sonunda bunu bulmak için çok fazla Googling aldığını itiraf etmekten nefret ediyorum.

sorun g++ son sürümlerini kod yudum için tutmayın işaretçi aliasing hakkında varsayımlar std_vector için oluşturduğu yapan bazı agresif optimizasyonlar yapmak olduğunu (ve diğer durumlarda.) g++ 4.1 bu yapmaz, ancak 4.4.5 kesinlikle yapar. Varsayımlar, geçerli ISO standardı tarafından mükemmel şekilde geçerli ve izin verilmiş olsa da, ne kadar iyi olduklarından emin değilim. Temel olarak, farklı türlerdeki iki işaretçinin (birkaç istisna hariç), aynı adrese numaralı adresi hiçbir zaman yollayamaz. SWIG'nin işaretçi-nesne ile jlong arasında dönüştürmek için oluşturduğu kod, bu kuralın temelidir.