[D] Operator overloading support for D1 and D2.
As mentioned in the documentation, opIndexAssign and implicit casting are not supported yet. git-svn-id: https://swig.svn.sourceforge.net/svnroot/swig/trunk@12357 626c5289-ae23-0410-ae9c-e8d60b6d4f22
This commit is contained in:
parent
9a0f7ed06c
commit
38c88a0931
7 changed files with 425 additions and 75 deletions
|
|
@ -29,6 +29,7 @@
|
|||
<li><a href="#D_other_features">Other features</a>
|
||||
<ul>
|
||||
<li><a href="#D_native_pointer_support">Native pointer support</a>
|
||||
<li><a href="#D_operator_overloading">Operator overloading</a>
|
||||
<li><a href="#D_test_suite">Running the test-suite</a>
|
||||
</ul>
|
||||
<li><a href="#D_typemap_examples">D Typemap examples</a>
|
||||
|
|
@ -391,7 +392,19 @@ struct A {
|
|||
<p>To determine if a type should be considered primitive, the <tt>cprimitive</tt> attribute on its <tt>dtype</tt> attribute is used. For example, the <tt>dtype</tt> typemap for <tt>float</tt> has <tt>cprimitive="1"</tt>, so the code from the <tt>nativepointer</tt> attribute is taken into account e.g. for <tt>float **</tt> or the function pointer <tt>float (*)(float *)</tt>.</p>
|
||||
|
||||
|
||||
<H3><a name="D_test_suite"></a>20.8.2 Running the test-suite</H3>
|
||||
<H3><a name="D_operator_overloading"></a>20.8.2 Operator overloading</H3>
|
||||
|
||||
|
||||
<p>The D module comes with basic operator overloading support for both D1 and D2. There are, however, a few limitations arising from conceptual differences between C++ and D:</p>
|
||||
|
||||
<p>The first key difference is that C++ supports free functions as operators (along with argument-dependent lookup), while D requires operators to be member functions of the class they are operating on. SWIG can only automatically generate wrapping code for member function operators; if you want to use operators defined as free functions in D, you need to handle them manually.</p>
|
||||
|
||||
<p>Another set of differences between C++ and D concerns individual operators. For example, there are quite a few operators which are overloadable in C++, but not in D, for example <tt>&&</tt> and <tt>||</tt>, but also <tt>!</tt>, and prefix increment/decrement operators in <a href="http://www.digitalmars.com/d/1.0/operatoroverloading.html">D1</a> resp. their postfix pendants in <a href="http://www.digitalmars.com/d/2.0/operatoroverloading.html">D2</a>.</p>
|
||||
|
||||
<p>There are also some cases where the operators can be translated to D, but the differences in the implementation details are big enough that a rather involved scheme would be required for automatic wrapping them, which has not been implemented yet. This affects, for example, the array subscript operator, <tt>[]</tt>, in combination with assignments – while <tt>operator []</tt> in C++ simply returns a reference which is then written to, D resorts to a separate <tt>opIndexAssign</tt> method –, or implicit casting (which was introduced in D2 via <tt>alias this</tt>). Despite the lack of automatic support, manually handling these cases should be perfectly possible.</p>
|
||||
|
||||
|
||||
<H3><a name="D_test_suite"></a>20.8.3 Running the test-suite</H3>
|
||||
|
||||
|
||||
<p>As with any other language, the SWIG test-suite can be built for D using the <tt>*-d-test-suite</tt> targets of the top-level Makefile. By default, D1 is targeted, to build it with D2, use the optional <tt>D_VERSION</tt> variable, e.g. <tt>make check-d-test-suite D_VERSION=2</tt>.</p>
|
||||
|
|
@ -414,7 +427,6 @@ struct A {
|
|||
<ul>
|
||||
<li><em>Static linking:</em> Currently, the C wrapper code is compiled into a dynamic library, out of which the symbol addresses are looked up at runtime by the D part. If statically linking the different languages into one binary was supported, a tool-chain capable of performing IPO at link time could inline the wrapping code, effectively reducing the overhead for simple calls to zero.</li>
|
||||
<li><em>C array handling:</em> Many data structures in some C/C++ libraries contain array containing of a pointer to the first element and the element count. Currently, one must manually writing wrapper code to be able to access these from D. It should be possible to add a set of SWIG macros to semi-automatically generate conversion code.</li>
|
||||
<li><em>Operator overloading:</em> Currently, operator overloading is supported only to a very limited extent – many C++ operators are just ignored with a warning. The problem here is that the way D handles operator overloading differs quite a lot from the way C++ does it, both syntactically and semantically, and even more so since the advent of template-based operator overloading in D2.</li>
|
||||
</ul>
|
||||
|
||||
<p>Some generated code might also be a bit rough around the edges, particularly in the following areas:</p>
|
||||
|
|
|
|||
89
Examples/test-suite/d/operator_overload_runme.1.d
Normal file
89
Examples/test-suite/d/operator_overload_runme.1.d
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
module operator_overload_runme;
|
||||
|
||||
import operator_overload.Op;
|
||||
|
||||
void main() {
|
||||
// Invoke the C++ sanity check first.
|
||||
Op.sanity_check();
|
||||
|
||||
auto a = new Op();
|
||||
auto b = new Op(5);
|
||||
auto c = b;
|
||||
auto d = new Op(2);
|
||||
auto dd = d;
|
||||
|
||||
// test equality
|
||||
assert(a != b);
|
||||
assert(b == c);
|
||||
assert(a != d);
|
||||
assert(d == dd);
|
||||
|
||||
// test <
|
||||
assert(a < b);
|
||||
assert(a <= b);
|
||||
assert(b <= c);
|
||||
assert(b >= c);
|
||||
assert(b > d);
|
||||
assert(b >= d);
|
||||
|
||||
// test +=
|
||||
auto e = new Op(3);
|
||||
e += d;
|
||||
assert(e == b);
|
||||
e -= c;
|
||||
assert(e == a);
|
||||
e = new Op(1);
|
||||
e *= b;
|
||||
assert(e == c);
|
||||
e /= d;
|
||||
assert(e == d);
|
||||
e %= c;
|
||||
assert(e == d);
|
||||
|
||||
// test +
|
||||
auto f = new Op(1);
|
||||
auto g = new Op(1);
|
||||
assert(f + g == new Op(2));
|
||||
assert(f - g == new Op(0));
|
||||
assert(f * g == new Op(1));
|
||||
assert(f / g == new Op(1));
|
||||
assert(f % g == new Op(0));
|
||||
|
||||
// test unary operators
|
||||
assert(-a == a);
|
||||
assert(-b == new Op(-5));
|
||||
// The unary ! operator is not overloadable in D1.
|
||||
|
||||
// test []
|
||||
auto h = new Op(3);
|
||||
assert(h[0]==3);
|
||||
assert(h[1]==0);
|
||||
// Generation of opIndexAssign is not supported yet.
|
||||
|
||||
// test ()
|
||||
auto i = new Op(3);
|
||||
assert(i()==3);
|
||||
assert(i(1)==4);
|
||||
assert(i(1,2)==6);
|
||||
|
||||
// test ++ and --
|
||||
auto j = new Op(100);
|
||||
int original = j.i;
|
||||
{
|
||||
Op newOp = j++;
|
||||
int newInt = original++;
|
||||
assert(j.i == original);
|
||||
assert(newOp.i == newInt);
|
||||
}
|
||||
{
|
||||
Op newOp = j--;
|
||||
int newInt = original--;
|
||||
assert(j.i == original);
|
||||
assert(newOp.i == newInt);
|
||||
}
|
||||
// Prefix increment/decrement operators are lowered to (foo +=/-= 1) in D1,
|
||||
// but the test case does not define an integer overload for operator +=
|
||||
// respectively -=.
|
||||
|
||||
// Implicit casting is not overloadable in D1.
|
||||
}
|
||||
91
Examples/test-suite/d/operator_overload_runme.2.d
Normal file
91
Examples/test-suite/d/operator_overload_runme.2.d
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
module operator_overload_runme;
|
||||
|
||||
import operator_overload.Op;
|
||||
|
||||
void main() {
|
||||
// Invoke the C++ sanity check first.
|
||||
Op.sanity_check();
|
||||
|
||||
auto a = new Op();
|
||||
auto b = new Op(5);
|
||||
auto c = b;
|
||||
auto d = new Op(2);
|
||||
auto dd = d;
|
||||
|
||||
// test equality
|
||||
assert(a != b);
|
||||
assert(b == c);
|
||||
assert(a != d);
|
||||
assert(d == dd);
|
||||
|
||||
// test <
|
||||
assert(a < b);
|
||||
assert(a <= b);
|
||||
assert(b <= c);
|
||||
assert(b >= c);
|
||||
assert(b > d);
|
||||
assert(b >= d);
|
||||
|
||||
// test +=
|
||||
auto e = new Op(3);
|
||||
e += d;
|
||||
assert(e == b);
|
||||
e -= c;
|
||||
assert(e == a);
|
||||
e = new Op(1);
|
||||
e *= b;
|
||||
assert(e == c);
|
||||
e /= d;
|
||||
assert(e == d);
|
||||
e %= c;
|
||||
assert(e == d);
|
||||
|
||||
// test +
|
||||
auto f = new Op(1);
|
||||
auto g = new Op(1);
|
||||
assert(f + g == new Op(2));
|
||||
assert(f - g == new Op(0));
|
||||
assert(f * g == new Op(1));
|
||||
assert(f / g == new Op(1));
|
||||
assert(f % g == new Op(0));
|
||||
|
||||
// test unary operators
|
||||
assert(-a == a);
|
||||
assert(-b == new Op(-5));
|
||||
|
||||
// Unfortunaly, there is no way to override conversion to boolean for
|
||||
// classes in D, opCast!("bool") is only used for structs.
|
||||
|
||||
// test []
|
||||
auto h = new Op(3);
|
||||
assert(h[0]==3);
|
||||
assert(h[1]==0);
|
||||
// Generation of opIndexAssign is not supported yet.
|
||||
|
||||
// test ()
|
||||
auto i = new Op(3);
|
||||
assert(i()==3);
|
||||
assert(i(1)==4);
|
||||
assert(i(1,2)==6);
|
||||
|
||||
// test ++ and --
|
||||
auto j = new Op(100);
|
||||
int original = j.i;
|
||||
// The prefix increment/decrement operators are not directly overloadable in
|
||||
// D2, and because the proxy classes are reference types, the lowering
|
||||
// yields the same value as the postfix operators.
|
||||
{
|
||||
Op newOp = ++j;
|
||||
int newInt = ++original;
|
||||
assert(j.i == original);
|
||||
assert(newOp.i == newInt);
|
||||
}
|
||||
{
|
||||
Op newOp = --j;
|
||||
int newInt = --original;
|
||||
assert(j.i == original);
|
||||
assert(newOp.i == newInt);
|
||||
}
|
||||
|
||||
// Implicit casting via alias this is not supported yet.
|
||||
}
|
||||
|
|
@ -79,6 +79,12 @@ see bottom for a set of possible tests
|
|||
%}
|
||||
#endif
|
||||
|
||||
#ifdef SWIGD
|
||||
// Due to the way operator overloading is implemented in D1 and D2, the prefix
|
||||
// increment/decrement operators (D1) resp. the postfix ones (D2) are ignored.
|
||||
%warnfilter(SWIGWARN_IGNORE_OPERATOR_PLUSPLUS, SWIGWARN_IGNORE_OPERATOR_MINUSMINUS);
|
||||
#endif
|
||||
|
||||
%rename(IntCast) operator int();
|
||||
%rename(DoubleCast) operator double();
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
%module operator_overload_break
|
||||
|
||||
#if defined(SWIGPYTHON)
|
||||
#if defined(SWIGPYTHON) || defined(SWIGD)
|
||||
%warnfilter(SWIGWARN_IGNORE_OPERATOR_PLUSPLUS);
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
%define SWIGD_CLASS_BODIES(OP_EQUALS_RETURN)
|
||||
|
||||
// Unfortunately, the »package« visibility attribute does not work in D when the
|
||||
// module in question is in the root package (happens if no -package is specified
|
||||
// at the SWIG command line), so we are stuck with public visibility for
|
||||
|
|
@ -72,18 +72,14 @@ public this(void* cObject, bool ownCObject) {
|
|||
swigCMemOwn = ownCObject;
|
||||
}
|
||||
|
||||
public override OP_EQUALS_RETURN opEquals(Object rhs) {
|
||||
if (auto other = cast($dclassname)rhs) {
|
||||
return (swigCPtr == other.swigCPtr);
|
||||
}
|
||||
return super.opEquals(rhs);
|
||||
}
|
||||
|
||||
public static void* swigGetCPtr($dclassname obj) {
|
||||
return (obj is null) ? null : obj.swigCPtr;
|
||||
}
|
||||
|
||||
mixin $imdmodule.SwigOperatorDefinitions;
|
||||
%}
|
||||
|
||||
|
||||
%typemap(dbody_derived) SWIGTYPE %{
|
||||
private void* swigCPtr;
|
||||
|
||||
|
|
@ -92,16 +88,11 @@ public this(void* cObject, bool ownCObject) {
|
|||
swigCPtr = cObject;
|
||||
}
|
||||
|
||||
public override OP_EQUALS_RETURN opEquals(Object rhs) {
|
||||
if (auto other = cast($dclassname)rhs) {
|
||||
return (swigCPtr == other.swigCPtr);
|
||||
}
|
||||
return super.opEquals(rhs);
|
||||
}
|
||||
|
||||
public static void* swigGetCPtr($dclassname obj) {
|
||||
return (obj is null) ? null : obj.swigCPtr;
|
||||
}
|
||||
|
||||
mixin $imdmodule.SwigOperatorDefinitions;
|
||||
%}
|
||||
|
||||
|
||||
|
|
@ -120,16 +111,11 @@ protected this() {
|
|||
swigCPtr = null;
|
||||
}
|
||||
|
||||
public override OP_EQUALS_RETURN opEquals(Object rhs) {
|
||||
if (auto other = cast($dclassname)rhs) {
|
||||
return (swigCPtr == other.swigCPtr);
|
||||
}
|
||||
return super.opEquals(rhs);
|
||||
}
|
||||
|
||||
public static void* swigGetCPtr($dclassname obj) {
|
||||
return (obj is null) ? null : obj.swigCPtr;
|
||||
}
|
||||
|
||||
mixin $imdmodule.SwigOperatorDefinitions;
|
||||
%}
|
||||
|
||||
|
||||
|
|
@ -138,35 +124,19 @@ public static void* swigGetCPtr($dclassname obj) {
|
|||
*/
|
||||
|
||||
%typemap(dbody) SWIGTYPE (CLASS::*) %{
|
||||
private char* m_swigCMemberPtr;
|
||||
private char* swigCPtr;
|
||||
|
||||
public this(char* cMemberPtr, bool futureUse) {
|
||||
m_swigCMemberPtr = cMemberPtr;
|
||||
swigCPtr = cMemberPtr;
|
||||
}
|
||||
|
||||
protected this() {
|
||||
m_swigCMemberPtr = null;
|
||||
swigCPtr = null;
|
||||
}
|
||||
|
||||
public override OP_EQUALS_RETURN opEquals(Object rhs) {
|
||||
if (auto other = cast($dclassname)rhs) {
|
||||
return (m_swigCMemberPtr == other.m_swigCMemberPtr);
|
||||
}
|
||||
return super.opEquals(rhs);
|
||||
}
|
||||
|
||||
|
||||
package static char* swigGetCMemberPtr($dclassname obj) {
|
||||
return (obj is null) ? null : obj.m_swigCMemberPtr;
|
||||
return (obj is null) ? null : obj.swigCPtr;
|
||||
}
|
||||
|
||||
mixin $imdmodule.SwigOperatorDefinitions;
|
||||
%}
|
||||
%enddef
|
||||
|
||||
|
||||
#if SWIG_D_VERSION == 1
|
||||
SWIGD_CLASS_BODIES(int)
|
||||
#else
|
||||
SWIGD_CLASS_BODIES(bool)
|
||||
#endif
|
||||
|
||||
#undef SWIGD_CLASS_BODIES
|
||||
|
|
|
|||
|
|
@ -4,15 +4,36 @@
|
|||
* Mapping of C++ operator overloading methods to D.
|
||||
* ----------------------------------------------------------------------------- */
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
#if (SWIG_D_VERSION == 1)
|
||||
|
||||
%rename(opAdd) *::operator+;
|
||||
%pragma(d) imdmodulecode=%{
|
||||
template SwigOperatorDefinitions() {
|
||||
public override int opEquals(Object o) {
|
||||
if (auto rhs = cast(typeof(this))o) {
|
||||
if (swigCPtr == rhs.swigCPtr) return 1;
|
||||
static if (is(typeof(swigOpEquals(rhs)))) {
|
||||
return swigOpEquals(rhs) ? 1 : 0;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return super.opEquals(o);
|
||||
}
|
||||
%}
|
||||
// opEquals is emitted in pure C mode as well to define two proxy classes
|
||||
// pointing to the same struct as equal.
|
||||
|
||||
#ifdef __cplusplus
|
||||
%rename(opPos) *::operator+();
|
||||
%rename(opPos) *::operator+() const;
|
||||
%rename(opNeg) *::operator-();
|
||||
%rename(opNeg) *::operator-() const;
|
||||
%rename(opCom) *::operator~();
|
||||
%rename(opCom) *::operator~() const;
|
||||
|
||||
%rename(opAdd) *::operator+;
|
||||
%rename(opAddAssign) *::operator+=;
|
||||
%rename(opSub) *::operator-;
|
||||
%rename(opNeg) *::operator-();
|
||||
%rename(opSubAssign) *::operator-=;
|
||||
%rename(opMul) *::operator*;
|
||||
%rename(opMulAssign) *::operator*=;
|
||||
|
|
@ -20,8 +41,6 @@
|
|||
%rename(opDivAssign) *::operator/=;
|
||||
%rename(opMod) *::operator%;
|
||||
%rename(opModAssign) *::operator%=;
|
||||
|
||||
%rename(opCom) *::operator~();
|
||||
%rename(opAnd) *::operator&;
|
||||
%rename(opAndAssign) *::operator&=;
|
||||
%rename(opOr) *::operator|;
|
||||
|
|
@ -34,44 +53,207 @@
|
|||
%rename(opShrAssign) *::operator>>=;
|
||||
|
||||
%rename(opIndex) *::operator[](unsigned) const;
|
||||
%rename(opIndexAssign) *::operator[](unsigned);
|
||||
%rename(opCall) *::operator();
|
||||
// opIndexAssign is not currently generated, it needs more extensive support
|
||||
// mechanisms.
|
||||
|
||||
%rename(opCall) *::operator();
|
||||
|
||||
// !a is not overrideable in D1.
|
||||
%ignoreoperator(LNOT) operator!;
|
||||
|
||||
// a != b is rewritten as !a.opEquals(b) in D.
|
||||
// For now, just ignore both of them, since there would be quite a bit of magic
|
||||
// needed to correctly generate a wrapper method for non-primitives types (there is
|
||||
// only one opEquals overload with an Object parameter in D).
|
||||
%ignoreoperator(EQ) operator==;
|
||||
%ignoreoperator(NOTEQUAL) operator!=;
|
||||
|
||||
// opCmp is used in D.
|
||||
%ignoreoperator(LT) operator<;
|
||||
%ignoreoperator(LTEQUAL) operator<=;
|
||||
%ignoreoperator(GT) operator>;
|
||||
%ignoreoperator(GTEQUAL) operator>=;
|
||||
%rename(swigOpEquals) *::operator==;
|
||||
%rename(swigOpLt) *::operator<;
|
||||
%rename(swigOpLtEquals) *::operator<=;
|
||||
%rename(swigOpGt) *::operator>;
|
||||
%rename(swigOpGtEquals) *::operator>=;
|
||||
|
||||
// a != b is rewritten as !a.opEquals(b) in D.
|
||||
%ignoreoperator(NOTEQUAL) operator!=;
|
||||
|
||||
// The logic operators are not overrideable in D.
|
||||
%ignoreoperator(LAND) operator&&;
|
||||
%ignoreoperator(LOR) operator||;
|
||||
|
||||
// ++/--a is rewritten as a +/-= 1 in D.
|
||||
%ignoreoperator(PLUSPLUS) operator++();
|
||||
%ignoreoperator(MINUSMINUS) operator--();
|
||||
%ignoreoperator(PLUSPLUS) operator++(int);
|
||||
%ignoreoperator(MINUSMINUS) operator--(int);
|
||||
// ++/--a is rewritten as a +/-= 1 in D1,so ignore the prefix operators.
|
||||
%ignoreoperator(PLUSPLUS) *::operator++();
|
||||
%ignoreoperator(MINUSMINUS) *::operator--();
|
||||
%rename(swigOpInc) *::operator++(int);
|
||||
%rename(swigOpDec) *::operator--(int);
|
||||
|
||||
// The C++ assignment operator does not translate well to D where custom types
|
||||
// have reference semantics.
|
||||
// The C++ assignment operator does not translate well to D where the proxy
|
||||
// classes have reference semantics.
|
||||
%ignoreoperator(EQ) operator=;
|
||||
|
||||
%pragma(d) imdmodulecode=%{
|
||||
public override int opCmp(Object o) {
|
||||
static if (is(typeof(swigOpLt(typeof(this).init) &&
|
||||
swigOpEquals(typeof(this).init)))) {
|
||||
if (auto rhs = cast(typeof(this))o) {
|
||||
if (swigOpLt(rhs)) {
|
||||
return -1;
|
||||
} else if (swigOpEquals(rhs)) {
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return super.opCmp(o);
|
||||
}
|
||||
|
||||
public typeof(this) opPostInc(T = int)(T unused = 0) {
|
||||
static assert(
|
||||
is(typeof(swigOpInc(int.init))),
|
||||
"opPostInc called on " ~ typeof(this).stringof ~ ", but no postfix " ~
|
||||
"increment operator exists in the corresponding C++ class."
|
||||
);
|
||||
return swigOpInc(int.init);
|
||||
}
|
||||
|
||||
public typeof(this) opPostDec(T = int)(T unused = 0) {
|
||||
static assert(
|
||||
is(typeof(swigOpDec(int.init))),
|
||||
"opPostInc called on " ~ typeof(this).stringof ~ ", but no postfix " ~
|
||||
"decrement operator exists in the corresponding C++ class."
|
||||
);
|
||||
return swigOpDec(int.init);
|
||||
}
|
||||
%}
|
||||
#endif
|
||||
|
||||
%pragma(d) imdmodulecode=%{
|
||||
}
|
||||
%}
|
||||
|
||||
#else
|
||||
%pragma(d) imdmodulecode=%{
|
||||
mixin template SwigOperatorDefinitions() {
|
||||
public override bool opEquals(Object o) {
|
||||
if (auto rhs = cast(typeof(this))o) {
|
||||
if (swigCPtr == rhs.swigCPtr) return true;
|
||||
static if (is(typeof(swigOpEquals(rhs)))) {
|
||||
return swigOpEquals(rhs);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return super.opEquals(o);
|
||||
}
|
||||
%}
|
||||
// opEquals is emitted in pure C mode as well to define two proxy classes
|
||||
// pointing to the same struct as equal.
|
||||
|
||||
// Operator overloading works completely different in D2, proper support will
|
||||
// probably need fairly extensive code generation support.
|
||||
#ifdef __cplusplus
|
||||
%rename(swigOpPos) *::operator+();
|
||||
%rename(swigOpPos) *::operator+() const;
|
||||
%rename(swigOpNeg) *::operator-();
|
||||
%rename(swigOpNeg) *::operator-() const;
|
||||
%rename(swigOpCom) *::operator~();
|
||||
%rename(swigOpCom) *::operator~() const;
|
||||
%rename(swigOpInc) *::operator++();
|
||||
%rename(swigOpDec) *::operator--();
|
||||
%ignoreoperator(PLUSPLUS) *::operator++(int);
|
||||
%ignoreoperator(MINUSMINUS) *::operator--(int);
|
||||
// The postfix increment/decrement operators are ignored because they are
|
||||
// rewritten to (auto t = e, ++e, t) in D2. The unary * operator (used for
|
||||
// pointer dereferencing in C/C++) isn't mapped to opUnary("*") by default,
|
||||
// despite this would be possible in D2 – the difference in member access
|
||||
// semantics would only lead to confusion in most cases.
|
||||
|
||||
%rename(swigOpAdd) *::operator+;
|
||||
%rename(swigOpSub) *::operator-;
|
||||
%rename(swigOpMul) *::operator*;
|
||||
%rename(swigOpDiv) *::operator/;
|
||||
%rename(swigOpMod) *::operator%;
|
||||
%rename(swigOpAnd) *::operator&;
|
||||
%rename(swigOpOr) *::operator|;
|
||||
%rename(swigOpXor) *::operator^;
|
||||
%rename(swigOpShl) *::operator<<;
|
||||
%rename(swigOpShr) *::operator>>;
|
||||
|
||||
%rename(swigOpAddAssign) *::operator+=;
|
||||
%rename(swigOpSubAssign) *::operator-=;
|
||||
%rename(swigOpMulAssign) *::operator*=;
|
||||
%rename(swigOpDivAssign) *::operator/=;
|
||||
%rename(swigOpModAssign) *::operator%=;
|
||||
%rename(swigOpAndAssign) *::operator&=;
|
||||
%rename(swigOpOrAssign) *::operator|=;
|
||||
%rename(swigOpXorAssign) *::operator^=;
|
||||
%rename(swigOpShlAssign) *::operator<<=;
|
||||
%rename(swigOpShrAssign) *::operator>>=;
|
||||
|
||||
%rename(opIndex) *::operator[];
|
||||
// opIndexAssign is not currently generated, it needs more extensive support
|
||||
// mechanisms.
|
||||
|
||||
%rename(opCall) *::operator();
|
||||
|
||||
%rename(swigOpEquals) *::operator==;
|
||||
%rename(swigOpLt) *::operator<;
|
||||
%rename(swigOpLtEquals) *::operator<=;
|
||||
%rename(swigOpGt) *::operator>;
|
||||
%rename(swigOpGtEquals) *::operator>=;
|
||||
|
||||
// a != b is rewritten as !a.opEquals(b) in D.
|
||||
%ignoreoperator(NOTEQUAL) operator!=;
|
||||
|
||||
// The logic operators are not overrideable in D.
|
||||
%ignoreoperator(LAND) operator&&;
|
||||
%ignoreoperator(LOR) operator||;
|
||||
|
||||
// The C++ assignment operator does not translate well to D where the proxy
|
||||
// classes have reference semantics.
|
||||
%ignoreoperator(EQ) operator=;
|
||||
|
||||
%pragma(d) imdmodulecode=%{
|
||||
public override int opCmp(Object o) {
|
||||
static if (__traits(compiles, swigOpLt(typeof(this).init) &&
|
||||
swigOpEquals(typeof(this).init))) {
|
||||
if (auto rhs = cast(typeof(this))o) {
|
||||
if (swigOpLt(rhs)) {
|
||||
return -1;
|
||||
} else if (swigOpEquals(rhs)) {
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return super.opCmp(o);
|
||||
}
|
||||
|
||||
private template swigOpBinary(string operator, string name) {
|
||||
enum swigOpBinary = `public void opOpAssign(string op, T)(T rhs) if (op == "` ~ operator ~
|
||||
`" && __traits(compiles, swigOp` ~ name ~ `Assign(rhs))) { swigOp` ~ name ~ `Assign(rhs);}` ~
|
||||
`public auto opBinary(string op, T)(T rhs) if (op == "` ~ operator ~
|
||||
`" && __traits(compiles, swigOp` ~ name ~ `(rhs))) { return swigOp` ~ name ~ `(rhs);}`;
|
||||
}
|
||||
mixin(swigOpBinary!("+", "Add"));
|
||||
mixin(swigOpBinary!("-", "Sub"));
|
||||
mixin(swigOpBinary!("*", "Mul"));
|
||||
mixin(swigOpBinary!("/", "Div"));
|
||||
mixin(swigOpBinary!("%", "Mod"));
|
||||
mixin(swigOpBinary!("&", "And"));
|
||||
mixin(swigOpBinary!("|", "Or"));
|
||||
mixin(swigOpBinary!("^", "Xor"));
|
||||
mixin(swigOpBinary!("<<", "Shl"));
|
||||
mixin(swigOpBinary!(">>", "Shr"));
|
||||
|
||||
private template swigOpUnary(string operator, string name) {
|
||||
enum swigOpUnary = `public auto opUnary(string op)() if (op == "` ~ operator ~
|
||||
`" && __traits(compiles, swigOp` ~ name ~ `())) { return swigOp` ~ name ~ `();}`;
|
||||
}
|
||||
mixin(swigOpUnary!("+", "Pos"));
|
||||
mixin(swigOpUnary!("-", "Neg"));
|
||||
mixin(swigOpUnary!("~", "Com"));
|
||||
mixin(swigOpUnary!("++", "Inc"));
|
||||
mixin(swigOpUnary!("--", "Dec"));
|
||||
%}
|
||||
#endif
|
||||
|
||||
%pragma(d) imdmodulecode=%{
|
||||
}
|
||||
%}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue