作成日: 2023-08-08 (火)
プロジェクトレイアウト
. └── extending-demos/ ├── Jamroot ├── simple/ │ ├── Jamfile │ ├── simple.cpp │ └── test_simple.py ├── point/ │ ├── Jamfile │ ├── point.cpp │ └── test_point.py ├── pypoint/ │ ├── Jamfile │ ├── pypoint.cpp │ └── test_pypoint.py └── fakegfx/ ├── Jamfile ├── fakegfx.h ├── fakegfx.cpp └── test_fakegfx.py
import python ;
lib boost_python3 ;
project
: requirements
<library>boost_python3
;
build-project simple ;
build-project point ;
build-project pypoint ;
build-project fakegfx ;
#include <boost/python.hpp>
#include <boost/algorithm/string.hpp>
#include <iostream>
namespace {
void println(std::string const &s) {
std::cout << s << '\n';
}
std::string to_upper(std::string const &s) {
return boost::to_upper_copy<std::string>(s);
}
} // ns anon
BOOST_PYTHON_MODULE(simple) {
namespace python = boost::python;
python::def("println", println);
python::def("to_upper", to_upper);
}
import simple
simple.println("Hello, Boost.Python!")
u = simple.to_upper("Hello, Boost.Python!")
simple.println(u)
project simple
: requirements
<location>.
;
python-extension simple : simple.cpp ;
#include <boost/python.hpp>
namespace {
struct Point {
double x = 0.0;
double y = 0.0;
Point() = default;
Point(double x, double y) : x{x}, y{y} {}
};
void translate(Point &pt, double tx, double ty) {
pt.x += tx;
pt.y += ty;
}
}
BOOST_PYTHON_MODULE(point) {
using namespace boost::python;
class_<Point>("Point")
.def(init<double, double>())
.def("translate", translate)
.def_readwrite("x", &Point::x)
.def_readwrite("y", &Point::y);
def("translate", translate);
}
import point
pt = point.Point()
print(f"{pt.x},{pt.y}")
pt.translate(100, -200)
print(f"{pt.x},{pt.y}")
project point
: requirements
<location>.
;
python-extension point : point.cpp ;
#include <boost/python.hpp>
namespace {
void translate(boost::python::object pt, double tx, double ty) {
pt.attr("x") += tx;
pt.attr("y") += ty;
}
} // ns anon
BOOST_PYTHON_MODULE(pypoint) {
boost::python::def("translate", translate);
}
import pypoint
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
pt = Point(1, 2)
pypoint.translate(pt, 100, -200)
print(f"{pt.x},{pt.y}")
project pypoint
: requirements
<location>.
;
python-extension pypoint : pypoint.cpp ;
#ifndef FAKEGFX_H
#define FAKEGFX_H
#include <iostream>
struct Point {
Point() = default;
Point(double x, double y) : x{x}, y{y} {}
double x, y;
};
inline void translate(Point &pt, double tx, double ty) {
pt.x += tx;
pt.y += ty;
}
class Shape {
public:
virtual ~Shape() = default;
virtual void draw() const = 0;
};
class RectangleShape : public Shape {
public:
RectangleShape(Point const &position)
: position_{position} {}
void draw() const override {
std::cout << "▬" << std::endl;
}
private:
Point position_;
};
inline void draw_shape(Shape const &shape) {
shape.draw();
}
inline void draw_rectangle_shape(RectangleShape const &shape) {
shape.draw();
}
#endif
#include "fakegfx.h"
#include <boost/python.hpp>
#include <boost/current_function.hpp>
#include <iostream>
namespace {
class ShapeWrap : public Shape, public boost::python::wrapper<Shape> {
public:
void draw() const override {
this->get_override("draw")();
}
};
class RectangleShapeWrap
: public RectangleShape
, public boost::python::wrapper<RectangleShape> {
public:
RectangleShapeWrap(Point const &position) : RectangleShape{position} {}
void draw() const override {
if (boost::python::override draw = this->get_override("draw")) {
draw();
} else {
RectangleShape::draw();
}
}
void default_draw() const {
std::cout << BOOST_CURRENT_FUNCTION << std::endl;
RectangleShape::draw();
}
};
} // ns anon
BOOST_PYTHON_MODULE(fakegfx) {
using namespace boost::python;
class_<Point>("Point")
.def(init<double, double>())
.def("translate", &translate)
.def_readwrite("x", &Point::x)
.def_readwrite("y", &Point::y);
class_<ShapeWrap, boost::noncopyable>("Shape")
.def("draw", pure_virtual(&Shape::draw));
class_<RectangleShapeWrap, bases<Shape>, boost::noncopyable>("RectangleShape", init<Point const&>())
.def("draw", &RectangleShape::draw /*1*/, &RectangleShapeWrap::default_draw /*2*/);
// drawの呼び出しを、関数2に転送する
// 関数2のシグネチャが関数1と一致することを保証させる
// 関数1の指定はそのためだけに必要となる
def("draw_shape", draw_shape);
def("draw_rectangle_shape", draw_rectangle_shape);
}
import fakegfx
# some points
pt = fakegfx.Point(1, 2)
print(f"{pt.x}, {pt.y}")
pt.translate(-100, 200)
print(f"{pt.x}, {pt.y}")
pt2 = fakegfx.Point()
print(f"{pt2.x}, {pt2.y}")
# circle shape
# derived from C++ shape class
# Shape <- CircleShape
class CircleShape(fakegfx.Shape):
def draw(self):
#super().draw() # cause pure virtual function call
print("○")
circle = CircleShape()
# rectangle shape
# defined in C++ code
rectangle = fakegfx.RectangleShape(pt)
# square shape
# derived from C++ rectangle shape class
# Shape <- RectangleShape <- SquareSahpe
class SquareShape(fakegfx.RectangleShape):
def __init__(self):
super().__init__(pt)
def draw(self):
fakegfx.RectangleShape.draw(self) # test non-cyclic
print("▧")
square = SquareShape()
print("#circle#")
fakegfx.draw_shape(circle)
print("#rectangle#")
fakegfx.draw_shape(rectangle)
print("#square#")
fakegfx.draw_shape(square)
print("-circle-")
circle.draw()
print("-rectangle-")
rectangle.draw()
print("-square-")
square.draw()
project extending
: requirements
<location>.
;
python-extension fakegfx : fakegfx.cpp ;