Commit ad0fb02f authored by gabrieldemarmiesse's avatar gabrieldemarmiesse

Merge remote-tracking branch 'myles1/master' into update_cpp_examples

parents 208c3553 73914beb
#include <iostream>
#include "Rectangle.h"
namespace shapes {
// Default constructor
Rectangle::Rectangle () {}
// Overloaded constructor
Rectangle::Rectangle (int x0, int y0, int x1, int y1) {
this->x0 = x0;
this->y0 = y0;
this->x1 = x1;
this->y1 = y1;
}
// Destructor
Rectangle::~Rectangle () {}
// Return the area of the rectangle
int Rectangle::getArea () {
return (this->x1 - this->x0) * (this->y1 - this->y0);
}
// Get the size of the rectangle.
// Put the size in the pointer args
void Rectangle::getSize (int *width, int *height) {
(*width) = x1 - x0;
(*height) = y1 - y0;
}
// Move the rectangle by dx dy
void Rectangle::move (int dx, int dy) {
this->x0 += dx;
this->y0 += dy;
this->x1 += dx;
this->y1 += dy;
}
}
#ifndef RECTANGLE_H
#define RECTANGLE_H
namespace shapes {
class Rectangle {
public:
int x0, y0, x1, y1;
Rectangle();
Rectangle(int x0, int y0, int x1, int y1);
~Rectangle();
int getArea();
void getSize(int* width, int* height);
void move(int dx, int dy);
};
}
#endif // RECTANGLE_H
#!/usr/bin/env python
# -*- coding: utf-8 -*-
try:
import rect
except ImportError:
print("Module rect has not yet been built")
print("Please run $python setup.py build_ext --inplace")
print("Then try again")
import sys
sys.exit()
x0, y0, x1, y1 = 1, 2, 3, 4
rect_obj = rect.PyRectangle(x0, y0, x1, y1)
print(dir(rect_obj))
# distutils: language = c++
# distutils: sources = Rectangle.cpp
# Decalre the class with cdef
cdef extern from "Rectangle.h" namespace "shapes":
cdef cppclass Rectangle:
Rectangle() except +
Rectangle(int, int, int, int) except +
int x0, y0, x1, y1
int getArea()
void getSize(int* width, int* height)
void move(int, int)
# Create a Cython extension type which holds a C++ instance
# as an attribute and create a bunch of forwarding methods
# Python extension type:
cdef class PyRectangle:
cdef Rectangle c_rect # Hold a C++ instance which we're wrapping
def __cinit__(self, int x0, int y0, int x1, int y1):
self.c_rect = Rectangle(x0, y0, x1, y1)
def get_area(self):
return self.c_rect.getArea()
def get_size(self):
cdef int width, height
self.c_rect.getSize(&width, &height)
return width, height
def move(self, dx, dy):
self.c_rect.move(dx, dy)
# Attribute access
@property
def x0(self):
return self.c_rect.x0
@x0.setter
def x0(self, x0):
self.c_rect.x0 = x0
# Attribute access
@property
def x1(self):
return self.c_rect.x1
@x1.setter
def x1(self, x1):
self.c_rect.x1 = x1
# Attribute access
@property
def y0(self):
return self.c_rect.y0
@y0.setter
def y0(self, y0):
self.c_rect.y0 = y0
# Attribute access
@property
def y1(self):
return self.c_rect.y1
@y1.setter
def y1(self, y1):
self.c_rect.y1 = y1
def main():
rec_ptr = new Rectangle(1, 2, 3, 4) # Instantiate a Rectangle object on the heap
try:
recArea = rec_ptr.getArea()
finally:
del rec_ptr # delete heap allocated object
cdef Rectangle rec_stack # Instantiate a Rectangle object on the stack
if __name__ == "__main__":
main()
from distutils.core import setup, Extension
from Cython.Build import cythonize
setup(ext_modules = cythonize("rect.pyx"))
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
import unittest
import os
class TestRectangleCppExtension(unittest.TestCase):
def setUp(self):
self.directory_at_runtime = os.listdir()
os.system("python setup.py build_ext --inplace")
import rect
self.x0, self.y0, self.x1, self.y1 = 1, 2, 3, 4
self.rect_obj = rect.PyRectangle(self.x0, self.y0, self.x1, self.y1)
def test_get_area(self):
width = self.x1 - self.x0
height = self.y1 - self.y0
area = width * height
self.assertEqual(
self.rect_obj.get_area(),
area)
def test_get_size(self):
true_width = self.x1 - self.x0
true_height = self.y1 - self.y0
width, height = self.rect_obj.get_size()
self.assertEqual(true_width, width)
self.assertEqual(true_height, height)
def test_move(self):
x0, x1 = self.rect_obj.x0, self.rect_obj.x1
y0, y1 = self.rect_obj.y0, self.rect_obj.y1
dx, dy = 10, 5
self.rect_obj.move(dx, dy)
self.assertEqual(
(x0+dx, x1+dx, y0+dy, y1+dy),
(self.rect_obj.x0, self.rect_obj.x1,
self.rect_obj.y0, self.rect_obj.y1))
def tearDown(self):
files_to_remove = [f for f in os.listdir()
if f not in self.directory_at_runtime]
for f in files_to_remove:
if os.path.isfile(f):
os.remove(f)
elif os.path.isdir(f):
os.system("rm -rf {}".format(f))
if __name__ == "__main__":
unittest.main()
......@@ -29,7 +29,7 @@ The general procedure for wrapping a C++ file can now be described as follows:
* declare classes as ``cdef cppclass`` blocks
* declare public names (variables, methods and constructors)
* Write an extension modules, ``cimport`` from the .pxd file and use
* Write one or more extension modules, ``cimport`` them from the .pxd file and use
the declarations.
A simple Tutorial
......@@ -67,30 +67,30 @@ and the implementation in the file called :file:`Rectangle.cpp`:
Rectangle::Rectangle() { }
Rectangle::Rectangle(int X0, int Y0, int X1, int Y1) {
x0 = X0;
y0 = Y0;
x1 = X1;
y1 = Y1;
}
Rectangle::Rectangle(int X0, int Y0, int X1, int Y1) {
x0 = X0;
y0 = Y0;
x1 = X1;
y1 = Y1;
}
Rectangle::~Rectangle() { }
Rectangle::~Rectangle() { }
int Rectangle::getArea() {
return (x1 - x0) * (y1 - y0);
}
int Rectangle::getArea() {
return (x1 - x0) * (y1 - y0);
}
void Rectangle::getSize(int *width, int *height) {
(*width) = x1 - x0;
(*height) = y1 - y0;
}
void Rectangle::getSize(int *width, int *height) {
(*width) = x1 - x0;
(*height) = y1 - y0;
}
void Rectangle::move(int dx, int dy) {
x0 += dx;
y0 += dy;
x1 += dx;
y1 += dy;
}
void Rectangle::move(int dx, int dy) {
x0 += dx;
y0 += dy;
x1 += dx;
y1 += dy;
}
}
......@@ -112,7 +112,7 @@ with distutils, you just need to pass the option ``language="c++"``::
language="c++", # generate C++ code
))
Cython will generate and compile the :file:`rect.cpp` file (from the
Cython will generate and compile the :file:`rect.cpp` file (from
:file:`rect.pyx`), then it will compile :file:`Rectangle.cpp`
(implementation of the ``Rectangle`` class) and link both objects files
together into :file:`rect.so`, which you can then import in Python using
......@@ -140,7 +140,7 @@ is then handled by ``cythonize()`` as follows::
The options can also be passed directly from the source file, which is
often preferable (and overrides any global option). Starting with
version 0.17, Cython also allows to pass external source files into the
version 0.17, Cython also allows passing external source files into the
``cythonize()`` command this way. Here is a simplified setup.py file::
from distutils.core import setup
......@@ -209,7 +209,7 @@ Declare a var with the wrapped C++ class
Now, we use cdef to declare a var of the class with the C++ ``new`` statement::
rec_ptr = new Rectangle(1, 2, 3, 4)
rec_ptr = new Rectangle(1, 2, 3, 4) # Instantiate a Rectangle object on the heap
try:
recArea = rec_ptr.getArea()
...
......@@ -290,6 +290,19 @@ instance.
If you prefer giving the same name to the wrapper as the C++ class, see the
section on :ref:`resolving naming conflicts <resolve-conflicts>`.
Compilation and Importing
=========================
Run ``$python setup.py build_ext --inplace``
Create :file:`test_import.py`:
::
import rect
x0, y0, x1, y1 = 1, 2, 3, 4
rect_obj = rect.Rectangle(x0, y0, x1, y1)
print(dir(rect_object))
Advanced C++ features
======================
......@@ -378,7 +391,7 @@ Note that the nested class is declared with a ``cppclass`` but without a ``cdef`
C++ operators not compatible with Python syntax
------------------------------------------------
Cython try to keep a syntax as close as possible to standard Python.
Cython tries to keep its syntax as close as possible to standard Python.
Because of this, certain C++ operators, like the preincrement ``++foo``
or the dereferencing operator ``*foo`` cannot be used with the same
syntax as C++. Cython provides functions replacing these operators in
......
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