Commit c329db8f authored by Xavier Thompson's avatar Xavier Thompson

Implement runtime 'iso' check for generic containers

parent e1939449
......@@ -977,6 +977,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
scope = entry.type.scope
check_cypclass_attrs = []
check_template_attrs = []
check_cpp_attrs = []
for e in scope.entries.values():
if e.is_type or e.name == "this":
continue
......@@ -984,6 +985,8 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
check_cypclass_attrs.append(e)
elif e.type.is_template_typename:
check_template_attrs.append(e)
elif e.type.is_cpp_class and not e.type.is_cyp_class:
check_cpp_attrs.append(e)
# potential template
if entry.type.templates:
templates_code = "template <typename %s>" % ", typename ".join(t.name for t in entry.type.templates)
......@@ -999,13 +1002,15 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
code.putln("visit(this->%s, arg);" % attr.cname)
for attr in check_template_attrs:
code.putln("__Pyx_CyObject_visit_template(visit, this->%s, arg);" % attr.cname)
for attr in check_cpp_attrs:
code.putln("__Pyx_CyObject_visit_generic(visit, this->%s, arg);" % attr.cname)
code.putln("}")
# isolation check method
if templates_code:
code.putln(templates_code)
code.putln("int %s::CyObject_iso() const" % namespace)
code.putln("{")
if check_cypclass_attrs or check_template_attrs:
if check_cypclass_attrs or check_template_attrs or check_cpp_attrs:
code.putln("return __Pyx_CyObject_owning(this) == 1;")
else:
code.putln("return this->CyObject_GETREF() == 1;")
......
......@@ -517,6 +517,52 @@
visit(o.uobj, arg);
}
/*
* Traverse generic containers.
*/
template<typename... Ts> struct Cy_make_void { typedef void type;};
template<typename... Ts> using Cy_void_t = typename Cy_make_void<Ts...>::type; // C++11 compatible version of std::void_t
template <typename T, typename = void>
struct Cy_is_iterable : std::false_type {};
template <typename T>
struct Cy_is_iterable<
T, Cy_void_t<
decltype(std::begin(std::declval<T>()) != std::end(std::declval<T>())),
decltype(++std::begin(std::declval<T>())),
decltype(*std::begin(std::declval<T>()))
>
> : std::true_type {};
template <typename T>
struct Cy_is_pair: std::false_type {};
template <typename ... Ts>
struct Cy_is_pair<std::pair<Ts...>> : std::true_type {};
template <typename T, typename std::enable_if<Cy_traverse_iso<T>::value, int>::type = 0>
static inline void __Pyx_CyObject_visit_generic(void (*visit)(const CyObject *o, void*arg), const T& o, void *arg) {
visit(o.uobj, arg);
}
template <typename T, typename std::enable_if<Cy_is_iterable<T>::value, int>::type = 0>
static inline void __Pyx_CyObject_visit_generic(void (*visit)(const CyObject *o, void*arg), const T& o, void *arg) {
for (auto& e : o) {
__Pyx_CyObject_visit_generic(visit, e, arg);
}
}
template <typename T, typename std::enable_if<Cy_is_pair<T>::value, int>::type = 0>
static inline void __Pyx_CyObject_visit_generic(void (*visit)(const CyObject *o, void*arg), const T& o, void *arg) {
__Pyx_CyObject_visit_generic(visit, o.first, arg);
__Pyx_CyObject_visit_generic(visit, o.second, arg);
}
template <typename T, typename std::enable_if<
!Cy_is_pair<T>::value && !Cy_is_iterable<T>::value && !Cy_traverse_iso<T>::value, int
>::type = 0>
static inline void __Pyx_CyObject_visit_generic(void (*visit)(const CyObject *o, void*arg), const T& o, void *arg) {}
/*
* Visit callback to collect reachable fields.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment