mirror of https://github.com/swig/swig
Merge branch 'bda_add_unordered_map'
* bda_add_unordered_map: Add runtime tests for C# std::unordered_map csharp: Added std_unordered_map.i Conflicts: CHANGES.current
This commit is contained in:
commit
432daea78c
|
@ -7,6 +7,10 @@ the issue number to the end of the URL: https://github.com/swig/swig/issues/
|
|||
Version 4.2.0 (in progress)
|
||||
===========================
|
||||
|
||||
2023-11-08: emmenlau
|
||||
#2480 [C#] Add std_unordered_map.i for wrapping std::std_unordered_map, implementing
|
||||
C# System.Collections.Generic.IDictionary<>.
|
||||
|
||||
2023-11-06: wsfulton
|
||||
[D, Java] Add the dbegin option to the %module directive for generating code at
|
||||
the beginning of every D file. Similarly javabegin for Java. This enables one
|
||||
|
|
|
@ -43,6 +43,7 @@ CPP11_TEST_CASES = \
|
|||
cpp11_shared_ptr_overload \
|
||||
cpp11_shared_ptr_template_upcast \
|
||||
cpp11_shared_ptr_upcast \
|
||||
cpp11_std_unordered_map \
|
||||
cpp11_strongly_typed_enumerations_simple \
|
||||
|
||||
include $(srcdir)/../common.mk
|
||||
|
|
|
@ -0,0 +1,126 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using cpp11_std_unordered_mapNamespace;
|
||||
|
||||
public class runme
|
||||
{
|
||||
static void checkThat(bool mustBeTrue)
|
||||
{
|
||||
if (!mustBeTrue)
|
||||
{
|
||||
throw new Exception("checkThat failed");
|
||||
}
|
||||
}
|
||||
|
||||
static void Main()
|
||||
{
|
||||
global::System.Collections.Generic.IDictionary<string, int> sim = new UnorderedMapStringInt();
|
||||
global::System.Collections.Generic.IDictionary<int, int> iim = new UnorderedMapIntInt();
|
||||
|
||||
checkThat(((UnorderedMapStringInt)sim).empty());
|
||||
checkThat(((UnorderedMapIntInt)iim).empty());
|
||||
|
||||
checkThat(sim.Count == 0);
|
||||
checkThat(iim.Count == 0);
|
||||
|
||||
int myInt;
|
||||
checkThat(!sim.TryGetValue("key", out myInt));
|
||||
checkThat(!iim.TryGetValue(1, out myInt));
|
||||
|
||||
checkThat(!sim.ContainsKey("key"));
|
||||
checkThat(!iim.ContainsKey(1));
|
||||
|
||||
sim.Add("key", 2);
|
||||
iim.Add(1, 2);
|
||||
|
||||
checkThat(sim.Count == 1);
|
||||
checkThat(iim.Count == 1);
|
||||
|
||||
checkThat(sim["key"] == 2);
|
||||
checkThat(iim[1] == 2);
|
||||
|
||||
checkThat(sim.Remove("key"));
|
||||
checkThat(iim.Remove(1));
|
||||
|
||||
checkThat(sim.Count == 0);
|
||||
checkThat(iim.Count == 0);
|
||||
|
||||
checkThat(!sim.TryGetValue("key", out myInt));
|
||||
checkThat(!iim.TryGetValue(1, out myInt));
|
||||
|
||||
checkThat(!sim.Remove("key"));
|
||||
checkThat(!iim.Remove(1));
|
||||
|
||||
sim["key"] = 2;
|
||||
iim[1] = 2;
|
||||
|
||||
sim.Clear();
|
||||
iim.Clear();
|
||||
checkThat(sim.Count == 0);
|
||||
checkThat(iim.Count == 0);
|
||||
|
||||
sim["key1"] = 1;
|
||||
iim[1] = 1;
|
||||
sim["key2"] = 2;
|
||||
iim[2] = 2;
|
||||
|
||||
checkThat(sim.Count == 2);
|
||||
checkThat(iim.Count == 2);
|
||||
checkThat(sim["key1"] == 1);
|
||||
checkThat(iim[1] == 1);
|
||||
checkThat(sim["key2"] == 2);
|
||||
checkThat(iim[2] == 2);
|
||||
|
||||
sim["key1"] = 3;
|
||||
iim[1] = 3;
|
||||
|
||||
checkThat(sim.Count == 2);
|
||||
checkThat(iim.Count == 2);
|
||||
checkThat(sim["key1"] == 3);
|
||||
checkThat(iim[1] == 3);
|
||||
|
||||
{
|
||||
int collectionSize = 20;
|
||||
UnorderedMapStringInt simap = new UnorderedMapStringInt();
|
||||
for (int i = 0; i < collectionSize; i++)
|
||||
{
|
||||
int val = i * 18;
|
||||
simap.Add(i.ToString(), val);
|
||||
}
|
||||
|
||||
// Keys and Values test
|
||||
IList<string> keys = new List<string>(simap.Keys);
|
||||
IList<int> values = new List<int>(simap.Values);
|
||||
Dictionary<string, int> check = new Dictionary<string, int>();
|
||||
if (keys.Count != collectionSize)
|
||||
throw new Exception("Keys count test failed");
|
||||
|
||||
if (values.Count != collectionSize)
|
||||
throw new Exception("Values count test failed");
|
||||
|
||||
for (int i = 0; i < keys.Count; i++)
|
||||
{
|
||||
if (simap[keys[i]] != values[i])
|
||||
throw new Exception("Keys and values test failed for index " + i);
|
||||
check.Add(keys[i], values[i]);
|
||||
}
|
||||
|
||||
for (int i = 0; i < collectionSize; i++)
|
||||
{
|
||||
if (!check.ContainsKey(i.ToString()))
|
||||
throw new Exception("Keys and Values ContainsKey test " + i + " failed");
|
||||
}
|
||||
|
||||
// CopyTo() test
|
||||
{
|
||||
KeyValuePair<string, int>[] outputarray = new KeyValuePair<string, int>[collectionSize];
|
||||
simap.CopyTo(outputarray);
|
||||
foreach (KeyValuePair<string, int> val in outputarray)
|
||||
{
|
||||
if (simap[val.Key] != val.Value)
|
||||
throw new Exception("CopyTo (1) test failed, index:" + val.Key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,299 @@
|
|||
/* -----------------------------------------------------------------------------
|
||||
* std_unordered_map.i
|
||||
*
|
||||
* SWIG typemaps for std::unordered_map< K, T, H >
|
||||
*
|
||||
* The C# wrapper is made to look and feel like a C# System.Collections.Generic.IDictionary<>.
|
||||
*
|
||||
* Using this wrapper is fairly simple. For example, to create an unordered_map from integers to doubles use:
|
||||
*
|
||||
* %include <std_unordered_map.i>
|
||||
* %template(MapIntDouble) std::unordered_map<int, double>
|
||||
*
|
||||
* Notes:
|
||||
* 1) IEnumerable<> is implemented in the proxy class which is useful for using LINQ with
|
||||
* C++ std::unordered_map wrappers.
|
||||
*
|
||||
* Warning: heavy macro usage in this file. Use swig -E to get a sane view on the real file contents!
|
||||
* ----------------------------------------------------------------------------- */
|
||||
|
||||
%{
|
||||
#include <unordered_map>
|
||||
#include <algorithm>
|
||||
#include <stdexcept>
|
||||
%}
|
||||
|
||||
/* K is the C++ key type, T is the C++ value type */
|
||||
%define SWIG_STD_UNORDERED_MAP_INTERNAL(K, T, H)
|
||||
|
||||
%typemap(csinterfaces) std::unordered_map< K, T, H > "global::System.IDisposable \n , global::System.Collections.Generic.IDictionary<$typemap(cstype, K), $typemap(cstype, T)>\n"
|
||||
%proxycode %{
|
||||
|
||||
public $typemap(cstype, T) this[$typemap(cstype, K) key] {
|
||||
get {
|
||||
return getitem(key);
|
||||
}
|
||||
|
||||
set {
|
||||
setitem(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
public bool TryGetValue($typemap(cstype, K) key, out $typemap(cstype, T) value) {
|
||||
if (this.ContainsKey(key)) {
|
||||
value = this[key];
|
||||
return true;
|
||||
}
|
||||
value = default($typemap(cstype, T));
|
||||
return false;
|
||||
}
|
||||
|
||||
public int Count {
|
||||
get {
|
||||
return (int)size();
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsReadOnly {
|
||||
get {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public global::System.Collections.Generic.ICollection<$typemap(cstype, K)> Keys {
|
||||
get {
|
||||
global::System.Collections.Generic.ICollection<$typemap(cstype, K)> keys = new global::System.Collections.Generic.List<$typemap(cstype, K)>();
|
||||
int size = this.Count;
|
||||
if (size > 0) {
|
||||
global::System.IntPtr iter = create_iterator_begin();
|
||||
for (int i = 0; i < size; i++) {
|
||||
keys.Add(get_next_key(iter));
|
||||
}
|
||||
destroy_iterator(iter);
|
||||
}
|
||||
return keys;
|
||||
}
|
||||
}
|
||||
|
||||
public global::System.Collections.Generic.ICollection<$typemap(cstype, T)> Values {
|
||||
get {
|
||||
global::System.Collections.Generic.ICollection<$typemap(cstype, T)> vals = new global::System.Collections.Generic.List<$typemap(cstype, T)>();
|
||||
foreach (global::System.Collections.Generic.KeyValuePair<$typemap(cstype, K), $typemap(cstype, T)> pair in this) {
|
||||
vals.Add(pair.Value);
|
||||
}
|
||||
return vals;
|
||||
}
|
||||
}
|
||||
|
||||
public void Add(global::System.Collections.Generic.KeyValuePair<$typemap(cstype, K), $typemap(cstype, T)> item) {
|
||||
Add(item.Key, item.Value);
|
||||
}
|
||||
|
||||
public bool Remove(global::System.Collections.Generic.KeyValuePair<$typemap(cstype, K), $typemap(cstype, T)> item) {
|
||||
if (Contains(item)) {
|
||||
return Remove(item.Key);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public bool Contains(global::System.Collections.Generic.KeyValuePair<$typemap(cstype, K), $typemap(cstype, T)> item) {
|
||||
if (this[item.Key] == item.Value) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void CopyTo(global::System.Collections.Generic.KeyValuePair<$typemap(cstype, K), $typemap(cstype, T)>[] array) {
|
||||
CopyTo(array, 0);
|
||||
}
|
||||
|
||||
public void CopyTo(global::System.Collections.Generic.KeyValuePair<$typemap(cstype, K), $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.");
|
||||
|
||||
global::System.Collections.Generic.IList<$typemap(cstype, K)> keyList = new global::System.Collections.Generic.List<$typemap(cstype, K)>(this.Keys);
|
||||
for (int i = 0; i < keyList.Count; i++) {
|
||||
$typemap(cstype, K) currentKey = keyList[i];
|
||||
array.SetValue(new global::System.Collections.Generic.KeyValuePair<$typemap(cstype, K), $typemap(cstype, T)>(currentKey, this[currentKey]), arrayIndex+i);
|
||||
}
|
||||
}
|
||||
|
||||
global::System.Collections.Generic.IEnumerator<global::System.Collections.Generic.KeyValuePair<$typemap(cstype, K), $typemap(cstype, T)>> global::System.Collections.Generic.IEnumerable<global::System.Collections.Generic.KeyValuePair<$typemap(cstype, K), $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<global::System.Collections.Generic.KeyValuePair<$typemap(cstype, K), $typemap(cstype, T)>>
|
||||
{
|
||||
private $csclassname collectionRef;
|
||||
private global::System.Collections.Generic.IList<$typemap(cstype, K)> keyCollection;
|
||||
private int currentIndex;
|
||||
private object currentObject;
|
||||
private int currentSize;
|
||||
|
||||
public $csclassnameEnumerator($csclassname collection) {
|
||||
collectionRef = collection;
|
||||
keyCollection = new global::System.Collections.Generic.List<$typemap(cstype, K)>(collection.Keys);
|
||||
currentIndex = -1;
|
||||
currentObject = null;
|
||||
currentSize = collectionRef.Count;
|
||||
}
|
||||
|
||||
// Type-safe iterator Current
|
||||
public global::System.Collections.Generic.KeyValuePair<$typemap(cstype, K), $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 (global::System.Collections.Generic.KeyValuePair<$typemap(cstype, K), $typemap(cstype, T)>)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++;
|
||||
$typemap(cstype, K) currentKey = keyCollection[currentIndex];
|
||||
currentObject = new global::System.Collections.Generic.KeyValuePair<$typemap(cstype, K), $typemap(cstype, T)>(currentKey, collectionRef[currentKey]);
|
||||
} 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 K key_type;
|
||||
typedef T mapped_type;
|
||||
typedef std::pair< const K, T > value_type;
|
||||
typedef value_type* pointer;
|
||||
typedef const value_type* const_pointer;
|
||||
typedef value_type& reference;
|
||||
typedef const value_type& const_reference;
|
||||
|
||||
unordered_map();
|
||||
unordered_map(const unordered_map& other);
|
||||
size_type size() const;
|
||||
bool empty() const;
|
||||
%rename(Clear) clear;
|
||||
void clear();
|
||||
%extend {
|
||||
const mapped_type& getitem(const key_type& key) throw (std::out_of_range) {
|
||||
std::unordered_map< K, T, H >::iterator iter = $self->find(key);
|
||||
if (iter != $self->end())
|
||||
return iter->second;
|
||||
else
|
||||
throw std::out_of_range("key not found");
|
||||
}
|
||||
|
||||
void setitem(const key_type& key, const mapped_type& x) {
|
||||
(*$self)[key] = x;
|
||||
}
|
||||
|
||||
bool ContainsKey(const key_type& key) {
|
||||
std::unordered_map< K, T, H >::iterator iter = $self->find(key);
|
||||
return iter != $self->end();
|
||||
}
|
||||
|
||||
void Add(const key_type& key, const mapped_type& value) throw (std::out_of_range) {
|
||||
std::unordered_map< K, T, H >::iterator iter = $self->find(key);
|
||||
if (iter != $self->end())
|
||||
throw std::out_of_range("key already exists");
|
||||
$self->insert(std::pair< K, T >(key, value));
|
||||
}
|
||||
|
||||
bool Remove(const key_type& key) {
|
||||
std::unordered_map< K, T, H >::iterator iter = $self->find(key);
|
||||
if (iter != $self->end()) {
|
||||
$self->erase(iter);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// create_iterator_begin(), get_next_key() and destroy_iterator work together to provide a collection of keys to C#
|
||||
%apply void *VOID_INT_PTR { std::unordered_map< K, T, H >::iterator *create_iterator_begin }
|
||||
%apply void *VOID_INT_PTR { std::unordered_map< K, T, H >::iterator *swigiterator }
|
||||
|
||||
std::unordered_map< K, T, H >::iterator *create_iterator_begin() {
|
||||
return new std::unordered_map< K, T, H >::iterator($self->begin());
|
||||
}
|
||||
|
||||
const key_type& get_next_key(std::unordered_map< K, T, H >::iterator *swigiterator) {
|
||||
(void)self;
|
||||
std::unordered_map< K, T, H >::iterator iter = *swigiterator;
|
||||
(*swigiterator)++;
|
||||
return (*iter).first;
|
||||
}
|
||||
|
||||
void destroy_iterator(std::unordered_map< K, T, H >::iterator *swigiterator) {
|
||||
(void)self;
|
||||
delete swigiterator;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
%enddef
|
||||
|
||||
%csmethodmodifiers std::unordered_map::size "private"
|
||||
%csmethodmodifiers std::unordered_map::getitem "private"
|
||||
%csmethodmodifiers std::unordered_map::setitem "private"
|
||||
%csmethodmodifiers std::unordered_map::create_iterator_begin "private"
|
||||
%csmethodmodifiers std::unordered_map::get_next_key "private"
|
||||
%csmethodmodifiers std::unordered_map::destroy_iterator "private"
|
||||
|
||||
// Default implementation
|
||||
namespace std {
|
||||
template<class K, class T, class H = std::hash<K> > class unordered_map {
|
||||
SWIG_STD_UNORDERED_MAP_INTERNAL(K, T, H)
|
||||
};
|
||||
}
|
Loading…
Reference in New Issue