From 7c4109c7018dedb5e165b66de36f0dd137322b13 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Mon, 28 Nov 2016 21:32:00 +0100 Subject: [PATCH 1/4] Add helper macro to avoid duplication in Java vector typemaps No real changes yet, just use a C#-like macro in Java std::vector<> typemaps too to avoid having to repeat almost exactly the same class declaration for the general case and for the bool specialization. --- Lib/java/std_vector.i | 49 +++++++++++-------------------------------- 1 file changed, 12 insertions(+), 37 deletions(-) diff --git a/Lib/java/std_vector.i b/Lib/java/std_vector.i index 971b426a1..eea87885d 100644 --- a/Lib/java/std_vector.i +++ b/Lib/java/std_vector.i @@ -9,13 +9,11 @@ #include %} -namespace std { - - template class vector { - public: +%define SWIG_STD_VECTOR_MINIMUM_INTERNAL(CTYPE, CREF_TYPE) + public: typedef size_t size_type; - typedef T value_type; - typedef const value_type& const_reference; + typedef CTYPE value_type; + typedef CREF_TYPE const_reference; vector(); vector(size_type n); size_type size() const; @@ -27,7 +25,7 @@ namespace std { %rename(add) push_back; void push_back(const value_type& x); %extend { - const_reference get(int i) throw (std::out_of_range) { + CREF_TYPE get(int i) throw (std::out_of_range) { int size = int(self->size()); if (i>=0 && i class vector { + SWIG_STD_VECTOR_MINIMUM_INTERNAL(T, const T&) }; // bool specialization template<> class vector { - public: - typedef size_t size_type; - typedef bool value_type; - typedef bool const_reference; - 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(); - %rename(add) push_back; - void push_back(const value_type& x); - %extend { - bool get(int i) throw (std::out_of_range) { - int size = int(self->size()); - if (i>=0 && isize()); - if (i>=0 && i Date: Mon, 28 Nov 2016 22:38:38 +0100 Subject: [PATCH 2/4] Make std::vector<> wrappers conform to List interface in Java Derive the class wrapping std::vector<> in Java from java.util.AbstractList<>. This makes it possible to use it with various algorithms working with Java collections and, maybe even more importantly, makes it possible to iterate over the wrapped vectors using for-each loops. This commit is based on the original patch by Volker Diels-Grabsch from https://sourceforge.net/p/swig/patches/278/ --- CHANGES.current | 4 + .../test-suite/java/li_std_vector_runme.java | 14 ++- Lib/java/java.swg | 17 ++++ Lib/java/std_vector.i | 98 +++++++++++++++++-- 4 files changed, 126 insertions(+), 7 deletions(-) diff --git a/CHANGES.current b/CHANGES.current index 14f6fb4cb..c68167775 100644 --- a/CHANGES.current +++ b/CHANGES.current @@ -5,6 +5,10 @@ See the RELEASENOTES file for a summary of changes in each release. Version 3.0.11 (in progress) ============================ +2016-11-28: Volker Diels-Grabsch, vadz + [Java] Implement java.util.List<> for std::vector. This notably allows to + iterate over wrapped vectors in a natural way. + 2016-11-28: wsfulton Fix %rename override of wildcard %rename for templates. For example: diff --git a/Examples/test-suite/java/li_std_vector_runme.java b/Examples/test-suite/java/li_std_vector_runme.java index b422655a4..3238f9dd8 100644 --- a/Examples/test-suite/java/li_std_vector_runme.java +++ b/Examples/test-suite/java/li_std_vector_runme.java @@ -19,6 +19,9 @@ public class li_std_vector_runme { v1.add(123); if (v1.get(0) != 123) throw new RuntimeException("v1 test failed"); + for (int n : v1) { + if (n != 123) throw new RuntimeException("v1 loop test failed"); + } StructVector v4 = li_std_vector.vecstruct(new StructVector()); StructPtrVector v5 = li_std_vector.vecstructptr(new StructPtrVector()); @@ -28,9 +31,18 @@ public class li_std_vector_runme { v5.add(new Struct(34)); v6.add(new Struct(56)); - Struct s = null; if (v4.get(0).getNum() != 12) throw new RuntimeException("v4 test failed"); if (v5.get(0).getNum() != 34) throw new RuntimeException("v5 test failed"); if (v6.get(0).getNum() != 56) throw new RuntimeException("v6 test failed"); + + for (Struct s : v4) { + if (s.getNum() != 12) throw new RuntimeException("v4 loop test failed"); + } + for (Struct s : v5) { + if (s.getNum() != 34) throw new RuntimeException("v5 loop test failed"); + } + for (Struct s : v6) { + if (s.getNum() != 56) throw new RuntimeException("v6 loop test failed"); + } } } diff --git a/Lib/java/java.swg b/Lib/java/java.swg index f1227d0ad..225de5935 100644 --- a/Lib/java/java.swg +++ b/Lib/java/java.swg @@ -103,9 +103,25 @@ SWIGINTERN const char * SWIG_UnpackData(const char *c, void *ptr, size_t sz) { %typemap(jstype) double, const double & "double" %typemap(jstype) void "void" +%typemap(jboxtype) bool "Boolean" +%typemap(jboxtype) char "Character" +%typemap(jboxtype) signed char "Byte" +%typemap(jboxtype) unsigned char "Short" +%typemap(jboxtype) short "Short" +%typemap(jboxtype) unsigned short "Integer" +%typemap(jboxtype) int "Integer" +%typemap(jboxtype) unsigned int "Long" +%typemap(jboxtype) long "Integer" +%typemap(jboxtype) unsigned long "Long" +%typemap(jboxtype) long long "Long" +%typemap(jboxtype) unsigned long long "java.math.BigInteger" +%typemap(jboxtype) float "Float" +%typemap(jboxtype) double "Double" + %typemap(jni) char *, char *&, char[ANY], char[] "jstring" %typemap(jtype) char *, char *&, char[ANY], char[] "String" %typemap(jstype) char *, char *&, char[ANY], char[] "String" +%typemap(jboxtype) char *, char *&, char[ANY], char[] "String" /* JNI types */ %typemap(jni) jboolean "jboolean" @@ -172,6 +188,7 @@ SWIGINTERN const char * SWIG_UnpackData(const char *c, void *ptr, size_t sz) { %typemap(jni) SWIGTYPE "jlong" %typemap(jtype) SWIGTYPE "long" %typemap(jstype) SWIGTYPE "$&javaclassname" +%typemap(jboxtype) SWIGTYPE "$typemap(jstype, $1_type)" %typemap(jni) SWIGTYPE [] "jlong" %typemap(jtype) SWIGTYPE [] "long" diff --git a/Lib/java/std_vector.i b/Lib/java/std_vector.i index eea87885d..6c745aa23 100644 --- a/Lib/java/std_vector.i +++ b/Lib/java/std_vector.i @@ -10,38 +10,124 @@ %} %define SWIG_STD_VECTOR_MINIMUM_INTERNAL(CTYPE, CREF_TYPE) +%typemap(javabase) std::vector "java.util.AbstractList<$typemap(jboxtype, CTYPE)>" +%typemap(javainterfaces) std::vector "java.util.RandomAccess" +%typemap(javacode) std::vector %{ + public $javaclassname($typemap(jstype, CTYPE)[] initialElements) { + this(); + for ($typemap(jstype, CTYPE) element : initialElements) { + add(element); + } + } + + public $javaclassname(Iterable<$typemap(jboxtype, CTYPE)> initialElements) { + this(); + for ($typemap(jstype, CTYPE) element : initialElements) { + add(element); + } + } + + public $typemap(jboxtype, CTYPE) get(int index) { + return doGet(index); + } + + public $typemap(jboxtype, CTYPE) set(int index, $typemap(jboxtype, CTYPE) e) { + return doSet(index, e); + } + + public boolean add($typemap(jboxtype, CTYPE) e) { + modCount++; + doAdd(e); + return true; + } + + public void add(int index, $typemap(jboxtype, CTYPE) e) { + modCount++; + doAdd(index, e); + } + + public $typemap(jboxtype, CTYPE) remove(int index) { + modCount++; + return doRemove(index); + } + + protected void removeRange(int fromIndex, int toIndex) { + modCount++; + doRemoveRange(fromIndex, toIndex); + } +%} + public: typedef size_t size_type; typedef CTYPE value_type; typedef CREF_TYPE const_reference; vector(); vector(size_type n); - size_type size() const; + // Note that it returns int, and not size_type, for compatibility with + // the signature of size() in Java interface. + int size() const; size_type capacity() const; void reserve(size_type n); %rename(isEmpty) empty; bool empty() const; void clear(); - %rename(add) push_back; - void push_back(const value_type& x); %extend { - CREF_TYPE get(int i) throw (std::out_of_range) { + void doAdd(const value_type& value) { + self->push_back(value); + } + + void doAdd(int index, const value_type& value) throw (std::out_of_range) { + const int size = int(self->size()); + if (0 <= index && index <= size) { + self->insert(self->begin() + index, value); + } else { + throw std::out_of_range("vector index out of range"); + } + } + value_type doRemove(int index) throw (std::out_of_range) { + const int size = int(self->size()); + if (0 <= index && index < size) { + CTYPE const old_value = (*self)[index]; + self->erase(self->begin() + index); + return old_value; + } else { + throw std::out_of_range("vector index out of range"); + } + } + CREF_TYPE doGet(int i) throw (std::out_of_range) { int size = int(self->size()); if (i>=0 && isize()); - if (i>=0 && i=0 && isize()); + if (0 <= fromIndex && fromIndex <= toIndex && toIndex <= size) { + self->erase(self->begin() + fromIndex, self->begin() + toIndex); + } else { + throw std::out_of_range("vector index out of range"); + } + } } %enddef +%javamethodmodifiers std::vector::doAdd "private"; +%javamethodmodifiers std::vector::doGet "private"; +%javamethodmodifiers std::vector::doSet "private"; +%javamethodmodifiers std::vector::doRemove "private"; +%javamethodmodifiers std::vector::doRemoveRange "private"; + namespace std { template class vector { From eba70ed16f7cd6d678633d8fc98562548672933d Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Tue, 29 Nov 2016 00:20:24 +0100 Subject: [PATCH 3/4] Add runtime checks for vector size in Java It doesn't seem to be possible to have a Java collection with more than 2^31-1 items, but it is perfectly possible to have an std::vector with more elements than that in C++, so add runtime checks verifying that we don't lose count of elements in the Java wrappers. --- Lib/java/std_vector.i | 42 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 34 insertions(+), 8 deletions(-) diff --git a/Lib/java/std_vector.i b/Lib/java/std_vector.i index 6c745aa23..fee33f8c2 100644 --- a/Lib/java/std_vector.i +++ b/Lib/java/std_vector.i @@ -7,6 +7,27 @@ %{ #include #include +#include + +// C++ allows to have up to 2^64-1 items in a vector on 64 bit machines and +// 2^32-1 even on 32 bit ones, but in Java size() must return a value of type +// "int" which is limited to signed 32 bit values, i.e. 2^31-1, and there +// doesn't seem to be any way to represent bigger vectors there. +// +// The only thing we can do is to at least detect such situation and throw an +// exception instead of silently returning the wrong size in this case and we +// use this helper to convert size_t values to int, instead of just casting +// them, in order to achieve this. +namespace { +int size_as_int(std::size_t sz) { + if (sz > static_cast(INT_MAX)) { + throw std::out_of_range("vector size is too big to be representable as int"); + } + + return static_cast(sz); +} +} // anonymous namespace + %} %define SWIG_STD_VECTOR_MINIMUM_INTERNAL(CTYPE, CREF_TYPE) @@ -55,6 +76,10 @@ modCount++; doRemoveRange(fromIndex, toIndex); } + + public int size() { + return doSize(); + } %} public: @@ -63,21 +88,22 @@ typedef CREF_TYPE const_reference; vector(); vector(size_type n); - // Note that it returns int, and not size_type, for compatibility with - // the signature of size() in Java interface. - int size() const; size_type capacity() const; void reserve(size_type n); %rename(isEmpty) empty; bool empty() const; void clear(); %extend { + int doSize() const { + return size_as_int(self->size()); + } + void doAdd(const value_type& value) { self->push_back(value); } void doAdd(int index, const value_type& value) throw (std::out_of_range) { - const int size = int(self->size()); + const int size = size_as_int(self->size()); if (0 <= index && index <= size) { self->insert(self->begin() + index, value); } else { @@ -85,7 +111,7 @@ } } value_type doRemove(int index) throw (std::out_of_range) { - const int size = int(self->size()); + const int size = size_as_int(self->size()); if (0 <= index && index < size) { CTYPE const old_value = (*self)[index]; self->erase(self->begin() + index); @@ -95,14 +121,14 @@ } } CREF_TYPE doGet(int i) throw (std::out_of_range) { - int size = int(self->size()); + const int size = size_as_int(self->size()); if (i>=0 && isize()); + const int size = size_as_int(self->size()); if (i>=0 && isize()); + const int size = size_as_int(self->size()); if (0 <= fromIndex && fromIndex <= toIndex && toIndex <= size) { self->erase(self->begin() + fromIndex, self->begin() + toIndex); } else { From 0bafadea5a2852fc88809ee2c5dbdfeb04eabbf1 Mon Sep 17 00:00:00 2001 From: William S Fulton Date: Fri, 26 May 2017 18:55:52 +0100 Subject: [PATCH 4/4] Fix potential STL std::vector wrappers <: digraphs problems. --- Lib/java/std_vector.i | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Lib/java/std_vector.i b/Lib/java/std_vector.i index fee33f8c2..6d4f75010 100644 --- a/Lib/java/std_vector.i +++ b/Lib/java/std_vector.i @@ -31,9 +31,9 @@ int size_as_int(std::size_t sz) { %} %define SWIG_STD_VECTOR_MINIMUM_INTERNAL(CTYPE, CREF_TYPE) -%typemap(javabase) std::vector "java.util.AbstractList<$typemap(jboxtype, CTYPE)>" -%typemap(javainterfaces) std::vector "java.util.RandomAccess" -%typemap(javacode) std::vector %{ +%typemap(javabase) std::vector< CTYPE > "java.util.AbstractList<$typemap(jboxtype, CTYPE)>" +%typemap(javainterfaces) std::vector< CTYPE > "java.util.RandomAccess" +%typemap(javacode) std::vector< CTYPE > %{ public $javaclassname($typemap(jstype, CTYPE)[] initialElements) { this(); for ($typemap(jstype, CTYPE) element : initialElements) {