2016-04-11 14 views
0

SWIG 3.0.8'de, C++ - Java haritasındaki std::list için hiçbir uygulama yoktur, yalnızca std::vector. Bu çoğu vaka için çok uygun değil, bu yüzden kendi SWIG tanımımı std::list oluşturmak mümkün olup olmadığını merak ediyordum ve nasıl yaparım?std :: list <std::string> listesi için, UTIG'de C++ 'da Java için <String> Listesinin nasıl bir örnek haritası oluşturursunuz?

+1

Kısa cevap: Muhtemelen 'Listeyi ' ile eşleştirmek istemiyorsunuz, 'AbstractList''i uygulamak çok daha iyi bir fikir. Daha önce benzer konularda birkaç cevap yazdım, bakınız: http://stackoverflow.com/a/12551108/168175 http://stackoverflow.com/a/8190135/168175 – Flexo

+0

(Ayrıca şunu ekleyin: ['AbstractSequentialList' ] (https://docs.oracle.com/javase/7/docs/api/java/util/AbstractSequentialList.html) 'std :: list' için daha iyi bir taban sınıfıdır. Yine de istersen buraya eşdeğer bir cevap yazmaktan mutluluk duyarım. – Flexo

+0

@Flexo Temel C++ nesnesi 'std :: list' kullanır, önceki cevaplarınızın bana nasıl yardımcı olduğu konusunda kafam karışmış mıyım? Eğer yazarsak çok memnun olurum! –

cevap

0

Sadece Java'da std::list'u sarmak için çalışacak bir dizi typemaps yazdım. java.util.AbstractSequentialList'u bir temel sınıf olarak kullanıyorlar, bu yüzden var olan verilerin yalnızca bir kopyası var ve hem Java hem de C++ veri yapısı kadar güzel çalışıyor. Bu cevap, benzer şekilde, an older answer wrapping std::vector'da kullandığım aynı tekniklerin bir iyileştirme ve bağlantı noktasıdır. Şimdi bunu oldukça fazla yeniden ediyorum beri

Öncelikle, autobox.i 'autobox' benim eski cevabın dışında ve bağımsız dosyasına türeşlem çekti:

// 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)) 
Sonra

ben bu kullanılmış benim aşağıdaki std_list.i dosyası:

%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); 
    } 
} 

Bu dosya çoğunlukla sadece ListIterator uygulanması için aşağı kaynar AbstractSequentialList, uygular. Bu biraz acımasız çünkü Java'nın bir yineleyici kavramını uyguladığı yöntem, tamamen farklı olmasa da, C++ soyutlamasına biraz farklıdır. ListIterator ait

Bizim Java uygulaması çoğunlukla opak C++ yineleyici ve aslında gerekli gereksinimlerini karşılamak üzere std::advance, std::distance ve operator++/operator-- kullanan fazladan C++ koduna aramak için bazı tutkal etrafında sarıcı olduğunu. Bir Java programcısının beklediği gibi arayüzü güvenli/sağlam kılmak için gerekli olan çeşitli kontroller yapıştırıcı içinde bulunmaktadır.

yudum arayüzü

liste aşağıdaki ana bölümden oluşmaktadır :: std için: std::list kendisi ilgili bölümlerinin

  1. Beyanı. (Bazıları Java'ya uygulama detayından başka bir şey olarak bir şey ifade etmediğinden özeldir)
  2. Daha sonra SWIG içinde %template'u kullandığımızda, gereken şablon C++ yineleyici kodunu başlatmamıza izin veren bazı ekstra özel kodlar.
  3. daha kolay Java bizim konteyner düşünür ve 'type 'Java olarak ++ yineleyici bir C opak kolu bilen türü' yazmayı yapmak std::list
  4. Bazı yardımcı makroları için içe aktarma/baseclass ayarlama herhangi dahil tutar Gerekirse otomatik kutulama çok yazılır.
  5. biz sarın her std::list<X> için bazı ek Java kodu:

    1. Başka yapıcı başka bir koleksiyondan kopyalama için Java koleksiyonları arayüzü tarafından tavsiye edildiği gibi. (Bu, oldukça verimli bir şekilde yapmak için yarattığımız Java yineleyicisini kullanıyor).
    2. ListIterator değişkeninin tüm gereksinimlerini karşılamak için her şeyi bir arada tutan bir anonim tür döndüren soyut yönteminin bir uygulaması.noblock önişlemci makroları ne şekilde açık olan

    Bu { } içine sarılır, ama bu { } oluşturulur Java takılan almaz.

    Ayrıca bu Java trick to pass data to an anonymous class during construction'u kullandım (ancak bunun yerine the double brace magic kullanmış olabilir). Bunu egzersiz

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

    Ve bazı gerçek Java: yerinde önüne aldığımızda

bir yudum modülü yazma, test.i çalıştırarak bunu doğrulayabilir

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); 
    } 
} 

çalışır Hangi beklendiği gibi:

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 

Hips:

4 
HELLO 
WORLD 
testing 
some more 
A 
B 
C 

Rastgele bir not: hasNext() ve ileri yineleme muhtemelen hasPrevious() ve bu durumda int std::distance aramayı önlemek daha kolaydır çünkü ters yineleme daha hızlıdır.

(Uyarı: ListIterator üye işlevlerinin anlamlarının ne kadar acele olması gerektiğine ilişkin Java belgelerini okudum. Bir veya birkaçını yanlış anlayabildim).

İlgili konular