diff --git a/Lib/java/java.swg b/Lib/java/java.swg index 2ffb57196..e0ddcba02 100644 --- a/Lib/java/java.swg +++ b/Lib/java/java.swg @@ -54,6 +54,14 @@ SWIGINTERN const char * SWIG_UnpackData(const char *c, void *ptr, size_t sz) { } } +%fragment("SWIG_JavaIntFromSize_t", "header") { +/* Check for overflow converting to Java int (always signed 32-bit) from (unsigned variable-bit) size_t */ +SWIGINTERN jint SWIG_JavaIntFromSize_t(size_t size) { + static const jint JINT_MAX = 0x7FFFFFFF; + return (size > (size_t)JINT_MAX) ? -1 : (jint)size; +} +} + /* Primitive types */ %typemap(jni) bool, const bool & "jboolean" %typemap(jni) char, const char & "jchar" diff --git a/Lib/java/std_vector.i b/Lib/java/std_vector.i index 99fbd3e9a..4f5afe6db 100644 --- a/Lib/java/std_vector.i +++ b/Lib/java/std_vector.i @@ -7,29 +7,17 @@ %{ #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 - %} +%fragment("SWIG_VectorSize", "header", fragment="SWIG_JavaIntFromSize_t") { +SWIGINTERN jint SWIG_VectorSize(size_t size) { + jint sz = SWIG_JavaIntFromSize_t(size); + if (sz == -1) + throw std::out_of_range("vector size is too large to fit into a Java int"); + return sz; +} +} + %define SWIG_STD_VECTOR_MINIMUM_INTERNAL(CTYPE, CREF_TYPE) %typemap(javabase) std::vector< CTYPE > "java.util.AbstractList<$typemap(jboxtype, CTYPE)>" %typemap(javainterfaces) std::vector< CTYPE > "java.util.RandomAccess" @@ -94,16 +82,17 @@ int size_as_int(std::size_t sz) { bool empty() const; void clear(); %extend { - int doSize() const { - return size_as_int(self->size()); + %fragment("SWIG_VectorSize"); + jint doSize() const throw (std::out_of_range) { + return SWIG_VectorSize(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 = size_as_int(self->size()); + void doAdd(jint index, const value_type& value) throw (std::out_of_range) { + const jint size = SWIG_VectorSize(self->size()); if (0 <= index && index <= size) { self->insert(self->begin() + index, value); } else { @@ -111,8 +100,8 @@ int size_as_int(std::size_t sz) { } } - value_type doRemove(int index) throw (std::out_of_range) { - const int size = size_as_int(self->size()); + value_type doRemove(jint index) throw (std::out_of_range) { + const jint size = SWIG_VectorSize(self->size()); if (0 <= index && index < size) { CTYPE const old_value = (*self)[index]; self->erase(self->begin() + index); @@ -122,27 +111,27 @@ int size_as_int(std::size_t sz) { } } - CREF_TYPE doGet(int i) throw (std::out_of_range) { - const int size = size_as_int(self->size()); - if (i>=0 && isize()); + if (index >= 0 && index < size) + return (*self)[index]; else throw std::out_of_range("vector index out of range"); } - value_type doSet(int i, const value_type& value) throw (std::out_of_range) { - const int size = size_as_int(self->size()); - if (i>=0 && isize()); + if (index >= 0 && index < size) { + CTYPE const old_value = (*self)[index]; + (*self)[index] = value; return old_value; } else throw std::out_of_range("vector index out of range"); } - void doRemoveRange(int fromIndex, int toIndex) throw (std::out_of_range) { - const int size = size_as_int(self->size()); + void doRemoveRange(jint fromIndex, jint toIndex) throw (std::out_of_range) { + const jint size = SWIG_VectorSize(self->size()); if (0 <= fromIndex && fromIndex <= toIndex && toIndex <= size) { self->erase(self->begin() + fromIndex, self->begin() + toIndex); } else {