Added boost::optional support for using with Boost.Python.
This commit is contained in:
parent
96684b72ca
commit
0528a1e49a
3 changed files with 93 additions and 18 deletions
|
|
@ -1,7 +1,9 @@
|
||||||
#include "pyinterp.h"
|
#include "pyinterp.h"
|
||||||
|
#include "pyutils.h"
|
||||||
#include "amount.h"
|
#include "amount.h"
|
||||||
|
|
||||||
#include <boost/python/exception_translator.hpp>
|
#include <boost/python/exception_translator.hpp>
|
||||||
|
#include <boost/python/implicit.hpp>
|
||||||
|
|
||||||
namespace ledger {
|
namespace ledger {
|
||||||
|
|
||||||
|
|
@ -21,6 +23,14 @@ amount_t py_round_2(const amount_t& amount) {
|
||||||
return amount.round();
|
return amount.round();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boost::optional<amount_t> py_value_1(const amount_t& amount,
|
||||||
|
const boost::optional<moment_t>& moment) {
|
||||||
|
return amount.value(moment);
|
||||||
|
}
|
||||||
|
boost::optional<amount_t> py_value_2(const amount_t& amount) {
|
||||||
|
return amount.value();
|
||||||
|
}
|
||||||
|
|
||||||
#define EXC_TRANSLATOR(type) \
|
#define EXC_TRANSLATOR(type) \
|
||||||
void exc_translate_ ## type(const type& err) { \
|
void exc_translate_ ## type(const type& err) { \
|
||||||
PyErr_SetString(PyExc_ArithmeticError, err.what()); \
|
PyErr_SetString(PyExc_ArithmeticError, err.what()); \
|
||||||
|
|
@ -161,7 +171,8 @@ void export_amount()
|
||||||
.def("in_place_unreduce", &amount_t::in_place_unreduce,
|
.def("in_place_unreduce", &amount_t::in_place_unreduce,
|
||||||
return_value_policy<reference_existing_object>())
|
return_value_policy<reference_existing_object>())
|
||||||
|
|
||||||
.def("value", &amount_t::value)
|
.def("value", py_value_1)
|
||||||
|
.def("value", py_value_2)
|
||||||
|
|
||||||
.def("sign", &amount_t::sign)
|
.def("sign", &amount_t::sign)
|
||||||
.def("__nonzero__", &amount_t::nonzero)
|
.def("__nonzero__", &amount_t::nonzero)
|
||||||
|
|
@ -213,6 +224,12 @@ void export_amount()
|
||||||
.def("valid", &amount_t::valid)
|
.def("valid", &amount_t::valid)
|
||||||
;
|
;
|
||||||
|
|
||||||
|
python_optional<amount_t>();
|
||||||
|
|
||||||
|
implicitly_convertible<double, amount_t>();
|
||||||
|
implicitly_convertible<long, amount_t>();
|
||||||
|
implicitly_convertible<string, amount_t>();
|
||||||
|
|
||||||
#define EXC_TRANSLATE(type) \
|
#define EXC_TRANSLATE(type) \
|
||||||
register_exception_translator<type>(&exc_translate_ ## type);
|
register_exception_translator<type>(&exc_translate_ ## type);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,8 @@
|
||||||
#include <Python.h>
|
#include <Python.h>
|
||||||
#include <datetime.h>
|
#include <datetime.h>
|
||||||
|
|
||||||
|
// jww (2007-05-04): Convert time duration objects to PyDelta
|
||||||
|
|
||||||
namespace ledger {
|
namespace ledger {
|
||||||
|
|
||||||
using namespace boost::python;
|
using namespace boost::python;
|
||||||
|
|
@ -29,7 +31,7 @@ struct date_from_python
|
||||||
static void* convertible(PyObject* obj_ptr)
|
static void* convertible(PyObject* obj_ptr)
|
||||||
{
|
{
|
||||||
PyDateTime_IMPORT;
|
PyDateTime_IMPORT;
|
||||||
if(PyDate_Check(obj_ptr) || PyDateTime_Check(obj_ptr)) return obj_ptr;
|
if (PyDate_Check(obj_ptr)) return obj_ptr;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -48,15 +50,13 @@ typedef register_python_conversion<date, date_to_python, date_from_python>
|
||||||
date_python_conversion;
|
date_python_conversion;
|
||||||
|
|
||||||
|
|
||||||
typedef boost::posix_time::ptime datetime;
|
|
||||||
|
|
||||||
struct datetime_to_python
|
struct datetime_to_python
|
||||||
{
|
{
|
||||||
static PyObject* convert(const datetime& moment)
|
static PyObject* convert(const moment_t& moment)
|
||||||
{
|
{
|
||||||
PyDateTime_IMPORT;
|
PyDateTime_IMPORT;
|
||||||
date dte = moment.date();
|
date dte = moment.date();
|
||||||
datetime::time_duration_type tod = moment.time_of_day();
|
moment_t::time_duration_type tod = moment.time_of_day();
|
||||||
return PyDateTime_FromDateAndTime(dte.year(), dte.month(), dte.day(),
|
return PyDateTime_FromDateAndTime(dte.year(), dte.month(), dte.day(),
|
||||||
tod.hours(), tod.minutes(), tod.seconds(),
|
tod.hours(), tod.minutes(), tod.seconds(),
|
||||||
tod.total_microseconds() % 1000000);
|
tod.total_microseconds() % 1000000);
|
||||||
|
|
@ -81,19 +81,21 @@ struct datetime_from_python
|
||||||
int h = PyDateTime_DATE_GET_HOUR(obj_ptr);
|
int h = PyDateTime_DATE_GET_HOUR(obj_ptr);
|
||||||
int min = PyDateTime_DATE_GET_MINUTE(obj_ptr);
|
int min = PyDateTime_DATE_GET_MINUTE(obj_ptr);
|
||||||
int s = PyDateTime_DATE_GET_SECOND(obj_ptr);
|
int s = PyDateTime_DATE_GET_SECOND(obj_ptr);
|
||||||
datetime* moment = new datetime(date(y,m,d),
|
moment_t* moment = new moment_t(date(y,m,d),
|
||||||
datetime::time_duration_type(h, min, s));
|
moment_t::time_duration_type(h, min, s));
|
||||||
data->convertible = (void*)moment;
|
data->convertible = (void*)moment;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef register_python_conversion<datetime, datetime_to_python, datetime_from_python>
|
typedef register_python_conversion<moment_t, datetime_to_python, datetime_from_python>
|
||||||
datetime_python_conversion;
|
datetime_python_conversion;
|
||||||
|
|
||||||
void export_times()
|
void export_times()
|
||||||
{
|
{
|
||||||
date_python_conversion();
|
date_python_conversion();
|
||||||
datetime_python_conversion();
|
datetime_python_conversion();
|
||||||
|
|
||||||
|
python_optional<moment_t>();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace ledger
|
} // namespace ledger
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,78 @@
|
||||||
#ifndef _PY_UTILS_H
|
#ifndef _PY_UTILS_H
|
||||||
#define _PY_UTILS_H
|
#define _PY_UTILS_H
|
||||||
|
|
||||||
template<class T, class TfromPy>
|
template <typename T, typename TfromPy>
|
||||||
struct ObjFromPy {
|
struct object_from_python
|
||||||
ObjFromPy() {
|
{
|
||||||
|
object_from_python() {
|
||||||
boost::python::converter::registry::push_back
|
boost::python::converter::registry::push_back
|
||||||
(&TfromPy::convertible,
|
(&TfromPy::convertible, &TfromPy::construct,
|
||||||
&TfromPy::construct,
|
|
||||||
boost::python::type_id<T>());
|
boost::python::type_id<T>());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<class T, class TtoPy, class TfromPy>
|
template <typename T, typename TtoPy, typename TfromPy>
|
||||||
struct register_python_conversion {
|
struct register_python_conversion
|
||||||
|
{
|
||||||
register_python_conversion() {
|
register_python_conversion() {
|
||||||
boost::python::to_python_converter<T, TtoPy>();
|
boost::python::to_python_converter<T, TtoPy>();
|
||||||
ObjFromPy<T, TfromPy>();
|
object_from_python<T, TfromPy>();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct python_optional : public boost::noncopyable
|
||||||
|
{
|
||||||
|
struct optional_to_python
|
||||||
|
{
|
||||||
|
static PyObject * convert(const boost::optional<T>& value)
|
||||||
|
{
|
||||||
|
return (value ? boost::python::to_python_value<T>()(*value) :
|
||||||
|
boost::python::detail::none());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct optional_from_python
|
||||||
|
{
|
||||||
|
static void * convertible(PyObject * source)
|
||||||
|
{
|
||||||
|
using namespace boost::python::converter;
|
||||||
|
|
||||||
|
if (source == Py_None)
|
||||||
|
return source;
|
||||||
|
|
||||||
|
const registration& converters(registered<T>::converters);
|
||||||
|
|
||||||
|
if (implicit_rvalue_convertible_from_python(source, converters)) {
|
||||||
|
rvalue_from_python_stage1_data data =
|
||||||
|
rvalue_from_python_stage1(source, converters);
|
||||||
|
return rvalue_from_python_stage2(source, data, converters);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void construct(PyObject * source,
|
||||||
|
boost::python::converter::rvalue_from_python_stage1_data * data)
|
||||||
|
{
|
||||||
|
using namespace boost::python::converter;
|
||||||
|
|
||||||
|
void * const storage = ((rvalue_from_python_storage<T> *) data)->storage.bytes;
|
||||||
|
|
||||||
|
if (data->convertible == source) // == None
|
||||||
|
new (storage) boost::optional<T>(); // A Boost uninitialized value
|
||||||
|
else
|
||||||
|
new (storage) boost::optional<T>(*static_cast<T *>(data->convertible));
|
||||||
|
|
||||||
|
data->convertible = storage;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
explicit python_optional() {
|
||||||
|
register_python_conversion<boost::optional<T>,
|
||||||
|
optional_to_python, optional_from_python>();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//boost::python::register_ptr_to_python< boost::shared_ptr<Base> >();
|
||||||
|
|
||||||
#endif // _PY_UTILS_H
|
#endif // _PY_UTILS_H
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue