519 lines
15 KiB
OpenEdge ABL
519 lines
15 KiB
OpenEdge ABL
/* -----------------------------------------------------------------------------
|
|
* std_list.i
|
|
*
|
|
* SWIG typemaps for std::list<T>
|
|
* C# implementation
|
|
* The C# wrapper is made to look and feel like a C# System.Collections.Generic.LinkedList<> collection.
|
|
*
|
|
* Note that IEnumerable<> is implemented in the proxy class which is useful for using LINQ with
|
|
* C++ std::list wrappers. The ICollection<> interface is also implemented to provide enhanced functionality
|
|
* whenever we are confident that the required C++ operator== is available. This is the case for when
|
|
* T is a primitive type or a pointer. If T does define an operator==, then use the SWIG_STD_LIST_ENHANCED
|
|
* macro to obtain this enhanced functionality, for example:
|
|
*
|
|
* SWIG_STD_LIST_ENHANCED(SomeNamespace::Klass)
|
|
* %template(ListKlass) std::list<SomeNamespace::Klass>;
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
%include <std_common.i>
|
|
|
|
// MACRO for use within the std::list class body
|
|
%define SWIG_STD_LIST_MINIMUM_INTERNAL(CSINTERFACE, CTYPE...)
|
|
%typemap(csinterfaces) std::list< CTYPE > "global::System.IDisposable, global::System.Collections.IEnumerable, global::System.Collections.Generic.CSINTERFACE<$typemap(cstype, CTYPE)>\n"
|
|
|
|
%apply void *VOID_INT_PTR { std::list< CTYPE >::iterator * };
|
|
|
|
%proxycode %{
|
|
public $csclassname(global::System.Collections.IEnumerable c) : this() {
|
|
if (c == null)
|
|
throw new global::System.ArgumentNullException("c");
|
|
foreach ($typemap(cstype, CTYPE) element in c) {
|
|
this.AddLast(element);
|
|
}
|
|
}
|
|
|
|
public bool IsReadOnly {
|
|
get {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public int Count {
|
|
get {
|
|
return (int)size();
|
|
}
|
|
}
|
|
|
|
public $csclassnameNode First {
|
|
get {
|
|
if (Count == 0)
|
|
return null;
|
|
return new $csclassnameNode(getFirstIter(), this);
|
|
}
|
|
}
|
|
|
|
public $csclassnameNode Last {
|
|
get {
|
|
if (Count == 0)
|
|
return null;
|
|
return new $csclassnameNode(getLastIter(), this);
|
|
}
|
|
}
|
|
|
|
public $csclassnameNode AddFirst($typemap(cstype, CTYPE) value) {
|
|
push_front(value);
|
|
return new $csclassnameNode(getFirstIter(), this);
|
|
}
|
|
|
|
public void AddFirst($csclassnameNode newNode) {
|
|
ValidateNewNode(newNode);
|
|
if (!newNode.inlist) {
|
|
push_front(newNode.csharpvalue);
|
|
newNode.iter = getFirstIter();
|
|
newNode.inlist = true;
|
|
} else {
|
|
throw new global::System.InvalidOperationException("The " + newNode.GetType().Name + " node already belongs to a " + this.GetType().Name);
|
|
}
|
|
}
|
|
|
|
public $csclassnameNode AddLast($typemap(cstype, CTYPE) value) {
|
|
push_back(value);
|
|
return new $csclassnameNode(getLastIter(), this);
|
|
}
|
|
|
|
public void AddLast($csclassnameNode newNode) {
|
|
ValidateNewNode(newNode);
|
|
if (!newNode.inlist) {
|
|
push_back(newNode.csharpvalue);
|
|
newNode.iter = getLastIter();
|
|
newNode.inlist = true;
|
|
} else {
|
|
throw new global::System.InvalidOperationException("The " + newNode.GetType().Name + " node already belongs to a " + this.GetType().Name);
|
|
}
|
|
}
|
|
|
|
public $csclassnameNode AddBefore($csclassnameNode node, $typemap(cstype, CTYPE) value) {
|
|
return new $csclassnameNode(insertNode(node.iter, value), this);
|
|
}
|
|
|
|
public void AddBefore($csclassnameNode node, $csclassnameNode newNode) {
|
|
ValidateNode(node);
|
|
ValidateNewNode(newNode);
|
|
if (!newNode.inlist) {
|
|
newNode.iter = insertNode(node.iter, newNode.csharpvalue);
|
|
newNode.inlist = true;
|
|
} else {
|
|
throw new global::System.InvalidOperationException("The " + newNode.GetType().Name + " node already belongs to a " + this.GetType().Name);
|
|
}
|
|
}
|
|
|
|
public $csclassnameNode AddAfter($csclassnameNode node, $typemap(cstype, CTYPE) value) {
|
|
node = node.Next;
|
|
return new $csclassnameNode(insertNode(node.iter, value), this);
|
|
}
|
|
|
|
public void AddAfter($csclassnameNode node, $csclassnameNode newNode) {
|
|
ValidateNode(node);
|
|
ValidateNewNode(newNode);
|
|
if (!newNode.inlist) {
|
|
if (node == this.Last)
|
|
AddLast(newNode);
|
|
else
|
|
{
|
|
node = node.Next;
|
|
newNode.iter = insertNode(node.iter, newNode.csharpvalue);
|
|
newNode.inlist = true;
|
|
}
|
|
} else {
|
|
throw new global::System.InvalidOperationException("The " + newNode.GetType().Name + " node already belongs to a " + this.GetType().Name);
|
|
}
|
|
}
|
|
|
|
public void Add($typemap(cstype, CTYPE) value) {
|
|
AddLast(value);
|
|
}
|
|
|
|
public void Remove($csclassnameNode node) {
|
|
ValidateNode(node);
|
|
eraseIter(node.iter);
|
|
}
|
|
|
|
public void CopyTo($typemap(cstype, CTYPE)[] array, int index) {
|
|
if (array == null)
|
|
throw new global::System.ArgumentNullException("array");
|
|
if (index < 0 || index > array.Length)
|
|
throw new global::System.ArgumentOutOfRangeException("index", "Value is less than zero");
|
|
if (array.Rank > 1)
|
|
throw new global::System.ArgumentException("Multi dimensional array.", "array");
|
|
$csclassnameNode node = this.First;
|
|
if (node != null) {
|
|
do {
|
|
array[index++] = node.Value;
|
|
node = node.Next;
|
|
} while (node != null);
|
|
}
|
|
}
|
|
|
|
internal void ValidateNode($csclassnameNode node) {
|
|
if (node == null) {
|
|
throw new System.ArgumentNullException("node");
|
|
}
|
|
if (!node.inlist || node.list != this) {
|
|
throw new System.InvalidOperationException("node");
|
|
}
|
|
}
|
|
|
|
internal void ValidateNewNode($csclassnameNode node) {
|
|
if (node == null) {
|
|
throw new System.ArgumentNullException("node");
|
|
}
|
|
}
|
|
|
|
global::System.Collections.Generic.IEnumerator<$typemap(cstype, CTYPE)> global::System.Collections.Generic.IEnumerable<$typemap(cstype, CTYPE)>.GetEnumerator() {
|
|
return new $csclassnameEnumerator(this);
|
|
}
|
|
|
|
global::System.Collections.IEnumerator global::System.Collections.IEnumerable.GetEnumerator() {
|
|
return new $csclassnameEnumerator(this);
|
|
}
|
|
|
|
public $csclassnameEnumerator GetEnumerator() {
|
|
return new $csclassnameEnumerator(this);
|
|
}
|
|
|
|
public sealed class $csclassnameEnumerator : global::System.Collections.IEnumerator,
|
|
global::System.Collections.Generic.IEnumerator<$typemap(cstype, CTYPE)>
|
|
{
|
|
private $csclassname collectionRef;
|
|
private $csclassnameNode currentNode;
|
|
private int currentIndex;
|
|
private object currentObject;
|
|
private int currentSize;
|
|
|
|
public $csclassnameEnumerator($csclassname collection) {
|
|
collectionRef = collection;
|
|
currentNode = collection.First;
|
|
currentIndex = 0;
|
|
currentObject = null;
|
|
currentSize = collectionRef.Count;
|
|
}
|
|
|
|
// Type-safe iterator Current
|
|
public $typemap(cstype, CTYPE) Current {
|
|
get {
|
|
if (currentIndex == -1)
|
|
throw new global::System.InvalidOperationException("Enumeration not started.");
|
|
if (currentIndex > currentSize)
|
|
throw new global::System.InvalidOperationException("Enumeration finished.");
|
|
if (currentObject == null)
|
|
throw new global::System.InvalidOperationException("Collection modified.");
|
|
return ($typemap(cstype, CTYPE))currentObject;
|
|
}
|
|
}
|
|
|
|
// Type-unsafe IEnumerator.Current
|
|
object global::System.Collections.IEnumerator.Current {
|
|
get {
|
|
return Current;
|
|
}
|
|
}
|
|
|
|
public bool MoveNext() {
|
|
if (currentNode == null) {
|
|
currentIndex = collectionRef.Count + 1;
|
|
return false;
|
|
}
|
|
++currentIndex;
|
|
currentObject = currentNode.Value;
|
|
currentNode = currentNode.Next;
|
|
return true;
|
|
}
|
|
|
|
public void Reset() {
|
|
currentIndex = -1;
|
|
currentObject = null;
|
|
if (collectionRef.Count != currentSize) {
|
|
throw new global::System.InvalidOperationException("Collection modified.");
|
|
}
|
|
}
|
|
|
|
public void Dispose() {
|
|
currentIndex = -1;
|
|
currentObject = null;
|
|
}
|
|
}
|
|
|
|
public sealed class $csclassnameNode {
|
|
internal $csclassname list;
|
|
internal System.IntPtr iter;
|
|
internal $typemap(cstype, CTYPE) csharpvalue;
|
|
internal bool inlist;
|
|
|
|
public $csclassnameNode($typemap(cstype, CTYPE) value) {
|
|
csharpvalue = value;
|
|
inlist = false;
|
|
}
|
|
|
|
internal $csclassnameNode(System.IntPtr iter, $csclassname list) {
|
|
this.list = list;
|
|
this.iter = iter;
|
|
inlist = true;
|
|
}
|
|
|
|
public $csclassname List {
|
|
get {
|
|
return this.list;
|
|
}
|
|
}
|
|
|
|
public $csclassnameNode Next {
|
|
get {
|
|
if (list.getNextIter(iter) == System.IntPtr.Zero)
|
|
return null;
|
|
return new $csclassnameNode(list.getNextIter(iter), list);
|
|
}
|
|
}
|
|
|
|
public $csclassnameNode Previous {
|
|
get {
|
|
if (list.getPrevIter(iter) == System.IntPtr.Zero)
|
|
return null;
|
|
return new $csclassnameNode(list.getPrevIter(iter), list);
|
|
}
|
|
}
|
|
|
|
public $typemap(cstype, CTYPE) Value {
|
|
get {
|
|
return list.getItem(this.iter);
|
|
}
|
|
set {
|
|
list.setItem(this.iter, value);
|
|
}
|
|
}
|
|
|
|
public static bool operator==($csclassnameNode node1, $csclassnameNode node2) {
|
|
if (object.ReferenceEquals(node1, null) && object.ReferenceEquals(node2, null))
|
|
return true;
|
|
if (object.ReferenceEquals(node1, null) || object.ReferenceEquals(node2, null))
|
|
return false;
|
|
return node1.Equals(node2);
|
|
}
|
|
|
|
public static bool operator!=($csclassnameNode node1, $csclassnameNode node2) {
|
|
if (node1 == null && node2 == null)
|
|
return false;
|
|
if (node1 == null || node2 == null)
|
|
return true;
|
|
return !node1.Equals(node2);
|
|
}
|
|
|
|
public bool Equals($csclassnameNode node) {
|
|
if (node == null)
|
|
return false;
|
|
if (!node.inlist || !this.inlist)
|
|
return object.ReferenceEquals(this, node);
|
|
return list.equals(this.iter, node.iter);
|
|
}
|
|
|
|
public override bool Equals(object node) {
|
|
return Equals(($csclassnameNode)node);
|
|
}
|
|
|
|
public override int GetHashCode() {
|
|
int hash = 13;
|
|
if (inlist) {
|
|
hash = (hash * 7) + this.list.GetHashCode();
|
|
hash = (hash * 7) + this.Value.GetHashCode();
|
|
hash = (hash * 7) + this.list.getNextIter(this.iter).GetHashCode();
|
|
hash = (hash * 7) + this.list.getPrevIter(this.iter).GetHashCode();
|
|
} else {
|
|
hash = (hash * 7) + this.csharpvalue.GetHashCode();
|
|
}
|
|
return hash;
|
|
}
|
|
|
|
public void Dispose() {
|
|
list.deleteIter(this.iter);
|
|
}
|
|
}
|
|
%}
|
|
|
|
public:
|
|
typedef size_t size_type;
|
|
typedef ptrdiff_t difference_type;
|
|
typedef CTYPE value_type;
|
|
typedef value_type* pointer;
|
|
typedef const value_type* const_pointer;
|
|
typedef value_type& reference;
|
|
typedef const value_type& const_reference;
|
|
|
|
class iterator;
|
|
|
|
void push_front(CTYPE const& x);
|
|
void push_back(CTYPE const& x);
|
|
%rename(RemoveFirst) pop_front;
|
|
void pop_front();
|
|
%rename(RemoveLast) pop_back;
|
|
void pop_back();
|
|
size_type size() const;
|
|
%rename(Clear) clear;
|
|
void clear();
|
|
%extend {
|
|
const_reference getItem(iterator *iter) {
|
|
return **iter;
|
|
}
|
|
|
|
void setItem(iterator *iter, CTYPE const& val) {
|
|
*(*iter) = val;
|
|
}
|
|
|
|
iterator *getFirstIter() {
|
|
if ($self->size() == 0)
|
|
return NULL;
|
|
return new std::list< CTYPE >::iterator($self->begin());
|
|
}
|
|
|
|
iterator *getLastIter() {
|
|
if ($self->size() == 0)
|
|
return NULL;
|
|
return new std::list< CTYPE >::iterator(--$self->end());
|
|
}
|
|
|
|
iterator *getNextIter(iterator *iter) {
|
|
std::list< CTYPE >::iterator it = *iter;
|
|
if (std::distance(it, --$self->end()) != 0) {
|
|
std::list< CTYPE >::iterator* itnext = new std::list< CTYPE >::iterator(++it);
|
|
return itnext;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
iterator *getPrevIter(iterator *iter) {
|
|
std::list< CTYPE >::iterator it = *iter;
|
|
if (std::distance($self->begin(), it) != 0) {
|
|
std::list< CTYPE >::iterator* itprev = new std::list< CTYPE >::iterator(--it);
|
|
return itprev;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
iterator *insertNode(iterator *iter, CTYPE const& value) {
|
|
std::list< CTYPE >::iterator it = $self->insert(*iter, value);
|
|
return new std::list< CTYPE >::iterator(it);
|
|
}
|
|
|
|
void eraseIter(iterator *iter) {
|
|
std::list< CTYPE >::iterator it = *iter;
|
|
$self->erase(it);
|
|
}
|
|
|
|
void deleteIter(iterator *iter) {
|
|
delete iter;
|
|
}
|
|
|
|
bool equals(iterator *iter1, iterator *iter2) {
|
|
if (iter1 == NULL && iter2 == NULL)
|
|
return true;
|
|
std::list< CTYPE >::iterator it1 = *iter1;
|
|
std::list< CTYPE >::iterator it2 = *iter2;
|
|
return it1 == it2;
|
|
}
|
|
}
|
|
%enddef
|
|
|
|
// Extra methods added to the collection class if operator== is defined for the class being wrapped
|
|
// The class will then implement ICollection<>, which adds extra functionality
|
|
%define SWIG_STD_LIST_EXTRA_OP_EQUALS_EQUALS(CTYPE...)
|
|
%extend {
|
|
bool Contains(CTYPE const& value) {
|
|
return std::find($self->begin(), $self->end(), value) != $self->end();
|
|
}
|
|
|
|
bool Remove(CTYPE const& value) {
|
|
std::list< CTYPE >::iterator it = std::find($self->begin(), $self->end(), value);
|
|
if (it != $self->end()) {
|
|
$self->erase(it);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
iterator *find(CTYPE const& value) {
|
|
if (std::find($self->begin(), $self->end(), value) != $self->end()) {
|
|
return new std::list< CTYPE >::iterator(std::find($self->begin(), $self->end(), value));
|
|
}
|
|
return NULL;
|
|
}
|
|
}
|
|
%proxycode %{
|
|
public $csclassnameNode Find($typemap(cstype, CTYPE) value) {
|
|
System.IntPtr tmp = find(value);
|
|
if (tmp != System.IntPtr.Zero) {
|
|
return new $csclassnameNode(tmp, this);
|
|
}
|
|
return null;
|
|
}
|
|
%}
|
|
%enddef
|
|
|
|
// Macros for std::list class specializations/enhancements
|
|
%define SWIG_STD_LIST_ENHANCED(CTYPE...)
|
|
namespace std {
|
|
template<> class list< CTYPE > {
|
|
SWIG_STD_LIST_MINIMUM_INTERNAL(ICollection, %arg(CTYPE));
|
|
SWIG_STD_LIST_EXTRA_OP_EQUALS_EQUALS(CTYPE)
|
|
};
|
|
}
|
|
%enddef
|
|
|
|
|
|
%{
|
|
#include <list>
|
|
#include <algorithm>
|
|
#include <stdexcept>
|
|
%}
|
|
|
|
%csmethodmodifiers std::list::size "private"
|
|
%csmethodmodifiers std::list::getItem "private"
|
|
%csmethodmodifiers std::list::setItem "private"
|
|
%csmethodmodifiers std::list::push_front "private"
|
|
%csmethodmodifiers std::list::push_back "private"
|
|
%csmethodmodifiers std::list::getFirstIter "private"
|
|
%csmethodmodifiers std::list::getNextIter "private"
|
|
%csmethodmodifiers std::list::getPrevIter "private"
|
|
%csmethodmodifiers std::list::getLastIter "private"
|
|
%csmethodmodifiers std::list::find "private"
|
|
%csmethodmodifiers std::list::deleteIter "private"
|
|
|
|
namespace std {
|
|
// primary (unspecialized) class template for std::list
|
|
// does not require operator== to be defined
|
|
template<class T>
|
|
class list {
|
|
SWIG_STD_LIST_MINIMUM_INTERNAL(IEnumerable, T)
|
|
};
|
|
// specialization for pointers
|
|
template<class T>
|
|
class list<T *> {
|
|
SWIG_STD_LIST_MINIMUM_INTERNAL(ICollection, T *)
|
|
SWIG_STD_LIST_EXTRA_OP_EQUALS_EQUALS(T *)
|
|
};
|
|
}
|
|
|
|
// template specializations for std::list
|
|
// these provide extra collections methods as operator== is defined
|
|
SWIG_STD_LIST_ENHANCED(char)
|
|
SWIG_STD_LIST_ENHANCED(signed char)
|
|
SWIG_STD_LIST_ENHANCED(unsigned char)
|
|
SWIG_STD_LIST_ENHANCED(short)
|
|
SWIG_STD_LIST_ENHANCED(unsigned short)
|
|
SWIG_STD_LIST_ENHANCED(int)
|
|
SWIG_STD_LIST_ENHANCED(unsigned int)
|
|
SWIG_STD_LIST_ENHANCED(long)
|
|
SWIG_STD_LIST_ENHANCED(unsigned long)
|
|
SWIG_STD_LIST_ENHANCED(long long)
|
|
SWIG_STD_LIST_ENHANCED(unsigned long long)
|
|
SWIG_STD_LIST_ENHANCED(float)
|
|
SWIG_STD_LIST_ENHANCED(double)
|
|
SWIG_STD_LIST_ENHANCED(std::string) // also requires a %include <std_string.i>
|
|
SWIG_STD_LIST_ENHANCED(std::wstring) // also requires a %include <std_wstring.i>
|