Merge branch 'csharp-set'
* csharp-set: Fix header comment in C# std_set typemaps Implement set-theoretic methods in std::set C# typemaps Add std::set<> typemaps for C#
This commit is contained in:
commit
51e75bacf7
4 changed files with 406 additions and 3 deletions
|
|
@ -7,6 +7,9 @@ the issue number to the end of the URL: https://github.com/swig/swig/issues/
|
||||||
Version 4.0.0 (in progress)
|
Version 4.0.0 (in progress)
|
||||||
===========================
|
===========================
|
||||||
|
|
||||||
|
2019-03-12: vadz
|
||||||
|
[C#] Add std::set<> typemaps.
|
||||||
|
|
||||||
2019-03-11: dirteat,opoplawski
|
2019-03-11: dirteat,opoplawski
|
||||||
[Octave] Fix compilation errors in Octave 5.1.
|
[Octave] Fix compilation errors in Octave 5.1.
|
||||||
|
|
||||||
|
|
|
||||||
89
Examples/test-suite/csharp/li_std_set_runme.cs
Normal file
89
Examples/test-suite/csharp/li_std_set_runme.cs
Normal file
|
|
@ -0,0 +1,89 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using li_std_setNamespace;
|
||||||
|
|
||||||
|
public class runme
|
||||||
|
{
|
||||||
|
static void checkThat(bool mustBeTrue, string message)
|
||||||
|
{
|
||||||
|
if (!mustBeTrue)
|
||||||
|
throw new Exception("Test that the set " + message + " failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void Main()
|
||||||
|
{
|
||||||
|
StringSet ss = new StringSet();
|
||||||
|
|
||||||
|
// Check the interface methods first.
|
||||||
|
ISet<string> s = ss;
|
||||||
|
|
||||||
|
checkThat(s.Count == 0, "is initially empty");
|
||||||
|
checkThat(!s.Contains("key"), "doesn't contain inexistent element");
|
||||||
|
checkThat(!s.Remove("key"), "returns false when removing inexistent element");
|
||||||
|
|
||||||
|
checkThat(s.Add("key"), "returns true when adding a new element");
|
||||||
|
checkThat(!s.Add("key"), "returns false when adding an existing element");
|
||||||
|
checkThat(s.Contains("key"), "contains the just added element");
|
||||||
|
checkThat(s.Remove("key"), "returns true when removing an existing element");
|
||||||
|
checkThat(s.Count == 0, "is empty again");
|
||||||
|
|
||||||
|
checkThat(s.Add("key1"), "Add(key1) returns true");
|
||||||
|
checkThat(s.Add("key2"), "Add(key2) returns true");
|
||||||
|
checkThat(s.Add("key3"), "Add(key3) returns true");
|
||||||
|
|
||||||
|
// Also check a different interface, providing a different Add() (sic!).
|
||||||
|
ICollection<string> coll = ss;
|
||||||
|
coll.Add("key");
|
||||||
|
checkThat(ss.Count == 4, "contains 4 elements");
|
||||||
|
|
||||||
|
// Now use object-specific methods, mimicking HashSet<>.
|
||||||
|
string val;
|
||||||
|
checkThat(ss.TryGetValue("key1", out val), "could retrieve existing item");
|
||||||
|
checkThat(val.Equals("key1"), "value was returned correctly by TryGetValue()");
|
||||||
|
checkThat(!ss.TryGetValue("no-such-key", out val), "couldn't retrieve inexistent item");
|
||||||
|
checkThat(val == null, "value was reset after failed TryGetValue()");
|
||||||
|
|
||||||
|
IList<string> list = new List<string>();
|
||||||
|
foreach (string str in ss) {
|
||||||
|
list.Add(str);
|
||||||
|
}
|
||||||
|
checkThat(list.Count == 4, "copy contains 4 elements");
|
||||||
|
|
||||||
|
ss.Clear();
|
||||||
|
checkThat(ss.Count == 0, "is empty after Clear()");
|
||||||
|
|
||||||
|
// Check set-theoretic methods.
|
||||||
|
checkThat(new StringSet().SetEquals(new StringSet()), "SetEquals() works for empty sets");
|
||||||
|
checkThat(new StringSet{"foo"}.SetEquals(new StringSet{"foo"}), "SetEquals() works for non-empty sets");
|
||||||
|
checkThat(!new StringSet{"foo"}.SetEquals(new[] {"bar"}), "SetEquals() doesn't always return true");
|
||||||
|
|
||||||
|
ss = new StringSet{"foo", "bar", "baz"};
|
||||||
|
ss.ExceptWith(new[] {"baz", "quux"});
|
||||||
|
checkThat(ss.SetEquals(new[] {"foo", "bar"}), "ExceptWith works");
|
||||||
|
|
||||||
|
ss = new StringSet{"foo", "bar", "baz"};
|
||||||
|
ss.IntersectWith(new[] {"baz", "quux"});
|
||||||
|
checkThat(ss.SetEquals(new[] {"baz"}), "IntersectWith works");
|
||||||
|
|
||||||
|
checkThat(ss.IsProperSubsetOf(new[] {"bar", "baz"}), "IsProperSubsetOf works");
|
||||||
|
checkThat(!ss.IsProperSubsetOf(new[] {"baz"}), "!IsProperSubsetOf works");
|
||||||
|
checkThat(ss.IsSubsetOf(new[] {"bar", "baz"}), "IsSubsetOf works");
|
||||||
|
checkThat(!ss.IsSubsetOf(new[] {"bar"}), "!IsSubsetOf works");
|
||||||
|
|
||||||
|
ss = new StringSet{"foo", "bar", "baz"};
|
||||||
|
checkThat(ss.IsProperSupersetOf(new[] {"bar"}), "IsProperSupersetOf works");
|
||||||
|
checkThat(!ss.IsProperSupersetOf(new[] {"quux"}), "IsProperSupersetOf works");
|
||||||
|
checkThat(ss.IsSupersetOf(new[] {"foo", "bar", "baz"}), "IsProperSupersetOf works");
|
||||||
|
checkThat(!ss.IsSupersetOf(new[] {"foo", "bar", "baz", "quux"}), "IsProperSupersetOf works");
|
||||||
|
|
||||||
|
checkThat(ss.Overlaps(new[] {"foo"}), "Overlaps works");
|
||||||
|
checkThat(!ss.Overlaps(new[] {"moo"}), "!Overlaps works");
|
||||||
|
|
||||||
|
ss.SymmetricExceptWith(new[] {"baz", "quux"});
|
||||||
|
checkThat(ss.SetEquals(new[] {"foo", "bar", "quux"}), "SymmetricExceptWith works");
|
||||||
|
|
||||||
|
ss = new StringSet{"foo", "bar", "baz"};
|
||||||
|
ss.UnionWith(new[] {"baz", "quux"});
|
||||||
|
checkThat(ss.SetEquals(new[] {"foo", "bar", "baz", "quux"}), "UnionWith works");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -15,14 +15,14 @@
|
||||||
%include <std_set.i>
|
%include <std_set.i>
|
||||||
%include <std_vector.i>
|
%include <std_vector.i>
|
||||||
|
|
||||||
// Use language macros since Java doesn't have multiset support (yet)
|
// Use language macros since Java and C# don't have multiset support (yet)
|
||||||
// and uses different naming conventions.
|
// and uses different naming conventions.
|
||||||
#if defined(SWIGRUBY) || defined(SWIGPYTHON)
|
#if defined(SWIGRUBY) || defined(SWIGPYTHON)
|
||||||
%include <std_multiset.i>
|
%include <std_multiset.i>
|
||||||
%template(set_int) std::multiset<int>;
|
%template(set_int) std::multiset<int>;
|
||||||
%template(v_int) std::vector<int>;
|
%template(v_int) std::vector<int>;
|
||||||
%template(set_string) std::set<std::string>;
|
%template(set_string) std::set<std::string>;
|
||||||
#elif defined(SWIGJAVA)
|
#elif defined(SWIGJAVA) || defined(SWIGCSHARP)
|
||||||
%template(StringSet) std::set<std::string>;
|
%template(StringSet) std::set<std::string>;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
||||||
311
Lib/csharp/std_set.i
Normal file
311
Lib/csharp/std_set.i
Normal file
|
|
@ -0,0 +1,311 @@
|
||||||
|
/* -----------------------------------------------------------------------------
|
||||||
|
* std_set.i
|
||||||
|
*
|
||||||
|
* SWIG typemaps for std::set<T>.
|
||||||
|
*
|
||||||
|
* Note that ISet<> used here requires .NET 4 or later.
|
||||||
|
*
|
||||||
|
* The C# wrapper implements ISet<> interface and shares performance
|
||||||
|
* characteristics of C# System.Collections.Generic.SortedSet<> class, but
|
||||||
|
* doesn't provide quite all of its methods.
|
||||||
|
* ----------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
%{
|
||||||
|
#include <set>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <stdexcept>
|
||||||
|
%}
|
||||||
|
|
||||||
|
%csmethodmodifiers std::set::size "private"
|
||||||
|
%csmethodmodifiers std::set::getitem "private"
|
||||||
|
%csmethodmodifiers std::set::create_iterator_begin "private"
|
||||||
|
%csmethodmodifiers std::set::get_next "private"
|
||||||
|
%csmethodmodifiers std::set::destroy_iterator "private"
|
||||||
|
|
||||||
|
namespace std {
|
||||||
|
|
||||||
|
// TODO: Add support for comparator and allocator template parameters.
|
||||||
|
template <class T>
|
||||||
|
class set {
|
||||||
|
|
||||||
|
%typemap(csinterfaces) std::set<T> "global::System.IDisposable, global::System.Collections.Generic.ISet<$typemap(cstype, T)>\n";
|
||||||
|
%proxycode %{
|
||||||
|
void global::System.Collections.Generic.ICollection<$typemap(cstype, T)>.Add(string item) {
|
||||||
|
((global::System.Collections.Generic.ISet<$typemap(cstype, T)>)this).Add(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryGetValue($typemap(cstype, T) equalValue, out $typemap(cstype, T) actualValue) {
|
||||||
|
try {
|
||||||
|
actualValue = getitem(equalValue);
|
||||||
|
return true;
|
||||||
|
} catch {
|
||||||
|
actualValue = default($typemap(cstype, T));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Count {
|
||||||
|
get {
|
||||||
|
return (int)size();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsReadOnly {
|
||||||
|
get {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CopyTo($typemap(cstype, T)[] array) {
|
||||||
|
CopyTo(array, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CopyTo($typemap(cstype, T)[] array, int arrayIndex) {
|
||||||
|
if (array == null)
|
||||||
|
throw new global::System.ArgumentNullException("array");
|
||||||
|
if (arrayIndex < 0)
|
||||||
|
throw new global::System.ArgumentOutOfRangeException("arrayIndex", "Value is less than zero");
|
||||||
|
if (array.Rank > 1)
|
||||||
|
throw new global::System.ArgumentException("Multi dimensional array.", "array");
|
||||||
|
if (arrayIndex+this.Count > array.Length)
|
||||||
|
throw new global::System.ArgumentException("Number of elements to copy is too large.");
|
||||||
|
|
||||||
|
foreach ($typemap(cstype, T) item in this) {
|
||||||
|
array.SetValue(item, arrayIndex++);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ExceptWith(global::System.Collections.Generic.IEnumerable<$typemap(cstype, T)> other) {
|
||||||
|
foreach ($typemap(cstype, T) item in other) {
|
||||||
|
Remove(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void IntersectWith(global::System.Collections.Generic.IEnumerable<$typemap(cstype, T)> other) {
|
||||||
|
$csclassname old = new $csclassname(this);
|
||||||
|
|
||||||
|
Clear();
|
||||||
|
foreach ($typemap(cstype, T) item in other) {
|
||||||
|
if (old.Contains(item))
|
||||||
|
Add(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int count_enum(global::System.Collections.Generic.IEnumerable<$typemap(cstype, T)> other) {
|
||||||
|
int count = 0;
|
||||||
|
foreach ($typemap(cstype, T) item in other) {
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsProperSubsetOf(global::System.Collections.Generic.IEnumerable<$typemap(cstype, T)> other) {
|
||||||
|
return IsSubsetOf(other) && Count < count_enum(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsProperSupersetOf(global::System.Collections.Generic.IEnumerable<$typemap(cstype, T)> other) {
|
||||||
|
return IsSupersetOf(other) && Count > count_enum(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsSubsetOf(global::System.Collections.Generic.IEnumerable<$typemap(cstype, T)> other) {
|
||||||
|
int countContained = 0;
|
||||||
|
|
||||||
|
foreach ($typemap(cstype, T) item in other) {
|
||||||
|
if (Contains(item))
|
||||||
|
countContained++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return countContained == Count;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsSupersetOf(global::System.Collections.Generic.IEnumerable<$typemap(cstype, T)> other) {
|
||||||
|
foreach ($typemap(cstype, T) item in other) {
|
||||||
|
if (!Contains(item))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Overlaps(global::System.Collections.Generic.IEnumerable<$typemap(cstype, T)> other) {
|
||||||
|
foreach ($typemap(cstype, T) item in other) {
|
||||||
|
if (Contains(item))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool SetEquals(global::System.Collections.Generic.IEnumerable<$typemap(cstype, T)> other) {
|
||||||
|
return IsSupersetOf(other) && Count == count_enum(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SymmetricExceptWith(global::System.Collections.Generic.IEnumerable<$typemap(cstype, T)> other) {
|
||||||
|
foreach ($typemap(cstype, T) item in other) {
|
||||||
|
if (!Remove(item))
|
||||||
|
Add(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UnionWith(global::System.Collections.Generic.IEnumerable<$typemap(cstype, T)> other) {
|
||||||
|
foreach ($typemap(cstype, T) item in other) {
|
||||||
|
Add(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private global::System.Collections.Generic.ICollection<$typemap(cstype, T)> Items {
|
||||||
|
get {
|
||||||
|
global::System.Collections.Generic.ICollection<$typemap(cstype, T)> items = new global::System.Collections.Generic.List<$typemap(cstype, T)>();
|
||||||
|
int size = this.Count;
|
||||||
|
if (size > 0) {
|
||||||
|
global::System.IntPtr iter = create_iterator_begin();
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
items.Add(get_next(iter));
|
||||||
|
}
|
||||||
|
destroy_iterator(iter);
|
||||||
|
}
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
global::System.Collections.Generic.IEnumerator<$typemap(cstype, T)> global::System.Collections.Generic.IEnumerable<$typemap(cstype, T)>.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);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Type-safe enumerator
|
||||||
|
/// Note that the IEnumerator documentation requires an InvalidOperationException to be thrown
|
||||||
|
/// whenever the collection is modified. This has been done for changes in the size of the
|
||||||
|
/// collection but not when one of the elements of the collection is modified as it is a bit
|
||||||
|
/// tricky to detect unmanaged code that modifies the collection under our feet.
|
||||||
|
public sealed class $csclassnameEnumerator : global::System.Collections.IEnumerator,
|
||||||
|
global::System.Collections.Generic.IEnumerator<$typemap(cstype, T)>
|
||||||
|
{
|
||||||
|
private $csclassname collectionRef;
|
||||||
|
private global::System.Collections.Generic.IList<$typemap(cstype, T)> ItemsCollection;
|
||||||
|
private int currentIndex;
|
||||||
|
private $typemap(cstype, T) currentObject;
|
||||||
|
private int currentSize;
|
||||||
|
|
||||||
|
public $csclassnameEnumerator($csclassname collection) {
|
||||||
|
collectionRef = collection;
|
||||||
|
ItemsCollection = new global::System.Collections.Generic.List<$typemap(cstype, T)>(collection.Items);
|
||||||
|
currentIndex = -1;
|
||||||
|
currentObject = null;
|
||||||
|
currentSize = collectionRef.Count;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Type-safe iterator Current
|
||||||
|
public $typemap(cstype, T) Current {
|
||||||
|
get {
|
||||||
|
if (currentIndex == -1)
|
||||||
|
throw new global::System.InvalidOperationException("Enumeration not started.");
|
||||||
|
if (currentIndex > currentSize - 1)
|
||||||
|
throw new global::System.InvalidOperationException("Enumeration finished.");
|
||||||
|
if (currentObject == null)
|
||||||
|
throw new global::System.InvalidOperationException("Collection modified.");
|
||||||
|
return currentObject;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Type-unsafe IEnumerator.Current
|
||||||
|
object global::System.Collections.IEnumerator.Current {
|
||||||
|
get {
|
||||||
|
return Current;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool MoveNext() {
|
||||||
|
int size = collectionRef.Count;
|
||||||
|
bool moveOkay = (currentIndex+1 < size) && (size == currentSize);
|
||||||
|
if (moveOkay) {
|
||||||
|
currentIndex++;
|
||||||
|
currentObject = ItemsCollection[currentIndex];
|
||||||
|
} else {
|
||||||
|
currentObject = null;
|
||||||
|
}
|
||||||
|
return moveOkay;
|
||||||
|
}
|
||||||
|
|
||||||
|
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:
|
||||||
|
typedef size_t size_type;
|
||||||
|
typedef ptrdiff_t difference_type;
|
||||||
|
typedef T key_type;
|
||||||
|
typedef T value_type;
|
||||||
|
typedef value_type* pointer;
|
||||||
|
typedef const value_type* const_pointer;
|
||||||
|
typedef value_type& reference;
|
||||||
|
typedef const value_type& const_reference;
|
||||||
|
|
||||||
|
set();
|
||||||
|
set(const set& other);
|
||||||
|
size_type size() const;
|
||||||
|
bool empty() const;
|
||||||
|
%rename(Clear) clear;
|
||||||
|
void clear();
|
||||||
|
%extend {
|
||||||
|
bool Add(const value_type& item) {
|
||||||
|
return $self->insert(item).second;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Contains(const value_type& item) {
|
||||||
|
return $self->count(item) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Remove(const value_type& item) {
|
||||||
|
return $self->erase(item) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const value_type& getitem(const value_type& item) throw (std::out_of_range) {
|
||||||
|
std::set<T>::iterator iter = $self->find(item);
|
||||||
|
if (iter == $self->end())
|
||||||
|
throw std::out_of_range("item not found");
|
||||||
|
|
||||||
|
return *iter;
|
||||||
|
}
|
||||||
|
|
||||||
|
// create_iterator_begin(), get_next() and destroy_iterator work together to provide a collection of items to C#
|
||||||
|
%apply void *VOID_INT_PTR { std::set<T>::iterator *create_iterator_begin }
|
||||||
|
%apply void *VOID_INT_PTR { std::set<T>::iterator *swigiterator }
|
||||||
|
|
||||||
|
std::set<T>::iterator *create_iterator_begin() {
|
||||||
|
return new std::set<T>::iterator($self->begin());
|
||||||
|
}
|
||||||
|
|
||||||
|
const key_type& get_next(std::set<T>::iterator *swigiterator) {
|
||||||
|
std::set<T>::iterator iter = *swigiterator;
|
||||||
|
(*swigiterator)++;
|
||||||
|
return *iter;
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroy_iterator(std::set<T>::iterator *swigiterator) {
|
||||||
|
delete swigiterator;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue