diff options
author | Clifford Wolf <cliffordvienna@gmail.com> | 2018-07-04 16:39:30 +0000 |
---|---|---|
committer | Clifford Wolf <cliffordvienna@gmail.com> | 2018-07-04 16:39:30 +0000 |
commit | 6d423bb24a762e4a53e9b9d279c620c386264287 (patch) | |
tree | 5f90b199d7d7e6cd2f7a96224dc3ecddadce154c /common | |
parent | 09dbcdcfa8c44b420c4a1763f599fd0e59e00d97 (diff) | |
parent | 726f2020f140a1f5e89e966e7cbde1d1f79473ba (diff) | |
download | nextpnr-6d423bb24a762e4a53e9b9d279c620c386264287.tar.gz nextpnr-6d423bb24a762e4a53e9b9d279c620c386264287.tar.bz2 nextpnr-6d423bb24a762e4a53e9b9d279c620c386264287.zip |
Merge branch 'new_python' into 'master'
New "contextual" system of Python wrappers
See merge request SymbioticEDA/nextpnr!4
Diffstat (limited to 'common')
-rw-r--r-- | common/nextpnr.cc | 2 | ||||
-rw-r--r-- | common/nextpnr.h | 13 | ||||
-rw-r--r-- | common/pybindings.cc | 109 | ||||
-rw-r--r-- | common/pybindings.h | 63 | ||||
-rw-r--r-- | common/pycontainers.h | 195 | ||||
-rw-r--r-- | common/pywrappers.h | 266 |
6 files changed, 468 insertions, 180 deletions
diff --git a/common/nextpnr.cc b/common/nextpnr.cc index a197eaff..3861e5fe 100644 --- a/common/nextpnr.cc +++ b/common/nextpnr.cc @@ -27,8 +27,6 @@ assertion_failure::assertion_failure(std::string msg, std::string expr_str, std: { } -std::unordered_set<BaseCtx *> IdString::global_ctx; - void IdString::set(const BaseCtx *ctx, const std::string &s) { auto it = ctx->idstring_str_to_idx->find(s); diff --git a/common/nextpnr.h b/common/nextpnr.h index 6a45875b..ec0c2f9f 100644 --- a/common/nextpnr.h +++ b/common/nextpnr.h @@ -118,16 +118,6 @@ struct IdString bool operator!=(const IdString &other) const { return index != other.index; } bool empty() const { return index == 0; } - - // --- deprecated old API --- - - static std::unordered_set<BaseCtx *> global_ctx; - - NPNR_DEPRECATED const std::string &global_str() const - { - assert(global_ctx.size() == 1); - return str(*global_ctx.begin()); - } }; NEXTPNR_NAMESPACE_END @@ -252,8 +242,6 @@ struct BaseCtx BaseCtx() { - IdString::global_ctx.insert(this); - idstring_str_to_idx = new std::unordered_map<std::string, int>; idstring_idx_to_str = new std::vector<const std::string *>; IdString::initialize_add(this, "", 0); @@ -262,7 +250,6 @@ struct BaseCtx ~BaseCtx() { - IdString::global_ctx.erase(this); delete idstring_str_to_idx; delete idstring_idx_to_str; } diff --git a/common/pybindings.cc b/common/pybindings.cc index e9ceca51..9bca307c 100644 --- a/common/pybindings.cc +++ b/common/pybindings.cc @@ -21,6 +21,7 @@ #ifndef NO_PYTHON #include "pybindings.h" +#include "arch_pybindings.h" #include "jsonparse.h" #include "nextpnr.h" @@ -61,8 +62,18 @@ Context *load_design_shim(std::string filename, ArchArgs args) return d; } +void translate_assertfail(const assertion_failure &e) +{ + // Use the Python 'C' API to set up an exception object + PyErr_SetString(PyExc_AssertionError, e.what()); +} + BOOST_PYTHON_MODULE(MODULE_NAME) { + register_exception_translator<assertion_failure>(&translate_assertfail); + + using namespace PythonConversion; + class_<GraphicElement>("GraphicElement") .def_readwrite("type", &GraphicElement::type) .def_readwrite("x1", &GraphicElement::x1) @@ -71,59 +82,73 @@ BOOST_PYTHON_MODULE(MODULE_NAME) .def_readwrite("y2", &GraphicElement::y2) .def_readwrite("text", &GraphicElement::text); - class_<PortRef>("PortRef").def_readwrite("cell", &PortRef::cell).def_readwrite("port", &PortRef::port); - - class_<NetInfo, NetInfo *, boost::noncopyable>("NetInfo") - .def_readwrite("name", &NetInfo::name) - .def_readwrite("driver", &NetInfo::driver) - .def_readwrite("users", &NetInfo::users) - .def_readwrite("attrs", &NetInfo::attrs) - .def_readwrite("wires", &NetInfo::wires); - - WRAP_MAP(decltype(NetInfo::attrs), "IdStrMap"); - - class_<std::vector<PortRef>>("PortRefVector").def(vector_indexing_suite<std::vector<PortRef>>()); - enum_<PortType>("PortType") .value("PORT_IN", PORT_IN) .value("PORT_OUT", PORT_OUT) .value("PORT_INOUT", PORT_INOUT) .export_values(); - class_<PortInfo>("PortInfo") - .def_readwrite("name", &PortInfo::name) - .def_readwrite("net", &PortInfo::net) - .def_readwrite("type", &PortInfo::type); - - class_<CellInfo, CellInfo *>("CellInfo") - .def_readwrite("name", &CellInfo::name) - .def_readwrite("type", &CellInfo::type) - .def_readwrite("ports", &CellInfo::ports) - .def_readwrite("attrs", &CellInfo::attrs) - .def_readwrite("params", &CellInfo::params) - .def_readwrite("bel", &CellInfo::bel) - .def_readwrite("pins", &CellInfo::pins); - - WRAP_MAP(decltype(CellInfo::ports), "IdPortMap"); - // WRAP_MAP(decltype(CellInfo::pins), "IdIdMap"); - - class_<BaseCtx, BaseCtx *, boost::noncopyable>("BaseCtx", no_init) - .add_property("nets", make_getter(&Context::nets, return_internal_reference<>())) - .add_property("cells", make_getter(&Context::cells, return_internal_reference<>())); - - WRAP_MAP_UPTR(decltype(Context::nets), "IdNetMap"); - WRAP_MAP_UPTR(decltype(Context::cells), "IdCellMap"); + typedef std::unordered_map<IdString, std::string> AttrMap; + typedef std::unordered_map<IdString, PortInfo> PortMap; + typedef std::unordered_map<IdString, IdString> PinMap; + + class_<BaseCtx, BaseCtx *, boost::noncopyable>("BaseCtx", no_init); + + auto ci_cls = class_<ContextualWrapper<CellInfo &>>("CellInfo", no_init); + readwrite_wrapper<CellInfo &, typeof(&CellInfo::name), &CellInfo::name, conv_to_str<IdString>, + conv_from_str<IdString>>::def_wrap(ci_cls, "name"); + readwrite_wrapper<CellInfo &, typeof(&CellInfo::type), &CellInfo::type, conv_to_str<IdString>, + conv_from_str<IdString>>::def_wrap(ci_cls, "type"); + readonly_wrapper<CellInfo &, typeof(&CellInfo::attrs), &CellInfo::attrs, wrap_context<AttrMap &>>::def_wrap( + ci_cls, "attrs"); + readonly_wrapper<CellInfo &, typeof(&CellInfo::params), &CellInfo::params, wrap_context<AttrMap &>>::def_wrap( + ci_cls, "params"); + readonly_wrapper<CellInfo &, typeof(&CellInfo::ports), &CellInfo::ports, wrap_context<PortMap &>>::def_wrap( + ci_cls, "ports"); + readwrite_wrapper<CellInfo &, typeof(&CellInfo::bel), &CellInfo::bel, conv_to_str<BelId>, + conv_from_str<BelId>>::def_wrap(ci_cls, "bel"); + readwrite_wrapper<CellInfo &, typeof(&CellInfo::belStrength), &CellInfo::belStrength, pass_through<PlaceStrength>, + pass_through<PlaceStrength>>::def_wrap(ci_cls, "belStrength"); + readonly_wrapper<CellInfo &, typeof(&CellInfo::pins), &CellInfo::pins, wrap_context<PinMap &>>::def_wrap(ci_cls, + "pins"); + + auto pi_cls = class_<ContextualWrapper<PortInfo &>>("PortInfo", no_init); + readwrite_wrapper<PortInfo &, typeof(&PortInfo::name), &PortInfo::name, conv_to_str<IdString>, + conv_from_str<IdString>>::def_wrap(pi_cls, "name"); + readonly_wrapper<PortInfo &, typeof(&PortInfo::net), &PortInfo::net, deref_and_wrap<NetInfo>>::def_wrap(pi_cls, + "net"); + readwrite_wrapper<PortInfo &, typeof(&PortInfo::type), &PortInfo::type, pass_through<PortType>, + pass_through<PortType>>::def_wrap(pi_cls, "type"); + + typedef std::vector<PortRef> PortVector; + typedef std::unordered_map<WireId, PipMap> WireMap; + + auto ni_cls = class_<ContextualWrapper<NetInfo &>>("NetInfo", no_init); + readwrite_wrapper<NetInfo &, typeof(&NetInfo::name), &NetInfo::name, conv_to_str<IdString>, + conv_from_str<IdString>>::def_wrap(ni_cls, "name"); + readwrite_wrapper<NetInfo &, typeof(&NetInfo::driver), &NetInfo::driver, wrap_context<PortRef &>, + unwrap_context<PortRef &>>::def_wrap(ni_cls, "driver"); + readonly_wrapper<NetInfo &, typeof(&NetInfo::users), &NetInfo::users, wrap_context<PortVector &>>::def_wrap( + ni_cls, "users"); + readonly_wrapper<NetInfo &, typeof(&NetInfo::wires), &NetInfo::wires, wrap_context<WireMap &>>::def_wrap(ni_cls, + "wires"); + + auto pr_cls = class_<ContextualWrapper<PortRef &>>("PortRef", no_init); + readonly_wrapper<PortRef &, typeof(&PortRef::cell), &PortRef::cell, deref_and_wrap<CellInfo>>::def_wrap(pr_cls, + "cell"); + readwrite_wrapper<PortRef &, typeof(&PortRef::port), &PortRef::port, conv_to_str<IdString>, + conv_from_str<IdString>>::def_wrap(pr_cls, "port"); + readwrite_wrapper<PortRef &, typeof(&PortRef::budget), &PortRef::budget, pass_through<delay_t>, + pass_through<delay_t>>::def_wrap(pr_cls, "budget"); def("parse_json", parse_json_shim); def("load_design", load_design_shim, return_value_policy<manage_new_object>()); - class_<IdString>("IdString") - .def("__str__", &IdString::global_str, return_value_policy<copy_const_reference>()) - .def(self < self) - .def(self == self); - arch_wrap_python(); + WRAP_MAP(AttrMap, pass_through<std::string>, "AttrMap"); + WRAP_MAP(PortMap, wrap_context<PortInfo &>, "PortMap"); + WRAP_MAP(PinMap, conv_to_str<IdString>, "PinMap"); - class_<Context, Context *, bases<Arch>, boost::noncopyable>("Context", no_init).def("checksum", &Context::checksum); + arch_wrap_python(); } static wchar_t *program; diff --git a/common/pybindings.h b/common/pybindings.h index 1565a138..c4d84442 100644 --- a/common/pybindings.h +++ b/common/pybindings.h @@ -36,50 +36,6 @@ NEXTPNR_NAMESPACE_BEGIN using namespace boost::python; -/* -A wrapper to enable custom type/ID to/from string conversions - */ -template <typename T> struct string_wrapper -{ - template <typename F> struct from_pystring_converter - { - from_pystring_converter() - { - converter::registry::push_back(&convertible, &construct, boost::python::type_id<T>()); - }; - - static void *convertible(PyObject *object) { return PyUnicode_Check(object) ? object : 0; } - - static void construct(PyObject *object, converter::rvalue_from_python_stage1_data *data) - { - const wchar_t *value = PyUnicode_AsUnicode(object); - const std::wstring value_ws(value); - if (value == 0) - throw_error_already_set(); - void *storage = ((boost::python::converter::rvalue_from_python_storage<T> *)data)->storage.bytes; - new (storage) T(fn(std::string(value_ws.begin(), value_ws.end()))); - data->convertible = storage; - } - - static F fn; - }; - - template <typename F> struct to_str_wrapper - { - static F fn; - - std::string str(T &x) { return fn(x); } - }; - - template <typename F1, typename F2> static void wrap(const char *type_name, F1 to_str_fn, F2 from_str_fn) - { - from_pystring_converter<F2>::fn = from_str_fn; - from_pystring_converter<F2>(); - to_str_wrapper<F1>::fn = to_str_fn; - class_<T>(type_name, no_init).def("__str__", to_str_wrapper<F1>::str); - }; -}; - std::string parse_python_exception(); template <typename Tn> void python_export_global(const char *name, Tn &x) @@ -106,6 +62,25 @@ void deinit_python(); void execute_python_file(const char *python_file); +// Defauld IdString conversions +namespace PythonConversion { + +template <> struct string_converter<IdString> +{ + inline IdString from_str(Context *ctx, std::string name) { return ctx->id(name); } + + inline std::string to_str(Context *ctx, IdString id) { return id.str(ctx); } +}; + +template <> struct string_converter<const IdString> +{ + inline IdString from_str(Context *ctx, std::string name) { return ctx->id(name); } + + inline std::string to_str(Context *ctx, IdString id) { return id.str(ctx); } +}; + +} // namespace PythonConversion + NEXTPNR_NAMESPACE_END #endif /* end of include guard: COMMON_PYBINDINGS_HH */ diff --git a/common/pycontainers.h b/common/pycontainers.h index 917f49e9..f4251558 100644 --- a/common/pycontainers.h +++ b/common/pycontainers.h @@ -24,10 +24,12 @@ #include <boost/python.hpp> #include <boost/python/suite/indexing/map_indexing_suite.hpp> #include <boost/python/suite/indexing/vector_indexing_suite.hpp> +#include <sstream> #include <stdexcept> #include <type_traits> #include <utility> #include "nextpnr.h" +#include "pywrappers.h" NEXTPNR_NAMESPACE_BEGIN @@ -37,18 +39,22 @@ inline void KeyError() { PyErr_SetString(PyExc_KeyError, "Key not found"); } /* A wrapper for a Pythonised nextpnr Iterator. The actual class wrapped is a -pair<Iterator, Iterator> containing (current, end) +pair<Iterator, Iterator> containing (current, end), wrapped in a ContextualWrapper + */ -template <typename T, typename P> struct iterator_wrapper +template <typename T, typename P, typename value_conv = PythonConversion::pass_through<T>> struct iterator_wrapper { typedef decltype(*(std::declval<T>())) value_t; - static value_t next(std::pair<T, T> &iter) + typedef PythonConversion::ContextualWrapper<std::pair<T, T>> wrapped_iter_t; + using return_t = typename value_conv::ret_type; + + static return_t next(wrapped_iter_t &iter) { - if (iter.first != iter.second) { - value_t val = *iter.first; - ++iter.first; + if (iter.base.first != iter.base.second) { + return_t val = value_conv()(iter.ctx, *iter.base.first); + ++iter.base.first; return val; } else { PyErr_SetString(PyExc_StopIteration, "End of range reached"); @@ -61,7 +67,7 @@ template <typename T, typename P> struct iterator_wrapper static void wrap(const char *python_name) { - class_<std::pair<T, T>>(python_name, no_init).def("__next__", next, P()); + class_<wrapped_iter_t>(python_name, no_init).def("__next__", next, P()); } }; @@ -71,22 +77,46 @@ and end() which return iterator-like objects supporting ++, * and != Full STL iterator semantics are not required, unlike the standard Boost wrappers */ -template <typename T, typename P = return_value_policy<return_by_value>> struct range_wrapper +template <typename T, typename P = return_value_policy<return_by_value>, + typename value_conv = PythonConversion::pass_through<T>> +struct range_wrapper { typedef decltype(std::declval<T>().begin()) iterator_t; + typedef decltype(*(std::declval<iterator_t>())) value_t; + typedef typename PythonConversion::ContextualWrapper<T> wrapped_range; + typedef typename PythonConversion::ContextualWrapper<std::pair<iterator_t, iterator_t>> wrapped_pair; + static wrapped_pair iter(wrapped_range &range) + { + return wrapped_pair(range.ctx, std::make_pair(range.base.begin(), range.base.end())); + } - static std::pair<iterator_t, iterator_t> iter(T &range) { return std::make_pair(range.begin(), range.end()); } + static std::string repr(wrapped_range &range) + { + PythonConversion::string_converter<value_t> conv; + bool first = true; + std::stringstream ss; + ss << "["; + for (const auto &item : range.base) { + if (!first) + ss << ", "; + ss << "'" << conv.to_str(range.ctx, item) << "'"; + first = false; + } + ss << "]"; + return ss.str(); + } static void wrap(const char *range_name, const char *iter_name) { - class_<T>(range_name, no_init).def("__iter__", iter); - iterator_wrapper<iterator_t, P>().wrap(iter_name); + class_<wrapped_range>(range_name, no_init).def("__iter__", iter).def("__repr__", repr); + iterator_wrapper<iterator_t, P, value_conv>().wrap(iter_name); } - typedef iterator_wrapper<iterator_t, P> iter_wrap; + typedef iterator_wrapper<iterator_t, P, value_conv> iter_wrap; }; -#define WRAP_RANGE(t) range_wrapper<t##Range>().wrap(#t "Range", #t "Iterator") +#define WRAP_RANGE(t, conv) \ + range_wrapper<t##Range, return_value_policy<return_by_value>, conv>().wrap(#t "Range", #t "Iterator") /* Wrapper for a pair, allows accessing either using C++-style members (.first and @@ -158,20 +188,23 @@ template <typename T1, typename T2> struct pair_wrapper /* Special case of above for map key/values */ -template <typename T1, typename T2> struct map_pair_wrapper +template <typename T1, typename T2, typename value_conv> struct map_pair_wrapper { typedef std::pair<T1, T2> T; + typedef PythonConversion::ContextualWrapper<T &> wrapped_pair; + typedef typename T::second_type V; struct pair_iterator_wrapper { - static object next(std::pair<T &, int> &iter) + static object next(std::pair<wrapped_pair &, int> &iter) { if (iter.second == 0) { iter.second++; - return object(iter.first.first); + return object(PythonConversion::string_converter<typeof(iter.first.base.first)>().to_str( + iter.first.ctx, iter.first.base.first)); } else if (iter.second == 1) { iter.second++; - return object(iter.first.second); + return object(value_conv()(iter.first.ctx, iter.first.base.second)); } else { PyErr_SetString(PyExc_StopIteration, "End of range reached"); boost::python::throw_error_already_set(); @@ -183,30 +216,37 @@ template <typename T1, typename T2> struct map_pair_wrapper static void wrap(const char *python_name) { - class_<std::pair<T &, int>>(python_name, no_init).def("__next__", next); + class_<std::pair<wrapped_pair &, int>>(python_name, no_init).def("__next__", next); } }; - static object get(T &x, int i) + static object get(wrapped_pair &x, int i) { if ((i >= 2) || (i < 0)) KeyError(); - return (i == 1) ? object(x.second) : object(x.first); + return (i == 1) ? object(value_conv()(x.ctx, x.base.second)) : object(x.base.first); } - static int len(T &x) { return 2; } + static int len(wrapped_pair &x) { return 2; } - static std::pair<T &, int> iter(T &x) { return std::make_pair(boost::ref(x), 0); }; + static std::pair<wrapped_pair &, int> iter(wrapped_pair &x) { return std::make_pair(boost::ref(x), 0); }; + + static std::string first_getter(wrapped_pair &t) + { + return PythonConversion::string_converter<typeof(t.base.first)>().to_str(t.ctx, t.base.first); + } + + static typename value_conv::ret_type second_getter(wrapped_pair &t) { return value_conv()(t.ctx, t.base.second); } static void wrap(const char *pair_name, const char *iter_name) { pair_iterator_wrapper::wrap(iter_name); - class_<T>(pair_name, no_init) + class_<wrapped_pair>(pair_name, no_init) .def("__iter__", iter) .def("__len__", len) .def("__getitem__", get) - .def_readonly("first", &T::first) - .def_readwrite("second", &T::second); + .add_property("first", first_getter) + .add_property("second", second_getter); } }; @@ -214,26 +254,35 @@ template <typename T1, typename T2> struct map_pair_wrapper Wrapper for a map, either an unordered_map, regular map or dict */ -template <typename T> struct map_wrapper +template <typename T, typename value_conv> struct map_wrapper { typedef typename std::remove_cv<typename std::remove_reference<typename T::key_type>::type>::type K; typedef typename T::mapped_type V; + typedef typename value_conv::ret_type wrapped_V; typedef typename T::value_type KV; + typedef typename PythonConversion::ContextualWrapper<T &> wrapped_map; - static V &get(T &x, K const &i) + static wrapped_V get(wrapped_map &x, std::string const &i) { - if (x.find(i) != x.end()) - return x.at(i); + K k = PythonConversion::string_converter<K>().from_str(x.ctx, i); + if (x.base.find(k) != x.base.end()) + return value_conv()(x.ctx, x.base.at(k)); KeyError(); std::terminate(); } - static void set(T &x, K const &i, V &v) { x[i] = v; } + static void set(wrapped_map &x, std::string const &i, V const &v) + { + x.base[PythonConversion::string_converter<K>().from_str(x.ctx, i)] = v; + } + + static size_t len(wrapped_map &x) { return x.base.size(); } - static void del(T const &x, K const &i) + static void del(T const &x, std::string const &i) { - if (x.find(i) != x.end()) - x.erase(i); + K k = PythonConversion::string_converter<K>().from_str(x.ctx, i); + if (x.base.find(k) != x.base.end()) + x.base.erase(k); else KeyError(); std::terminate(); @@ -241,13 +290,13 @@ template <typename T> struct map_wrapper static void wrap(const char *map_name, const char *kv_name, const char *kv_iter_name, const char *iter_name) { - map_pair_wrapper<typename KV::first_type, typename KV::second_type>::wrap(kv_name, kv_iter_name); - typedef range_wrapper<T, return_value_policy<copy_non_const_reference>> rw; + map_pair_wrapper<typename KV::first_type, typename KV::second_type, value_conv>::wrap(kv_name, kv_iter_name); + typedef range_wrapper<T &, return_value_policy<return_by_value>, PythonConversion::wrap_context<KV &>> rw; typename rw::iter_wrap().wrap(iter_name); - class_<T>(map_name, no_init) + class_<wrapped_map>(map_name, no_init) .def("__iter__", rw::iter) - .def("__len__", &T::size) - .def("__getitem__", get, return_internal_reference<>()) + .def("__len__", len) + .def("__getitem__", get) .def("__setitem__", set, with_custodian_and_ward<1, 2>()); } }; @@ -258,17 +307,20 @@ Special case of above for map key/values where value is a unique_ptr template <typename T1, typename T2> struct map_pair_wrapper_uptr { typedef std::pair<T1, T2> T; + typedef PythonConversion::ContextualWrapper<T &> wrapped_pair; typedef typename T::second_type::element_type V; + struct pair_iterator_wrapper { - static object next(std::pair<T &, int> &iter) + static object next(std::pair<wrapped_pair &, int> &iter) { if (iter.second == 0) { iter.second++; - return object(iter.first.first); + return object(PythonConversion::string_converter<typeof(iter.first.base.first)>().to_str( + iter.first.ctx, iter.first.base.first)); } else if (iter.second == 1) { iter.second++; - return object(iter.first.second.get()); + return object(PythonConversion::ContextualWrapper<V &>(iter.first.ctx, *iter.first.base.second.get())); } else { PyErr_SetString(PyExc_StopIteration, "End of range reached"); boost::python::throw_error_already_set(); @@ -280,32 +332,41 @@ template <typename T1, typename T2> struct map_pair_wrapper_uptr static void wrap(const char *python_name) { - class_<std::pair<T &, int>>(python_name, no_init).def("__next__", next); + class_<std::pair<wrapped_pair &, int>>(python_name, no_init).def("__next__", next); } }; - static object get(T &x, int i) + static object get(wrapped_pair &x, int i) { if ((i >= 2) || (i < 0)) KeyError(); - return (i == 1) ? object(x.second.get()) : object(x.first); + return (i == 1) ? object(PythonConversion::ContextualWrapper<V &>(x.ctx, *x.base.second.get())) + : object(x.base.first); } - static int len(T &x) { return 2; } + static int len(wrapped_pair &x) { return 2; } - static std::pair<T &, int> iter(T &x) { return std::make_pair(boost::ref(x), 0); }; + static std::pair<wrapped_pair &, int> iter(wrapped_pair &x) { return std::make_pair(boost::ref(x), 0); }; - static V &second_getter(T &t) { return *t.second.get(); } + static std::string first_getter(wrapped_pair &t) + { + return PythonConversion::string_converter<typeof(t.base.first)>().to_str(t.ctx, t.base.first); + } + + static PythonConversion::ContextualWrapper<V &> second_getter(wrapped_pair &t) + { + return PythonConversion::ContextualWrapper<V &>(t.ctx, *t.base.second.get()); + } static void wrap(const char *pair_name, const char *iter_name) { pair_iterator_wrapper::wrap(iter_name); - class_<T, boost::noncopyable>(pair_name, no_init) + class_<wrapped_pair>(pair_name, no_init) .def("__iter__", iter) .def("__len__", len) .def("__getitem__", get) - .def_readonly("first", &T::first) - .add_property("second", make_function(second_getter, return_internal_reference<>())); + .add_property("first", first_getter) + .add_property("second", second_getter); } }; @@ -317,22 +378,31 @@ template <typename T> struct map_wrapper_uptr { typedef typename std::remove_cv<typename std::remove_reference<typename T::key_type>::type>::type K; typedef typename T::mapped_type::pointer V; + typedef typename T::mapped_type::element_type &Vr; typedef typename T::value_type KV; + typedef typename PythonConversion::ContextualWrapper<T &> wrapped_map; - static V get(T &x, K const &i) + static PythonConversion::ContextualWrapper<Vr> get(wrapped_map &x, std::string const &i) { - if (x.find(i) != x.end()) - return x.at(i).get(); + K k = PythonConversion::string_converter<K>().from_str(x.ctx, i); + if (x.base.find(k) != x.base.end()) + return PythonConversion::ContextualWrapper<Vr>(x.ctx, *x.base.at(k).get()); KeyError(); std::terminate(); } - static void set(T &x, K const &i, V const &v) { x[i] = typename T::mapped_type(v); } + static void set(wrapped_map &x, std::string const &i, V const &v) + { + x.base[PythonConversion::string_converter<K>().from_str(x.ctx, i)] = typename T::mapped_type(v); + } + + static size_t len(wrapped_map &x) { return x.base.size(); } - static void del(T const &x, K const &i) + static void del(T const &x, std::string const &i) { - if (x.find(i) != x.end()) - x.erase(i); + K k = PythonConversion::string_converter<K>().from_str(x.ctx, i); + if (x.base.find(k) != x.base.end()) + x.base.erase(k); else KeyError(); std::terminate(); @@ -341,17 +411,18 @@ template <typename T> struct map_wrapper_uptr static void wrap(const char *map_name, const char *kv_name, const char *kv_iter_name, const char *iter_name) { map_pair_wrapper_uptr<typename KV::first_type, typename KV::second_type>::wrap(kv_name, kv_iter_name); - typedef range_wrapper<T, return_internal_reference<>> rw; + typedef range_wrapper<T &, return_value_policy<return_by_value>, PythonConversion::wrap_context<KV &>> rw; typename rw::iter_wrap().wrap(iter_name); - class_<T, boost::noncopyable>(map_name, no_init) + class_<wrapped_map>(map_name, no_init) .def("__iter__", rw::iter) - .def("__len__", &T::size) - .def("__getitem__", get, return_internal_reference<>()) + .def("__len__", len) + .def("__getitem__", get) .def("__setitem__", set, with_custodian_and_ward<1, 2>()); } }; -#define WRAP_MAP(t, name) map_wrapper<t>().wrap(#name, #name "KeyValue", #name "KeyValueIter", #name "Iterator") +#define WRAP_MAP(t, conv, name) \ + map_wrapper<t, conv>().wrap(#name, #name "KeyValue", #name "KeyValueIter", #name "Iterator") #define WRAP_MAP_UPTR(t, name) \ map_wrapper_uptr<t>().wrap(#name, #name "KeyValue", #name "KeyValueIter", #name "Iterator") diff --git a/common/pywrappers.h b/common/pywrappers.h index 2c91f26f..725caca8 100644 --- a/common/pywrappers.h +++ b/common/pywrappers.h @@ -41,65 +41,297 @@ template <typename T> struct ContextualWrapper Context *ctx; T base; - ContextualWrapper(Context *c, T &&x) : ctx(c), base(x){}; + inline ContextualWrapper(Context *c, T x) : ctx(c), base(x){}; - operator T() { return base; }; + inline operator T() { return base; }; typedef T base_type; }; +template <typename T> struct WrapIfNotContext +{ + typedef ContextualWrapper<T> maybe_wrapped_t; +}; + +template <> struct WrapIfNotContext<Context> +{ + typedef Context maybe_wrapped_t; +}; + +template <typename T> inline Context *get_ctx(typename WrapIfNotContext<T>::maybe_wrapped_t &wrp_ctx) +{ + return wrp_ctx.ctx; +} + +template <> inline Context *get_ctx<Context>(WrapIfNotContext<Context>::maybe_wrapped_t &unwrp_ctx) +{ + return &unwrp_ctx; +} + +template <typename T> inline T &get_base(typename WrapIfNotContext<T>::maybe_wrapped_t &wrp_ctx) +{ + return wrp_ctx.base; +} + +template <> inline Context &get_base<Context>(WrapIfNotContext<Context>::maybe_wrapped_t &unwrp_ctx) +{ + return unwrp_ctx; +} + template <typename T> ContextualWrapper<T> wrap_ctx(Context *ctx, T x) { return ContextualWrapper<T>(ctx, x); } // Dummy class, to be implemented by users -template <typename T> class string_converter; +template <typename T> struct string_converter; + +class bad_wrap +{ +}; // Action options -template <typename T> class do_nothing +template <typename T> struct pass_through { - T operator()(Context *ctx, T x) { return x; } + inline T operator()(Context *ctx, T x) { return x; } using ret_type = T; using arg_type = T; }; -template <typename T> class wrap_context +template <typename T> struct wrap_context { - ContextualWrapper<T> operator()(Context *ctx, T x) { return ContextualWrapper<T>(ctx, x); } + inline ContextualWrapper<T> operator()(Context *ctx, T x) { return ContextualWrapper<T>(ctx, x); } + using arg_type = T; using ret_type = ContextualWrapper<T>; }; -template <typename T> class unwrap_context +template <typename T> struct unwrap_context { - T operator()(Context *ctx, ContextualWrapper<T> x) { return x.base; } + inline T operator()(Context *ctx, ContextualWrapper<T> x) { return x.base; } + using ret_type = T; using arg_type = ContextualWrapper<T>; }; -template <typename T> class conv_from_string +template <typename T> struct conv_from_str { - T operator()(Context *ctx, std::string x) { return string_converter<T>().from_str(ctx, x); } + inline T operator()(Context *ctx, std::string x) { return string_converter<T>().from_str(ctx, x); } + using ret_type = T; using arg_type = std::string; }; -template <typename T> class conv_to_string +template <typename T> struct conv_to_str { - std::string operator()(Context *ctx, T x) { return string_converter<T>().to_str(ctx, x); } + inline std::string operator()(Context *ctx, T x) { return string_converter<T>().to_str(ctx, x); } + using ret_type = std::string; using arg_type = T; }; +template <typename T> struct deref_and_wrap +{ + inline ContextualWrapper<T &> operator()(Context *ctx, T *x) + { + if (x == nullptr) + throw bad_wrap(); + return ContextualWrapper<T &>(ctx, *x); + } + + using arg_type = T *; + using ret_type = ContextualWrapper<T &>; +}; + // Function wrapper -// Example: one parameter, one return -template <typename Class, typename FuncT, FuncT fn, typename rv_conv, typename arg1_conv> struct function_wrapper +// Zero parameters, one return +template <typename Class, typename FuncT, FuncT fn, typename rv_conv> struct fn_wrapper_0a { - using class_type = ContextualWrapper<Class>; + using class_type = typename WrapIfNotContext<Class>::maybe_wrapped_t; + using conv_result_type = typename rv_conv::ret_type; + + static conv_result_type wrapped_fn(class_type &cls) + { + Context *ctx = get_ctx<Class>(cls); + Class &base = get_base<Class>(cls); + return rv_conv()(ctx, (base.*fn)()); + } + + template <typename WrapCls> static void def_wrap(WrapCls cls_, const char *name) { cls_.def(name, wrapped_fn); } +}; + +// One parameter, one return +template <typename Class, typename FuncT, FuncT fn, typename rv_conv, typename arg1_conv> struct fn_wrapper_1a +{ + using class_type = typename WrapIfNotContext<Class>::maybe_wrapped_t; using conv_result_type = typename rv_conv::ret_type; using conv_arg1_type = typename arg1_conv::arg_type; static conv_result_type wrapped_fn(class_type &cls, conv_arg1_type arg1) { - return rv_conv()(cls.ctx, cls.base.*fn(arg1_conv()(cls.ctx, arg1))); + Context *ctx = get_ctx<Class>(cls); + Class &base = get_base<Class>(cls); + return rv_conv()(ctx, (base.*fn)(arg1_conv()(ctx, arg1))); + } + + template <typename WrapCls> static void def_wrap(WrapCls cls_, const char *name) { cls_.def(name, wrapped_fn); } +}; + +// Two parameters, one return +template <typename Class, typename FuncT, FuncT fn, typename rv_conv, typename arg1_conv, typename arg2_conv> +struct fn_wrapper_2a +{ + using class_type = typename WrapIfNotContext<Class>::maybe_wrapped_t; + using conv_result_type = typename rv_conv::ret_type; + using conv_arg1_type = typename arg1_conv::arg_type; + using conv_arg2_type = typename arg2_conv::arg_type; + + static conv_result_type wrapped_fn(class_type &cls, conv_arg1_type arg1, conv_arg2_type arg2) + { + Context *ctx = get_ctx<Class>(cls); + Class &base = get_base<Class>(cls); + return rv_conv()(ctx, (base.*fn)(arg1_conv()(ctx, arg1), arg2_conv()(ctx, arg2))); + } + + template <typename WrapCls> static void def_wrap(WrapCls cls_, const char *name) { cls_.def(name, wrapped_fn); } +}; + +// Three parameters, one return +template <typename Class, typename FuncT, FuncT fn, typename rv_conv, typename arg1_conv, typename arg2_conv, + typename arg3_conv> +struct fn_wrapper_3a +{ + using class_type = typename WrapIfNotContext<Class>::maybe_wrapped_t; + using conv_result_type = typename rv_conv::ret_type; + using conv_arg1_type = typename arg1_conv::arg_type; + using conv_arg2_type = typename arg2_conv::arg_type; + using conv_arg3_type = typename arg3_conv::arg_type; + + static conv_result_type wrapped_fn(class_type &cls, conv_arg1_type arg1, conv_arg2_type arg2, conv_arg3_type arg3) + { + Context *ctx = get_ctx<Class>(cls); + Class &base = get_base<Class>(cls); + return rv_conv()(ctx, (base.*fn)(arg1_conv()(ctx, arg1), arg2_conv()(ctx, arg2), arg3_conv()(ctx, arg3))); + } + + template <typename WrapCls> static void def_wrap(WrapCls cls_, const char *name) { cls_.def(name, wrapped_fn); } +}; + +// Zero parameters void +template <typename Class, typename FuncT, FuncT fn> struct fn_wrapper_0a_v +{ + using class_type = typename WrapIfNotContext<Class>::maybe_wrapped_t; + + static void wrapped_fn(class_type &cls) + { + Class &base = get_base<Class>(cls); + return (base.*fn)(); + } + + template <typename WrapCls> static void def_wrap(WrapCls cls_, const char *name) { cls_.def(name, wrapped_fn); } +}; + +// One parameter, void +template <typename Class, typename FuncT, FuncT fn, typename arg1_conv> struct fn_wrapper_1a_v +{ + using class_type = typename WrapIfNotContext<Class>::maybe_wrapped_t; + using conv_arg1_type = typename arg1_conv::arg_type; + + static void wrapped_fn(class_type &cls, conv_arg1_type arg1) + { + Context *ctx = get_ctx<Class>(cls); + Class &base = get_base<Class>(cls); + return (base.*fn)(arg1_conv()(ctx, arg1)); + } + + template <typename WrapCls> static void def_wrap(WrapCls cls_, const char *name) { cls_.def(name, wrapped_fn); } +}; + +// Two parameters, one return +template <typename Class, typename FuncT, FuncT fn, typename arg1_conv, typename arg2_conv> struct fn_wrapper_2a_v +{ + using class_type = typename WrapIfNotContext<Class>::maybe_wrapped_t; + using conv_arg1_type = typename arg1_conv::arg_type; + using conv_arg2_type = typename arg2_conv::arg_type; + + static void wrapped_fn(class_type &cls, conv_arg1_type arg1, conv_arg2_type arg2) + { + Context *ctx = get_ctx<Class>(cls); + Class &base = get_base<Class>(cls); + return (base.*fn)(arg1_conv()(ctx, arg1), arg2_conv()(ctx, arg2)); + } + + template <typename WrapCls> static void def_wrap(WrapCls cls_, const char *name) { cls_.def(name, wrapped_fn); } +}; + +// Three parameters, one return +template <typename Class, typename FuncT, FuncT fn, typename arg1_conv, typename arg2_conv, typename arg3_conv> +struct fn_wrapper_3a_v +{ + using class_type = typename WrapIfNotContext<Class>::maybe_wrapped_t; + using conv_arg1_type = typename arg1_conv::arg_type; + using conv_arg2_type = typename arg2_conv::arg_type; + using conv_arg3_type = typename arg3_conv::arg_type; + + static void wrapped_fn(class_type &cls, conv_arg1_type arg1, conv_arg2_type arg2, conv_arg3_type arg3) + { + Context *ctx = get_ctx<Class>(cls); + Class &base = get_base<Class>(cls); + return (base.*fn)(arg1_conv()(ctx, arg1), arg2_conv()(ctx, arg2), arg3_conv()(ctx, arg3)); + } + + template <typename WrapCls> static void def_wrap(WrapCls cls_, const char *name) { cls_.def(name, wrapped_fn); } +}; + +// Wrapped getter +template <typename Class, typename MemT, MemT mem, typename v_conv> struct readonly_wrapper +{ + using class_type = typename WrapIfNotContext<Class>::maybe_wrapped_t; + using conv_val_type = typename v_conv::ret_type; + + static object wrapped_getter(class_type &cls) + { + Context *ctx = get_ctx<Class>(cls); + Class &base = get_base<Class>(cls); + try { + return object(v_conv()(ctx, (base.*mem))); + } catch (bad_wrap &) { + return object(); + } + } + + template <typename WrapCls> static void def_wrap(WrapCls cls_, const char *name) + { + cls_.add_property(name, wrapped_getter); + } +}; + +// Wrapped getter/setter +template <typename Class, typename MemT, MemT mem, typename get_conv, typename set_conv> struct readwrite_wrapper +{ + using class_type = typename WrapIfNotContext<Class>::maybe_wrapped_t; + using conv_val_type = typename get_conv::ret_type; + + static object wrapped_getter(class_type &cls) + { + Context *ctx = get_ctx<Class>(cls); + Class &base = get_base<Class>(cls); + try { + return object(get_conv()(ctx, (base.*mem))); + } catch (bad_wrap &) { + return object(); + } + } + + using conv_arg_type = typename set_conv::arg_type; + + static void wrapped_setter(class_type &cls, conv_arg_type val) + { + Context *ctx = get_ctx<Class>(cls); + Class &base = get_base<Class>(cls); + (base.*mem) = set_conv()(ctx, val); + } + + template <typename WrapCls> static void def_wrap(WrapCls cls_, const char *name) + { + cls_.add_property(name, wrapped_getter, wrapped_setter); } }; |