2016-04-11 7 views
0

は、Javaマップ、唯一std::vectorにC++でstd::listのための実装はありません3.0.8。これはほとんどの場合にはあまり理想的ではないので、SWIGの定義をstd::listにすることが可能かどうか、どうすればいいでしょうか?std :: listのtypemapをどのように作成しますか?SWIGのC++とJavaのリスト<String>への<std::string>は? SWIGで

+1

答え:おそらく 'List 'にマップしたくないのですが、 'AbstractList'を実装する方がはるかに良いアイデアです。私は前に、同様の主題に関するいくつかの答えを書いた:http://stackoverflow.com/a/12551108/168175 http://stackoverflow.com/a/8190135/168175 – Flexo

+0

(['AbstractSequentialList' ](https://docs.oracle.com/javase/7/docs/api/java/util/AbstractSequentialList.html)は、 'std :: list'のより良い基本クラスです)。あなたがしたい場合は、ここで等価な答えを書くことを幸せ。 – Flexo

+0

@Flexo私のベースC++オブジェクトは 'std :: list'を使用しています。私はあなたの以前の答えが私を助けてくれると混乱していますか?もしあなたがそれを書くなら、大いに感謝します! –

答えて

0

私はJavaでうまくstd::listを包むために働く必要があるタイプマップのセットを書きました。それらは基本クラスとしてjava.util.AbstractSequentialListを使用するので、存在するデータのコピーは1つしかなく、JavaとC++の両方のデータ構造としてうまく機能します。この答えは、私がan older answer wrapping std::vectorで使ったのと同じ手法の改良と港です。私は今それを非常に多くを再利用していますので、

は、まず私は、私の古い答えの出てスタンドアロンのファイルにautobox.i「をAutoBoxの」タイプマップを引っ張っ:

// Java typemaps for autoboxing in return types of generics 
%define AUTOBOX(CTYPE, JTYPE) 
%typemap(autobox) CTYPE, const CTYPE&, CTYPE& "JTYPE" 
%enddef 
AUTOBOX(double, Double) 
AUTOBOX(float, Float) 
AUTOBOX(boolean, Boolean) 
AUTOBOX(signed char, Byte) 
AUTOBOX(short, Short) 
AUTOBOX(int, Integer) 
AUTOBOX(long, Long) 
AUTOBOX(SWIGTYPE, $typemap(jstype,$1_basetype)) 

をそれから私は私の中でこれを使用しました以下std_list.iファイル:

%include <autobox.i> 
%include <stdint.i> 

%{ 
#include <list> 
#include <algorithm> 
%} 

namespace std { 
    template <typename T> class list { 
    public: 
    // This typedef is a weird hack to make stuff work 
    typedef std::list<T>::iterator iterator; 
    typedef size_t size_type; 
    typedef T value_type; 
    typedef T& reference; 

    void assign(size_type n, const value_type &val); 

    bool empty() const; 

    list(size_type n, const value_type &value=value_type()); 
    list(const list &o); 
    list(); 
    ~list(); 

    size_type max_size() const; 

    void pop_back(); 
    void pop_front(); 
    void push_back(const value_type &x); 
    void push_front(const value_type &x); 
    void remove(const T &v); 

    // Possible bug: jint != size_type 
    jint size() const; 
    void sort(); 

%javamethodmodifiers "private"; 
    // Only for helping implement listIterator 
    iterator begin(); 
    iterator insert(iterator pos, const value_type &v); 

    %extend { 
     static void set(iterator pos, const value_type& v) { 
     *pos = v; 
     } 

     jint previous_index(const iterator& pos) const { 
     return pos == self->begin() ? -1 : std::distance(self->begin(), static_cast<std::list<T>::const_iterator>(pos)); 
     } 

     jint next_index(const iterator& pos) const { 
     return pos == self->end() ? self->size() : std::distance(self->begin(), static_cast<std::list<T>::const_iterator>(pos)); 
     } 

     static iterator next(iterator pos) { 
     return ++pos; 
     } 

     static iterator previous(iterator pos) { 
     return --pos; 
     } 

     static value_type deref(const iterator& pos) { 
     return *pos; 
     } 

     static void advance(iterator& pos, jint index) { 
     std::advance(pos, index); 
     } 

     bool has_next(const iterator& pos) const { 
     return pos != $self->end(); 
     } 
    } 
%javamethodmodifiers "public"; 
    }; 
} 

%typemap(javaimports) std::list %{ 
    import java.util.AbstractSequentialList; 
    import java.util.ListIterator; 
    import java.util.NoSuchElementException; 
    import java.util.Collection; 
%} 

%typemap(javabase) std::list "AbstractSequentialList<$typemap(autobox,$1_basetype::value_type)>" 

#define JAVA_VALUE_TYPE $typemap(autobox,$1_basetype::value_type) 
#define JAVA_ITERATOR_TYPE $typemap(jstype, $1_basetype::iterator) 

%typemap(javacode,noblock=1) std::list { 
    public $javaclassname(Collection c) { 
    this(); 
    ListIterator<JAVA_VALUE_TYPE> it = listIterator(0); 
    for (Object o: c) { 
     it.add((JAVA_VALUE_TYPE)o); 
    } 
    } 

    public ListIterator<JAVA_VALUE_TYPE> listIterator(int index) { 
    return new ListIterator<JAVA_VALUE_TYPE>() { 
     private JAVA_ITERATOR_TYPE pos; 
     private JAVA_ITERATOR_TYPE last; 

     private ListIterator<JAVA_VALUE_TYPE> init(int index) { 
     pos = $javaclassname.this.begin(); 
     $javaclassname.advance(pos, index); 
     return this; 
     } 

     public void add(JAVA_VALUE_TYPE v) { 
     // Technically we can invalidate last here, but this makes more sense 
     last=$javaclassname.this.insert(pos, v); 
     } 

     public void set(JAVA_VALUE_TYPE v) { 
     if (null==last) { 
      throw new IllegalStateException(); 
     } 
     $javaclassname.set(last, v); 
     } 

     public void remove() { 
     if (null==last) { 
      throw new IllegalStateException(); 
     } 
     $javaclassname.this.remove(last); 
     last=null; 
     } 

     public int previousIndex() { 
     return $javaclassname.this.previous_index(pos); 
     } 

     public int nextIndex() { 
     return $javaclassname.this.next_index(pos); 
     } 

     public JAVA_VALUE_TYPE previous() { 
     if (previousIndex() < 0) { 
      throw new NoSuchElementException(); 
     } 
     last = pos; 
     pos = $javaclassname.previous(pos); 
     return $javaclassname.deref(last); 
     } 

     public JAVA_VALUE_TYPE next() { 
     if (!hasNext()) { 
      throw new NoSuchElementException(); 
     } 
     last = pos; 
     pos = $javaclassname.next(pos); 
     return $javaclassname.deref(last); 
     } 

     public boolean hasPrevious() { 
     return previousIndex() != -1; 
     } 

     public boolean hasNext() { 
     return $javaclassname.this.has_next(pos); 
     } 
    }.init(index); 
    } 
} 

このファイルには、ほとんどがちょうどListIteratorを実装するまで沸騰する、AbstractSequentialListを実装しています。 Javaがイテレータのコンセプトを実装する方法は、C++の抽象化とは少し異なりますが、完全に異なるわけではありません。 ListIterator

当社のJava実装では、ほとんどが不透明なC++イテレータと、実際に必要な要件を満たすためにstd::advancestd::distanceoperator++/operator--を使用して少し余分なC++コードに呼び出すためにいくつかの接着剤の周りだけのラッパーです。接着剤の中には、Javaプログラマが期待しているように、インターフェースを安全/頑強にするために必要なさまざまなチェックがあります。 ::リストをはstdする

SWIGインタフェースは、次の主要部分で構成されていますstd::list自体の関連部分の

  1. 宣言。
  2. 私たちは、後にSWIG内%templateを使用するときに我々が必要とするテンプレートC++のイテレータのコードの一部をインスタンス化させるためにいくつかの余分なプライベートコード(それは実装の詳細以外としてのJavaにも意味がありませんので、一部はプライベートです)。
  3. それが簡単にJavaがいずれかを含め、当社のコンテナが保持していると考えていることと「タイプ「JavaはC++のようにイテレータへの不透明なハンドルを知っているタイプ」を書くために作るためにstd::list
  4. いくつかのヘルパーマクロの輸入/基底クラスを設定します彼らがたくさん書かれているので、必要に応じてオートボクシング。
  5. 我々はラップごとstd::list<X>のためのいくつかの追加のJavaコード:

    1. 別のコンストラクタ別のコレクションからコピーするためのJavaコレクションインタフェースによって推奨されているように。 (これは私たちが作成したJavaイテレータを使用して、効率的に処理します)。
    2. 可変ListIteratorための要件のすべてを満たすために、一緒にすべてを接着する匿名型を返すlistIterator抽象メソッドの実装。NOBLOCKは、プリプロセッサマクロが起こるように、オンと

    これは{ }内にラップされていますが、その{ }が生成されたJavaに挿入されません。

    このJava trick to pass data to an anonymous class during constructionも使用しましたが(代わりにthe double brace magicを使用している可能性があります)。

    %module test 
    
    %include "std_list.i" 
    %include <std_string.i> 
    
    %template(DoubleList) std::list<double>; 
    %template(StringList) std::list<std::string>; 
    

    そして、それを行使するためにいくつかの実際のJava:我々はSWIGモジュール、test.iを書い実行することによって、それを検証することができる場所で

    ことで

import java.util.ArrayList; 

public class run { 
    public static void dump(java.util.AbstractCollection c) { 
    for (Object o: c) { 
     System.out.println(o); 
    } 
    } 

    public static void main(String[] argv) { 
    System.loadLibrary("test"); 
    for (int i = 0; i < 1; ++i) { 
     go(); 
//  System.gc(); 
    } 
    } 

    public static void go() { 
    StringList sl = new StringList(); 
    dump(sl); 
    sl.add(0,"HELLO"); // 1 arg form also worked 
    sl.add(1,"WORLD"); 
    sl.add(2,"testing"); 
    sl.add(3,"some more"); 
    System.out.println(sl.size()); 
    dump(sl); 

    sl = new StringList(new ArrayList<String>() {{ 
     add("A"); 
     add("B"); 
     add("C"); 
    }}); 
    dump(sl); 
    } 
} 

作品期待どおり:

swig3.0 -java -c++ -Wall test.i 
javac *.java 
g++ -Wall -Wextra -shared -o libtest.so test_wrap.cxx -I/usr/lib/jvm/default-java/include/ -I/usr/lib/jvm/default-java/include/linux -fPIC -D_GLIBCXX_DEBUG 
LD_LIBRARY_PATH=. java run 

ギブス:

4 
HELLO 
WORLD 
testing 
some more 
A 
B 
C 

ランダムノート:hasNext()と前方反復は、おそらくhasPrevious()、それはそのような場合、INT std::distance呼び出しを避けるために簡単だという理由だけで逆反復よりも高速です。

(注意:ListIteratorメンバ関数のセマンティクスが急いでいるはずのJavaドキュメントを読んでいますが、そのうちの1つ以上が間違っている可能性があります)。

関連する問題