From 1e96d65ded029f68bb294cfb25c56f138dd51180 Mon Sep 17 00:00:00 2001 From: David Shah Date: Mon, 2 Jul 2018 15:59:18 +0200 Subject: python: Add context wrapper support for ranges Signed-off-by: David Shah --- common/pybindings.cc | 9 ++++----- common/pybindings.h | 56 +++++++++++---------------------------------------- common/pycontainers.h | 39 +++++++++++++++++++++++------------ common/pywrappers.h | 44 +++++++++++++++++++++++++++++----------- 4 files changed, 74 insertions(+), 74 deletions(-) (limited to 'common') diff --git a/common/pybindings.cc b/common/pybindings.cc index 329bcf1e..1746c517 100644 --- a/common/pybindings.cc +++ b/common/pybindings.cc @@ -80,7 +80,7 @@ BOOST_PYTHON_MODULE(MODULE_NAME) .def_readwrite("attrs", &NetInfo::attrs) .def_readwrite("wires", &NetInfo::wires); - WRAP_MAP(decltype(NetInfo::attrs), "IdStrMap"); + // WRAP_MAP(decltype(NetInfo::attrs), "IdStrMap"); class_>("PortRefVector").def(vector_indexing_suite>()); @@ -104,15 +104,15 @@ BOOST_PYTHON_MODULE(MODULE_NAME) .def_readwrite("bel", &CellInfo::bel) .def_readwrite("pins", &CellInfo::pins); - WRAP_MAP(decltype(CellInfo::ports), "IdPortMap"); + // WRAP_MAP(decltype(CellInfo::ports), "IdPortMap"); // WRAP_MAP(decltype(CellInfo::pins), "IdIdMap"); class_("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"); + // WRAP_MAP_UPTR(decltype(Context::nets), "IdNetMap"); + // WRAP_MAP_UPTR(decltype(Context::cells), "IdCellMap"); def("parse_json", parse_json_shim); def("load_design", load_design_shim, return_value_policy()); @@ -122,7 +122,6 @@ BOOST_PYTHON_MODULE(MODULE_NAME) .def(self < self) .def(self == self); arch_wrap_python(); - } static wchar_t *program; diff --git a/common/pybindings.h b/common/pybindings.h index 1565a138..852fb21f 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 struct string_wrapper -{ - template struct from_pystring_converter - { - from_pystring_converter() - { - converter::registry::push_back(&convertible, &construct, boost::python::type_id()); - }; - - 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 *)data)->storage.bytes; - new (storage) T(fn(std::string(value_ws.begin(), value_ws.end()))); - data->convertible = storage; - } - - static F fn; - }; - - template struct to_str_wrapper - { - static F fn; - - std::string str(T &x) { return fn(x); } - }; - - template static void wrap(const char *type_name, F1 to_str_fn, F2 from_str_fn) - { - from_pystring_converter::fn = from_str_fn; - from_pystring_converter(); - to_str_wrapper::fn = to_str_fn; - class_(type_name, no_init).def("__str__", to_str_wrapper::str); - }; -}; - std::string parse_python_exception(); template void python_export_global(const char *name, Tn &x) @@ -106,6 +62,18 @@ void deinit_python(); void execute_python_file(const char *python_file); +// Defauld IdString conversions +namespace PythonConversion { + +template <> struct string_converter +{ + 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..e1a73d75 100644 --- a/common/pycontainers.h +++ b/common/pycontainers.h @@ -28,6 +28,7 @@ #include #include #include "nextpnr.h" +#include "pywrappers.h" NEXTPNR_NAMESPACE_BEGIN @@ -37,18 +38,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 containing (current, end) +pair containing (current, end), wrapped in a ContextualWrapper + */ -template struct iterator_wrapper +template > struct iterator_wrapper { typedef decltype(*(std::declval())) value_t; - static value_t next(std::pair &iter) + typedef PythonConversion::ContextualWrapper> 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 +66,7 @@ template struct iterator_wrapper static void wrap(const char *python_name) { - class_>(python_name, no_init).def("__next__", next, P()); + class_(python_name, no_init).def("__next__", next, P()); } }; @@ -71,22 +76,29 @@ and end() which return iterator-like objects supporting ++, * and != Full STL iterator semantics are not required, unlike the standard Boost wrappers */ -template > struct range_wrapper +template , + typename value_conv = PythonConversion::pass_through> +struct range_wrapper { typedef decltype(std::declval().begin()) iterator_t; - - static std::pair iter(T &range) { return std::make_pair(range.begin(), range.end()); } + typedef typename PythonConversion::ContextualWrapper wrapped_range; + typedef typename PythonConversion::ContextualWrapper> wrapped_pair; + static wrapped_pair iter(wrapped_range &range) + { + return wrapped_pair(range.ctx, std::make_pair(range.base.begin(), range.base.end())); + } static void wrap(const char *range_name, const char *iter_name) { - class_(range_name, no_init).def("__iter__", iter); - iterator_wrapper().wrap(iter_name); + class_(range_name, no_init).def("__iter__", iter); + iterator_wrapper().wrap(iter_name); } typedef iterator_wrapper iter_wrap; }; -#define WRAP_RANGE(t) range_wrapper().wrap(#t "Range", #t "Iterator") +#define WRAP_RANGE(t, conv) \ + range_wrapper, conv>().wrap(#t "Range", #t "Iterator") /* Wrapper for a pair, allows accessing either using C++-style members (.first and @@ -259,6 +271,7 @@ template struct map_pair_wrapper_uptr { typedef std::pair T; typedef typename T::second_type::element_type V; + struct pair_iterator_wrapper { static object next(std::pair &iter) diff --git a/common/pywrappers.h b/common/pywrappers.h index 5b0146ac..55d70e42 100644 --- a/common/pywrappers.h +++ b/common/pywrappers.h @@ -41,32 +41,37 @@ template struct ContextualWrapper Context *ctx; T base; - inline ContextualWrapper(Context *c, T &&x) : ctx(c), base(x){}; + inline ContextualWrapper(Context *c, T x) : ctx(c), base(x){}; inline operator T() { return base; }; typedef T base_type; }; -template struct WrapIfNotContext { - typedef ContextualWrapper maybe_wrapped_t; +template struct WrapIfNotContext +{ + typedef ContextualWrapper maybe_wrapped_t; }; -template <> struct WrapIfNotContext { +template <> struct WrapIfNotContext +{ typedef Context maybe_wrapped_t; }; - -template inline Context *get_ctx(typename WrapIfNotContext::maybe_wrapped_t &wrp_ctx) { +template inline Context *get_ctx(typename WrapIfNotContext::maybe_wrapped_t &wrp_ctx) +{ return wrp_ctx.ctx; } -template <> inline Context *get_ctx(WrapIfNotContext::maybe_wrapped_t &unwrp_ctx) { +template <> inline Context *get_ctx(WrapIfNotContext::maybe_wrapped_t &unwrp_ctx) +{ return &unwrp_ctx; } -template inline T&get_base(typename WrapIfNotContext::maybe_wrapped_t &wrp_ctx) { +template inline T &get_base(typename WrapIfNotContext::maybe_wrapped_t &wrp_ctx) +{ return wrp_ctx.base; } -template <> inline Context &get_base(WrapIfNotContext::maybe_wrapped_t &unwrp_ctx) { +template <> inline Context &get_base(WrapIfNotContext::maybe_wrapped_t &unwrp_ctx) +{ return unwrp_ctx; } @@ -76,7 +81,7 @@ template ContextualWrapper wrap_ctx(Context *ctx, T x) { return template struct string_converter; // Action options -template struct do_nothing +template struct pass_through { inline T operator()(Context *ctx, T x) { return x; } @@ -113,8 +118,23 @@ template struct conv_to_str }; // Function wrapper -// Example: one parameter, one return -template struct fn_wrapper +// Zero parameters, one return +template struct fn_wrapper_0a +{ + using class_type = typename WrapIfNotContext::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(cls); + Class &base = get_base(cls); + return rv_conv()(ctx, (base.*fn)()); + } + + template static void def_wrap(WrapCls cls_, const char *name) { cls_.def(name, wrapped_fn); } +}; +// One parameter, one return +template struct fn_wrapper_1a { using class_type = typename WrapIfNotContext::maybe_wrapped_t; using conv_result_type = typename rv_conv::ret_type; -- cgit v1.2.3