Commit f7f48c4b authored by Robert Bradshaw's avatar Robert Bradshaw

Merge branch 'cpp-operator'

parents 1733c4ef 4d6f38c0
......@@ -11053,9 +11053,8 @@ class CBinopNode(BinopNode):
cpp_type = None
if type1.is_cpp_class or type1.is_ptr:
cpp_type = type1.find_cpp_operation_type(self.operator, type2)
# FIXME: handle the reversed case?
#if cpp_type is None and (type2.is_cpp_class or type2.is_ptr):
# cpp_type = type2.find_cpp_operation_type(self.operator, type1)
if cpp_type is None and (type2.is_cpp_class or type2.is_ptr):
cpp_type = type2.find_cpp_operation_type(self.operator, type1)
# FIXME: do we need to handle other cases here?
return cpp_type
......
......@@ -907,10 +907,28 @@ class Scope(object):
if res is not None:
return res
function = self.lookup("operator%s" % operator)
if function is None:
function_alternatives = []
if function is not None:
function_alternatives = function.all_alternatives()
# look-up nonmember methods listed within a class
method_alternatives = []
if len(operands)==2: # binary operators only
for n in range(2):
if operands[n].type.is_cpp_class:
obj_type = operands[n].type
method = obj_type.scope.lookup("operator%s" % operator)
if method is not None:
method_alternatives += method.all_alternatives()
if (not method_alternatives) and (not function_alternatives):
return None
# select the unique alternatives
all_alternatives = list(set(method_alternatives + function_alternatives))
return PyrexTypes.best_match([arg.type for arg in operands],
function.all_alternatives())
all_alternatives)
def lookup_operator_for_types(self, pos, operator, types):
from .Nodes import Node
......
......@@ -321,6 +321,10 @@ Cython uses C++ naming for overloading operators::
Foo operator-(Foo)
int operator*(Foo)
int operator/(int)
int operator*(int, Foo) # allows 1*Foo()
# nonmember operators can also be specified outside the class
double operator/(double, Foo)
cdef Foo foo = new Foo()
......@@ -330,6 +334,13 @@ Cython uses C++ naming for overloading operators::
x = foo * foo2
x = foo / 1
x = foo[0] * foo2
x = foo[0] / 1
x = 1*foo[0]
cdef double y
y = 2.0/foo[0]
Note that if one has *pointers* to C++ objects, dereferencing must be done
to avoid doing pointer arithmetic rather than arithmetic on the objects
themselves::
......
......@@ -27,18 +27,29 @@ cdef extern from "cpp_operators_helper.h" nogil:
const_char* operator--(int)
const_char* operator+(int)
const_char* operator+(int,const TestOps&)
const_char* operator-(int)
const_char* operator-(int,const TestOps&)
const_char* operator*(int)
# deliberately omitted operator* to test case where only defined outside class
const_char* operator/(int)
const_char* operator/(int,const TestOps&)
const_char* operator%(int)
const_char* operator%(int,const TestOps&)
const_char* operator|(int)
const_char* operator|(int,const TestOps&)
const_char* operator&(int)
const_char* operator&(int,const TestOps&)
const_char* operator^(int)
const_char* operator^(int,const TestOps&)
const_char* operator,(int)
const_char* operator,(int,const TestOps&)
const_char* operator<<(int)
const_char* operator<<(int,const TestOps&)
const_char* operator>>(int)
const_char* operator>>(int,const TestOps&)
const_char* operator==(int)
const_char* operator!=(int)
......@@ -49,6 +60,23 @@ cdef extern from "cpp_operators_helper.h" nogil:
const_char* operator[](int)
const_char* operator()(int)
# Defining the operator outside the class does work
# but doesn't help when importing from pxd files
# (they don't get imported)
const_char* operator+(float,const TestOps&)
# deliberately omitted operator- to test case where only defined in class
const_char* operator*(float,const TestOps&)
const_char* operator/(float,const TestOps&)
const_char* operator%(float,const TestOps&)
const_char* operator|(float,const TestOps&)
const_char* operator&(float,const TestOps&)
const_char* operator^(float,const TestOps&)
const_char* operator,(float,const TestOps&)
const_char* operator<<(float,const TestOps&)
const_char* operator>>(float,const TestOps&)
cdef cppclass TruthClass:
TruthClass()
......@@ -129,6 +157,63 @@ def test_binop():
out(x, typeof(x))
del t
def test_nonmember_binop():
"""
>>> test_nonmember_binop()
nonmember binary + [const_char *]
nonmember binary - [const_char *]
nonmember binary / [const_char *]
nonmember binary % [const_char *]
nonmember binary & [const_char *]
nonmember binary | [const_char *]
nonmember binary ^ [const_char *]
nonmember binary << [const_char *]
nonmember binary >> [const_char *]
nonmember binary COMMA [const_char *]
nonmember binary2 + [const_char *]
nonmember binary2 * [const_char *]
nonmember binary2 / [const_char *]
nonmember binary2 % [const_char *]
nonmember binary2 & [const_char *]
nonmember binary2 | [const_char *]
nonmember binary2 ^ [const_char *]
nonmember binary2 << [const_char *]
nonmember binary2 >> [const_char *]
nonmember binary2 COMMA [const_char *]
"""
cdef TestOps* t = new TestOps()
out(1 + t[0], typeof(1 + t[0]))
out(1 - t[0], typeof(1 - t[0]))
# * deliberately omitted
out(1 / t[0], typeof(1 / t[0]))
out(1 % t[0], typeof(1 % t[0]))
out(1 & t[0], typeof(1 & t[0]))
out(1 | t[0], typeof(1 | t[0]))
out(1 ^ t[0], typeof(1 ^ t[0]))
out(1 << t[0], typeof(1 << t[0]))
out(1 >> t[0], typeof(1 >> t[0]))
x = cython.operator.comma(1, t[0])
out(x, typeof(x))
# now test float operators defined outside class
out(1. + t[0], typeof(1. + t[0]))
# operator - deliberately omitted
out(1. * t[0], typeof(1. * t[0]))
out(1. / t[0], typeof(1. / t[0]))
out(1. % t[0], typeof(1. % t[0]))
out(1. & t[0], typeof(1. & t[0]))
out(1. | t[0], typeof(1. | t[0]))
out(1. ^ t[0], typeof(1. ^ t[0]))
out(1. << t[0], typeof(1. << t[0]))
out(1. >> t[0], typeof(1. >> t[0]))
# for some reason we need a cdef here - not sure this is quite right
y = cython.operator.comma(1., t[0])
out(y, typeof(y))
del t
def test_cmp():
"""
>>> test_cmp()
......
#define UN_OP(op) const char* operator op () { return "unary "#op; }
#define POST_UN_OP(op) const char* operator op (int x) { x++; return "post "#op; }
#define BIN_OP(op) const char* operator op (int x) { x++; return "binary "#op; }
#define NONMEMBER_BIN_OP(op) const char* operator op (int x, const TestOps&) { x++; return "nonmember binary "#op; }
#define NONMEMBER_BIN_OP2(op) const char* operator op (double x, const TestOps&) { x++; return "nonmember binary2 "#op; }
#define COMMA ,
......@@ -46,6 +48,34 @@ public:
};
NONMEMBER_BIN_OP(+)
NONMEMBER_BIN_OP(-)
NONMEMBER_BIN_OP(*)
NONMEMBER_BIN_OP(/)
NONMEMBER_BIN_OP(%)
NONMEMBER_BIN_OP(<<)
NONMEMBER_BIN_OP(>>)
NONMEMBER_BIN_OP(|)
NONMEMBER_BIN_OP(&)
NONMEMBER_BIN_OP(^)
NONMEMBER_BIN_OP(COMMA)
NONMEMBER_BIN_OP2(+)
NONMEMBER_BIN_OP2(-)
NONMEMBER_BIN_OP2(*)
NONMEMBER_BIN_OP2(/)
NONMEMBER_BIN_OP2(%)
NONMEMBER_BIN_OP2(<<)
NONMEMBER_BIN_OP2(>>)
NONMEMBER_BIN_OP2(|)
NONMEMBER_BIN_OP2(&)
NONMEMBER_BIN_OP2(^)
NONMEMBER_BIN_OP2(COMMA)
class TruthClass {
public:
TruthClass() : value(false) {}
......@@ -53,4 +83,4 @@ public:
virtual ~TruthClass() {};
operator bool() { return value; }
bool value;
};
};
\ No newline at end of file
......@@ -94,6 +94,7 @@ cdef const_vector_to_list(const vector[double]& cv):
cython.operator.preincrement(iter)
return lst
cdef double dmax = numeric_limits[double].max()
cdef double dmin = numeric_limits[double].min()
cdef double deps = numeric_limits[double].epsilon()
......@@ -124,4 +125,23 @@ def convert_to_vector(I):
"""
cdef vector[int] x = I
def complex_operators():
"""
>>> complex_operators()
[-1.0, 0.0, 0.0, 2.0, 0.0, 2.0]
"""
cdef libcpp.complex.complex[double] a = libcpp.complex.complex[double](0.0,1.0)
cdef libcpp.complex.complex[double] r1=a*a
cdef libcpp.complex.complex[double] r2=a*2.0
cdef libcpp.complex.complex[double] r3=2.0*a
return [r1.real(), r1.imag(), r2.real(), r2.imag(), r3.real(), r3.imag()]
def pair_comparison():
"""
>>> pair_comparison()
[False, True, False, True, False]
"""
cdef pair[double, double] p1 = pair[double, double](1.0,2.0)
cdef pair[double, double] p2 = pair[double, double](2.0,2.0)
return [p1==p2,p1==p1,p1>p2,p1<p2,p2>p2]
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment