swig/Lib/java/std_list.i
William S Fulton c686045f55 More efficient add implementation for Java std::list
The default implementation in AbstractSequentialList<E>
calls add(size(), e) and size() might be expensive.
2017-06-24 23:33:31 +01:00

215 lines
6 KiB
OpenEdge ABL

%include <std_common.i>
%{
#include <list>
#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::push_back "private";
%javamethodmodifiers std::list::begin "private";
%javamethodmodifiers std::list::insert "private";
%javamethodmodifiers std::list::doSize "private";
%javamethodmodifiers std::list::doPreviousIndex "private";
%javamethodmodifiers std::list::doNextIndex "private";
%javamethodmodifiers std::list::doHasNext "private";
// Match Java style better:
%rename(Iterator) std::list::iterator;
%nodefaultctor std::list::iterator;
namespace std {
template <typename T> class list {
%typemap(javabase) std::list<T> "java.util.AbstractSequentialList<$typemap(jboxtype, T)>"
%proxycode %{
public $javaclassname(java.util.Collection c) {
this();
java.util.ListIterator<$typemap(jboxtype, T)> it = listIterator(0);
// Special case the "copy constructor" here to avoid lots of cross-language calls
for (Object o : c) {
it.add(($typemap(jboxtype, T))o);
}
}
public int size() {
return doSize();
}
public boolean add($typemap(jboxtype, T) value) {
push_back(value);
return true;
}
public java.util.ListIterator<$typemap(jboxtype, T)> listIterator(int index) {
return new java.util.ListIterator<$typemap(jboxtype, T)>() {
private Iterator pos;
private Iterator last;
private java.util.ListIterator<$typemap(jboxtype, T)> init(int index) {
pos = $javaclassname.this.begin();
pos = pos.advance_unchecked(index);
return this;
}
public void add($typemap(jboxtype, T) v) {
// Technically we can invalidate last here, but this makes more sense
last = $javaclassname.this.insert(pos, v);
}
public void set($typemap(jboxtype, T) v) {
if (null == last) {
throw new IllegalStateException();
}
last.set_unchecked(v);
}
public void remove() {
if (null == last) {
throw new IllegalStateException();
}
$javaclassname.this.remove(last);
last = null;
}
public int previousIndex() {
return $javaclassname.this.doPreviousIndex(pos);
}
public int nextIndex() {
return $javaclassname.this.doNextIndex(pos);
}
public $typemap(jboxtype, T) previous() {
if (previousIndex() < 0) {
throw new java.util.NoSuchElementException();
}
last = pos;
pos = pos.previous_unchecked();
return last.deref_unchecked();
}
public $typemap(jboxtype, T) next() {
if (!hasNext()) {
throw new java.util.NoSuchElementException();
}
last = pos;
pos = pos.next_unchecked();
return last.deref_unchecked();
}
public boolean hasPrevious() {
// This call to previousIndex() will be much slower than the hasNext() implementation, but it's simpler like this with C++ forward iterators
return previousIndex() != -1;
}
public boolean hasNext() {
return $javaclassname.this.doHasNext(pos);
}
}.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 "java.util.ListIterator<$typemap(jboxtype, T)>"
struct iterator {
%extend {
void set_unchecked(const T &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;
}
T deref_unchecked() const {
return **$self;
}
iterator advance_unchecked(size_type index) const {
std::list<T>::iterator ret = *$self;
std::advance(ret, index);
return ret;
}
}
};
list();
list(const list &other);
~list();
void assign(size_type n, const T &value);
%rename(isEmpty) empty;
bool empty() const;
void clear();
%rename(remove) erase;
iterator erase(iterator pos);
size_type max_size() const;
void pop_back();
void pop_front();
void push_back(const T &value);
void push_front(const T &value);
iterator begin();
iterator end();
iterator insert(iterator pos, const T &value);
%extend {
%fragment("SWIG_ListSize");
list(jint count) throw (std::out_of_range) {
if (count < 0)
throw std::out_of_range("list count must be positive");
return new std::list<T>(static_cast<std::list<T>::size_type>(count));
}
list(jint count, const T &value) throw (std::out_of_range) {
if (count < 0)
throw std::out_of_range("list count must be positive");
return new std::list<T>(static_cast<std::list<T>::size_type>(count), value);
}
jint doSize() const throw (std::out_of_range) {
return SWIG_ListSize(self->size());
}
jint doPreviousIndex(const iterator &pos) const throw (std::out_of_range) {
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 throw (std::out_of_range) {
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();
}
}
};
}