Java std::list rework to be consistent with std::vector wrappers

This commit is contained in:
William S Fulton 2017-06-22 11:47:56 +01:00
commit dd25f5b722

View file

@ -2,137 +2,35 @@
%{ %{
#include <list> #include <list>
#include <algorithm> #include <stdexcept>
%} %}
%fragment("SWIG_ListSize", "header", fragment="SWIG_JavaIntFromSize_t") {
SWIGINTERN jint SWIG_ListSize(size_t size) {
jint sz = SWIG_JavaIntFromSize_t(size);
if (sz == -1)
throw std::out_of_range("list size is too large to fit into a Java int");
return sz;
}
}
%javamethodmodifiers std::list::begin "private"; %javamethodmodifiers std::list::begin "private";
%javamethodmodifiers std::list::insert "private"; %javamethodmodifiers std::list::insert "private";
%javamethodmodifiers std::list::set "private"; %javamethodmodifiers std::list::set "private";
%javamethodmodifiers std::list::previous_index "private";
%javamethodmodifiers std::list::next_index "private";
%javamethodmodifiers std::list::previous "private"; %javamethodmodifiers std::list::previous "private";
%javamethodmodifiers std::list::next "private"; %javamethodmodifiers std::list::next "private";
%javamethodmodifiers std::list::deref "private"; %javamethodmodifiers std::list::deref "private";
%javamethodmodifiers std::list::advance "private"; %javamethodmodifiers std::list::advance "private";
%javamethodmodifiers std::list::has_next "private"; %javamethodmodifiers std::list::doSize "private";
%javamethodmodifiers std::list::doPreviousIndex "private";
/* %javamethodmodifiers std::list::doNextIndex "private";
To conform to Java Collection interface we must return int from size(). %javamethodmodifiers std::list::doHasNext "private";
Unfortunately that loses precision from the integer types commonly used in
C++ implementations. Since we can't overload on return values the best
workaround here is to expose the real C++ size() return value to Java as a
long and use the javaout typemap to validate. We can then at least fails
gracefully in the case where we have a collection with > 2^31-1 items rather
than failing mysteriously.
The use of SWIG_list_size_type here allows us to selectively %apply this to
only the cases where we have to conform to the Java interface requirement,
without interfering with other size_type usage. The intention is that
SWIG_list_size_type is both reserved and unique. (Perhaps it could live in
std_common.i later on?)
*/
%typemap(jstype) SWIG_list_size_type "int";
%typemap(javaout) SWIG_list_size_type {
final long result = $jnicall;
if (result > Integer.MAX_VALUE) {
throw new IndexOutOfBoundsException("Size of Collection is not representable as int");
}
return (int)result;
}
// Match Java style better: // Match Java style better:
%rename(Iterator) std::list::iterator; %rename(Iterator) std::list::iterator;
%nodefaultctor std::list::iterator; %nodefaultctor std::list::iterator;
namespace std {
template <typename T> class list {
public:
typedef size_t size_type;
typedef T value_type;
typedef T& reference;
%apply SWIG_list_size_type { size_type next_index, size_type previous_index, size_type size };
/*
* We'd actually be better off having the nested class *not* be static in the wrapper
* output, but this doesn't actually remove the $static from the nested class still.
* (This would allow us to somewhat simplify the implementation of the ListIterator
* interface and give "natural" semantics to Java users of the C++ iterator)
*/
//%typemap(javaclassmodifiers) iterator "public class"
//%typemap(javainterfaces) iterator "ListIterator<$typemap(jboxtype,$1_basetype::value_type)>"
struct iterator {
%extend {
void set_unchecked(const value_type& v) {
**$self = v;
}
iterator next_unchecked() const {
std::list<T>::iterator ret=*$self;
++ret;
return ret;
}
iterator previous_unchecked() const {
std::list<T>::iterator ret=*$self;
--ret;
return ret;
}
value_type deref_unchecked() const {
return **$self;
}
iterator advance_unchecked(const size_type index) const {
std::list<T>::iterator ret=*$self;
std::advance(ret, index);
return ret;
}
}
};
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);
size_type size() const;
// Although sort() is nice it makes operator<() mandatory which it probably shouldn't be
//void sort();
iterator begin();
iterator end();
iterator insert(iterator pos, const value_type &v);
%extend {
size_type previous_index(const iterator& pos) const {
return pos == self->begin() ? -1 : std::distance(self->begin(), static_cast<std::list<T>::const_iterator>(pos));
}
size_type next_index(const iterator& pos) const {
return pos == self->end() ? self->size() : std::distance(self->begin(), static_cast<std::list<T>::const_iterator>(pos));
}
bool has_next(const iterator& pos) const {
return pos != $self->end();
}
}
};
}
%typemap(javaimports) std::list %{ %typemap(javaimports) std::list %{
import java.util.AbstractSequentialList; import java.util.AbstractSequentialList;
import java.util.ListIterator; import java.util.ListIterator;
@ -140,61 +38,65 @@ namespace std {
import java.util.Collection; import java.util.Collection;
%} %}
%typemap(javabase) std::list "AbstractSequentialList<$typemap(jboxtype,$1_basetype::value_type)>" %typemap(javabase) std::list "AbstractSequentialList<$typemap(jboxtype, $1_basetype::value_type)>"
#define JAVA_VALUE_TYPE $typemap(jboxtype,$1_basetype::value_type) namespace std {
#define JAVA_ITERATOR_TYPE Iterator template <typename T> class list {
%typemap(javacode,noblock=1) std::list { %proxycode %{
public $javaclassname(Collection c) { public $javaclassname(Collection c) {
this(); this();
ListIterator<JAVA_VALUE_TYPE> it = listIterator(0); ListIterator<$typemap(jboxtype, T)> it = listIterator(0);
// We should special case the "copy constructor" here to avoid lots of cross-language calls // Special case the "copy constructor" here to avoid lots of cross-language calls
for (Object o: c) { for (Object o : c) {
it.add((JAVA_VALUE_TYPE)o); it.add(($typemap(jboxtype, T))o);
} }
} }
public ListIterator<JAVA_VALUE_TYPE> listIterator(int index) { public int size() {
return new ListIterator<JAVA_VALUE_TYPE>() { return doSize();
private JAVA_ITERATOR_TYPE pos; }
private JAVA_ITERATOR_TYPE last;
private ListIterator<JAVA_VALUE_TYPE> init(int index) { public ListIterator<$typemap(jboxtype, T)> listIterator(int index) {
return new ListIterator<$typemap(jboxtype, T)>() {
private Iterator pos;
private Iterator last;
private ListIterator<$typemap(jboxtype, T)> init(int index) {
pos = $javaclassname.this.begin(); pos = $javaclassname.this.begin();
pos = pos.advance_unchecked(index); pos = pos.advance_unchecked(index);
return this; return this;
} }
public void add(JAVA_VALUE_TYPE v) { public void add($typemap(jboxtype, T) v) {
// Technically we can invalidate last here, but this makes more sense // Technically we can invalidate last here, but this makes more sense
last=$javaclassname.this.insert(pos, v); last = $javaclassname.this.insert(pos, v);
} }
public void set(JAVA_VALUE_TYPE v) { public void set($typemap(jboxtype, T) v) {
if (null==last) { if (null == last) {
throw new IllegalStateException(); throw new IllegalStateException();
} }
last.set_unchecked(v); last.set_unchecked(v);
} }
public void remove() { public void remove() {
if (null==last) { if (null == last) {
throw new IllegalStateException(); throw new IllegalStateException();
} }
$javaclassname.this.remove(last); $javaclassname.this.remove(last);
last=null; last = null;
} }
public int previousIndex() { public int previousIndex() {
return $javaclassname.this.previous_index(pos); return $javaclassname.this.doPreviousIndex(pos);
} }
public int nextIndex() { public int nextIndex() {
return $javaclassname.this.next_index(pos); return $javaclassname.this.doNextIndex(pos);
} }
public JAVA_VALUE_TYPE previous() { public $typemap(jboxtype, T) previous() {
if (previousIndex() < 0) { if (previousIndex() < 0) {
throw new NoSuchElementException(); throw new NoSuchElementException();
} }
@ -203,7 +105,7 @@ namespace std {
return last.deref_unchecked(); return last.deref_unchecked();
} }
public JAVA_VALUE_TYPE next() { public $typemap(jboxtype, T) next() {
if (!hasNext()) { if (!hasNext()) {
throw new NoSuchElementException(); throw new NoSuchElementException();
} }
@ -218,8 +120,88 @@ namespace std {
} }
public boolean hasNext() { public boolean hasNext() {
return $javaclassname.this.has_next(pos); return $javaclassname.this.doHasNext(pos);
} }
}.init(index); }.init(index);
} }
%}
public:
typedef size_t size_type;
typedef T value_type;
typedef T &reference;
/*
* We'd actually be better off having the nested class *not* be static in the wrapper
* output, but this doesn't actually remove the $static from the nested class still.
* (This would allow us to somewhat simplify the implementation of the ListIterator
* interface and give "natural" semantics to Java users of the C++ iterator)
*/
//%typemap(javaclassmodifiers) iterator "public class"
//%typemap(javainterfaces) iterator "ListIterator<$typemap(jboxtype, $1_basetype::value_type)>"
struct iterator {
%extend {
void set_unchecked(const value_type &v) {
**$self = v;
}
iterator next_unchecked() const {
std::list<T>::iterator ret = *$self;
++ret;
return ret;
}
iterator previous_unchecked() const {
std::list<T>::iterator ret = *$self;
--ret;
return ret;
}
value_type deref_unchecked() const {
return **$self;
}
iterator advance_unchecked(const size_type index) const {
std::list<T>::iterator ret = *$self;
std::advance(ret, index);
return ret;
}
}
};
list();
list(size_type n, const value_type &value = value_type());
list(const list &o);
~list();
void assign(size_type n, const value_type &val);
bool empty() const;
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);
iterator begin();
iterator end();
iterator insert(iterator pos, const value_type &v);
%extend {
%fragment("SWIG_ListSize");
jint doSize() const throw (std::out_of_range) {
return SWIG_ListSize(self->size());
}
jint doPreviousIndex(const iterator &pos) const {
return pos == self->begin() ? -1 : SWIG_ListSize(std::distance(self->begin(), static_cast<std::list<T>::const_iterator>(pos)));
}
jint doNextIndex(const iterator &pos) const {
return pos == self->end() ? self->size() : SWIG_ListSize(std::distance(self->begin(), static_cast<std::list<T>::const_iterator>(pos)));
}
bool doHasNext(const iterator &pos) const {
return pos != $self->end();
}
}
};
} }