python: Add context wrapper support for ranges
Signed-off-by: David Shah <davey1576@gmail.com>
This commit is contained in:
parent
4bc12f2ead
commit
1e96d65ded
@ -80,7 +80,7 @@ BOOST_PYTHON_MODULE(MODULE_NAME)
|
|||||||
.def_readwrite("attrs", &NetInfo::attrs)
|
.def_readwrite("attrs", &NetInfo::attrs)
|
||||||
.def_readwrite("wires", &NetInfo::wires);
|
.def_readwrite("wires", &NetInfo::wires);
|
||||||
|
|
||||||
WRAP_MAP(decltype(NetInfo::attrs), "IdStrMap");
|
// WRAP_MAP(decltype(NetInfo::attrs), "IdStrMap");
|
||||||
|
|
||||||
class_<std::vector<PortRef>>("PortRefVector").def(vector_indexing_suite<std::vector<PortRef>>());
|
class_<std::vector<PortRef>>("PortRefVector").def(vector_indexing_suite<std::vector<PortRef>>());
|
||||||
|
|
||||||
@ -104,15 +104,15 @@ BOOST_PYTHON_MODULE(MODULE_NAME)
|
|||||||
.def_readwrite("bel", &CellInfo::bel)
|
.def_readwrite("bel", &CellInfo::bel)
|
||||||
.def_readwrite("pins", &CellInfo::pins);
|
.def_readwrite("pins", &CellInfo::pins);
|
||||||
|
|
||||||
WRAP_MAP(decltype(CellInfo::ports), "IdPortMap");
|
// WRAP_MAP(decltype(CellInfo::ports), "IdPortMap");
|
||||||
// WRAP_MAP(decltype(CellInfo::pins), "IdIdMap");
|
// WRAP_MAP(decltype(CellInfo::pins), "IdIdMap");
|
||||||
|
|
||||||
class_<BaseCtx, BaseCtx *, boost::noncopyable>("BaseCtx", no_init)
|
class_<BaseCtx, BaseCtx *, boost::noncopyable>("BaseCtx", no_init)
|
||||||
.add_property("nets", make_getter(&Context::nets, return_internal_reference<>()))
|
.add_property("nets", make_getter(&Context::nets, return_internal_reference<>()))
|
||||||
.add_property("cells", make_getter(&Context::cells, 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::nets), "IdNetMap");
|
||||||
WRAP_MAP_UPTR(decltype(Context::cells), "IdCellMap");
|
// WRAP_MAP_UPTR(decltype(Context::cells), "IdCellMap");
|
||||||
|
|
||||||
def("parse_json", parse_json_shim);
|
def("parse_json", parse_json_shim);
|
||||||
def("load_design", load_design_shim, return_value_policy<manage_new_object>());
|
def("load_design", load_design_shim, return_value_policy<manage_new_object>());
|
||||||
@ -122,7 +122,6 @@ BOOST_PYTHON_MODULE(MODULE_NAME)
|
|||||||
.def(self < self)
|
.def(self < self)
|
||||||
.def(self == self);
|
.def(self == self);
|
||||||
arch_wrap_python();
|
arch_wrap_python();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static wchar_t *program;
|
static wchar_t *program;
|
||||||
|
@ -36,50 +36,6 @@ NEXTPNR_NAMESPACE_BEGIN
|
|||||||
|
|
||||||
using namespace boost::python;
|
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();
|
std::string parse_python_exception();
|
||||||
|
|
||||||
template <typename Tn> void python_export_global(const char *name, Tn &x)
|
template <typename Tn> void python_export_global(const char *name, Tn &x)
|
||||||
@ -106,6 +62,18 @@ void deinit_python();
|
|||||||
|
|
||||||
void execute_python_file(const char *python_file);
|
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); }
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace PythonConversion
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_END
|
NEXTPNR_NAMESPACE_END
|
||||||
|
|
||||||
#endif /* end of include guard: COMMON_PYBINDINGS_HH */
|
#endif /* end of include guard: COMMON_PYBINDINGS_HH */
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include "nextpnr.h"
|
#include "nextpnr.h"
|
||||||
|
#include "pywrappers.h"
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_BEGIN
|
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
|
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;
|
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) {
|
if (iter.base.first != iter.base.second) {
|
||||||
value_t val = *iter.first;
|
return_t val = value_conv()(iter.ctx, *iter.base.first);
|
||||||
++iter.first;
|
++iter.base.first;
|
||||||
return val;
|
return val;
|
||||||
} else {
|
} else {
|
||||||
PyErr_SetString(PyExc_StopIteration, "End of range reached");
|
PyErr_SetString(PyExc_StopIteration, "End of range reached");
|
||||||
@ -61,7 +66,7 @@ template <typename T, typename P> struct iterator_wrapper
|
|||||||
|
|
||||||
static void wrap(const char *python_name)
|
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 +76,29 @@ and end() which return iterator-like objects supporting ++, * and !=
|
|||||||
Full STL iterator semantics are not required, unlike the standard Boost wrappers
|
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<T>().begin()) iterator_t;
|
||||||
|
typedef typename PythonConversion::ContextualWrapper<T> wrapped_range;
|
||||||
static std::pair<iterator_t, iterator_t> iter(T &range) { return std::make_pair(range.begin(), range.end()); }
|
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 void wrap(const char *range_name, const char *iter_name)
|
static void wrap(const char *range_name, const char *iter_name)
|
||||||
{
|
{
|
||||||
class_<T>(range_name, no_init).def("__iter__", iter);
|
class_<wrapped_range>(range_name, no_init).def("__iter__", iter);
|
||||||
iterator_wrapper<iterator_t, P>().wrap(iter_name);
|
iterator_wrapper<iterator_t, P, value_conv>().wrap(iter_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef iterator_wrapper<iterator_t, P> iter_wrap;
|
typedef iterator_wrapper<iterator_t, P> 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
|
Wrapper for a pair, allows accessing either using C++-style members (.first and
|
||||||
@ -259,6 +271,7 @@ template <typename T1, typename T2> struct map_pair_wrapper_uptr
|
|||||||
{
|
{
|
||||||
typedef std::pair<T1, T2> T;
|
typedef std::pair<T1, T2> T;
|
||||||
typedef typename T::second_type::element_type V;
|
typedef typename T::second_type::element_type V;
|
||||||
|
|
||||||
struct pair_iterator_wrapper
|
struct pair_iterator_wrapper
|
||||||
{
|
{
|
||||||
static object next(std::pair<T &, int> &iter)
|
static object next(std::pair<T &, int> &iter)
|
||||||
|
@ -41,32 +41,37 @@ template <typename T> struct ContextualWrapper
|
|||||||
Context *ctx;
|
Context *ctx;
|
||||||
T base;
|
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; };
|
inline operator T() { return base; };
|
||||||
typedef T base_type;
|
typedef T base_type;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T> struct WrapIfNotContext {
|
template <typename T> struct WrapIfNotContext
|
||||||
|
{
|
||||||
typedef ContextualWrapper<T> maybe_wrapped_t;
|
typedef ContextualWrapper<T> maybe_wrapped_t;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <> struct WrapIfNotContext<Context> {
|
template <> struct WrapIfNotContext<Context>
|
||||||
|
{
|
||||||
typedef Context maybe_wrapped_t;
|
typedef Context maybe_wrapped_t;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename T> inline Context *get_ctx(typename WrapIfNotContext<T>::maybe_wrapped_t &wrp_ctx)
|
||||||
template <typename T> inline Context *get_ctx(typename WrapIfNotContext<T>::maybe_wrapped_t &wrp_ctx) {
|
{
|
||||||
return wrp_ctx.ctx;
|
return wrp_ctx.ctx;
|
||||||
}
|
}
|
||||||
template <> inline Context *get_ctx<Context>(WrapIfNotContext<Context>::maybe_wrapped_t &unwrp_ctx) {
|
template <> inline Context *get_ctx<Context>(WrapIfNotContext<Context>::maybe_wrapped_t &unwrp_ctx)
|
||||||
|
{
|
||||||
return &unwrp_ctx;
|
return &unwrp_ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T> inline T&get_base(typename WrapIfNotContext<T>::maybe_wrapped_t &wrp_ctx) {
|
template <typename T> inline T &get_base(typename WrapIfNotContext<T>::maybe_wrapped_t &wrp_ctx)
|
||||||
|
{
|
||||||
return wrp_ctx.base;
|
return wrp_ctx.base;
|
||||||
}
|
}
|
||||||
template <> inline Context &get_base<Context>(WrapIfNotContext<Context>::maybe_wrapped_t &unwrp_ctx) {
|
template <> inline Context &get_base<Context>(WrapIfNotContext<Context>::maybe_wrapped_t &unwrp_ctx)
|
||||||
|
{
|
||||||
return unwrp_ctx;
|
return unwrp_ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,7 +81,7 @@ template <typename T> ContextualWrapper<T> wrap_ctx(Context *ctx, T x) { return
|
|||||||
template <typename T> struct string_converter;
|
template <typename T> struct string_converter;
|
||||||
|
|
||||||
// Action options
|
// Action options
|
||||||
template <typename T> struct do_nothing
|
template <typename T> struct pass_through
|
||||||
{
|
{
|
||||||
inline T operator()(Context *ctx, T x) { return x; }
|
inline T operator()(Context *ctx, T x) { return x; }
|
||||||
|
|
||||||
@ -113,8 +118,23 @@ template <typename T> struct conv_to_str
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Function wrapper
|
// Function wrapper
|
||||||
// Example: one parameter, one return
|
// Zero parameters, one return
|
||||||
template <typename Class, typename FuncT, FuncT fn, typename rv_conv, typename arg1_conv> struct fn_wrapper
|
template <typename Class, typename FuncT, FuncT fn, typename rv_conv> struct fn_wrapper_0a
|
||||||
|
{
|
||||||
|
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 class_type = typename WrapIfNotContext<Class>::maybe_wrapped_t;
|
||||||
using conv_result_type = typename rv_conv::ret_type;
|
using conv_result_type = typename rv_conv::ret_type;
|
||||||
|
@ -27,24 +27,18 @@ NEXTPNR_NAMESPACE_BEGIN
|
|||||||
|
|
||||||
namespace PythonConversion {
|
namespace PythonConversion {
|
||||||
|
|
||||||
template<>
|
template <> struct string_converter<BelId>
|
||||||
struct string_converter<BelId>
|
|
||||||
{
|
{
|
||||||
BelId from_str(Context *ctx, std::string name)
|
BelId from_str(Context *ctx, std::string name) { return ctx->getBelByName(ctx->id(name)); }
|
||||||
{ return ctx->getBelByName(ctx->id(name)); }
|
|
||||||
|
|
||||||
std::string to_str(Context *ctx, BelId id)
|
std::string to_str(Context *ctx, BelId id) { return ctx->getBelName(id).str(ctx); }
|
||||||
{ return ctx->getBelName(id).str(ctx); }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template<>
|
template <> struct string_converter<BelType>
|
||||||
struct string_converter<BelType>
|
|
||||||
{
|
{
|
||||||
BelType from_str(Context *ctx, std::string name)
|
BelType from_str(Context *ctx, std::string name) { return ctx->belTypeFromId(ctx->id(name)); }
|
||||||
{ return ctx->belTypeFromId(ctx->id(name)); }
|
|
||||||
|
|
||||||
std::string to_str(Context *ctx, BelType typ)
|
std::string to_str(Context *ctx, BelType typ) { return ctx->belTypeToId(typ).str(ctx); }
|
||||||
{ return ctx->belTypeToId(typ).str(ctx); }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace PythonConversion
|
} // namespace PythonConversion
|
||||||
@ -80,11 +74,15 @@ void arch_wrap_python()
|
|||||||
#undef X
|
#undef X
|
||||||
|
|
||||||
auto arch_cls = class_<Arch, Arch *, bases<BaseCtx>, boost::noncopyable>("Arch", init<ArchArgs>());
|
auto arch_cls = class_<Arch, Arch *, bases<BaseCtx>, boost::noncopyable>("Arch", init<ArchArgs>());
|
||||||
auto ctx_cls = class_<Context, Context *, bases<Arch>, boost::noncopyable>("Context", no_init).def("checksum",
|
auto ctx_cls = class_<Context, Context *, bases<Arch>, boost::noncopyable>("Context", no_init)
|
||||||
&Context::checksum);
|
.def("checksum", &Context::checksum);
|
||||||
fn_wrapper<Context, typeof(&Context::getBelType), &Context::getBelType, conv_to_str<BelType>,
|
|
||||||
conv_from_str<BelId>>::def_wrap(ctx_cls, "getBelType");
|
|
||||||
|
|
||||||
|
fn_wrapper_1a<Context, typeof(&Context::getBelType), &Context::getBelType, conv_to_str<BelType>,
|
||||||
|
conv_from_str<BelId>>::def_wrap(ctx_cls, "getBelType");
|
||||||
|
fn_wrapper_1a<Context, typeof(&Context::checkBelAvail), &Context::checkBelAvail, pass_through<bool>,
|
||||||
|
conv_from_str<BelId>>::def_wrap(ctx_cls, "checkBelAvail");
|
||||||
|
fn_wrapper_0a<Context, typeof(&Context::getBels), &Context::getBels, wrap_context<BelRange>>::def_wrap(
|
||||||
|
ctx_cls, "getBels");
|
||||||
/*
|
/*
|
||||||
.def("getBelByName", &Arch::getBelByName)
|
.def("getBelByName", &Arch::getBelByName)
|
||||||
.def("getWireByName", &Arch::getWireByName)
|
.def("getWireByName", &Arch::getWireByName)
|
||||||
@ -108,12 +106,11 @@ void arch_wrap_python()
|
|||||||
.def("estimateDelay", &Arch::estimateDelay);
|
.def("estimateDelay", &Arch::estimateDelay);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
WRAP_RANGE(Bel, conv_to_str<BelId>);
|
||||||
WRAP_RANGE(Bel);
|
// WRAP_RANGE(BelPin);
|
||||||
WRAP_RANGE(BelPin);
|
// WRAP_RANGE(Wire);
|
||||||
WRAP_RANGE(Wire);
|
// WRAP_RANGE(AllPip);
|
||||||
WRAP_RANGE(AllPip);
|
// WRAP_RANGE(Pip);
|
||||||
WRAP_RANGE(Pip);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_END
|
NEXTPNR_NAMESPACE_END
|
||||||
|
Loading…
Reference in New Issue
Block a user