Commit 967a395d authored by Xavier Thompson's avatar Xavier Thompson

Refactor acthon implementation

parent acf56eff
......@@ -934,8 +934,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
if entry.type.activable:
# Generate acthon-specific classes
self.generate_cyp_class_reifying_entries(entry, code)
self.generate_cyp_class_activated_class(entry, code)
self.generate_cyp_class_activate_function(entry, code)
self.generate_cyp_class_activated_methods(entry, code)
# Generate cypclass attr destructor
self.generate_cyp_class_attrs_destructor_definition(entry, code)
# Generate wrapper constructor
......@@ -964,29 +963,9 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
code.putln("Cy_XDECREF(this->%s);" % attr.cname)
code.putln("}")
def generate_cyp_class_activate_function(self, entry, code):
def generate_cyp_class_activated_methods(self, entry, code):
"""
Generate activate function for activable cypclass entries.
"""
class_decl = entry.type.empty_declaration_code()
activated_class_decl = "%s::Activated" % class_decl
code.putln("%s *%s::__activate__() {" % (activated_class_decl, class_decl))
code.putln("if (this->%s == NULL) {" % Naming.cypclass_active_self_cname)
code.putln("this->%s = new %s(this, %s);" % (
Naming.cypclass_active_self_cname,
activated_class_decl,
", ".join(["this->_active_queue_class", "this->_active_result_class"])
)
)
code.putln("}")
code.putln("Cy_INCREF((%s *)(this->%s));" % (activated_class_decl, Naming.cypclass_active_self_cname))
code.putln("return (%s *)(this->%s);" % (activated_class_decl, Naming.cypclass_active_self_cname))
code.putln("}")
def generate_cyp_class_activated_class(self, entry, code):
"""
Generate activated cypclass.
Generate activated cypclass methods.
"""
from . import Builtin
......@@ -996,31 +975,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
result_attr_cname = "_active_result_class"
queue_attr_cname = "_active_queue_class"
passive_self_attr_cname = Naming.builtin_prefix + entry.type.empty_declaration_code().replace('::', '__') + "_passive_self"
activable_bases_cnames = [base.cname for base in entry.type.base_classes if base.activable]
activable_bases_inheritance_list = ["public %s::Activated" % cname for cname in activable_bases_cnames]
if activable_bases_cnames:
base_classes_code = ", ".join(activable_bases_inheritance_list)
initialize_code = ", ".join([
"%s::Activated(passive_object, active_queue, active_result_constructor)" % cname
for cname in activable_bases_cnames
])
else:
base_classes_code = "public ActhonActivableClass"
initialize_code = "ActhonActivableClass(active_queue, active_result_constructor)"
code.putln("struct %s::Activated : %s {" % (entry.type.empty_declaration_code(), base_classes_code))
code.putln("%s;" % entry.type.declaration_code(passive_self_attr_cname))
result_constructor_type = PyrexTypes.CPtrType(PyrexTypes.CFuncType(result_interface_type, [], nogil = 1))
code.putln(("Activated(%s * passive_object, %s, %s)"
": %s, %s(passive_object){} // Used by _passive_self.__activate__()" % (
entry.type.empty_declaration_code(),
queue_interface_type.declaration_code("active_queue"),
result_constructor_type.declaration_code("active_result_constructor"),
initialize_code,
passive_self_attr_cname
)
))
for reified_function_entry in entry.type.scope.reified_entries:
reifying_class_name = "%s%s" % (Naming.cypclass_reified_prefix, reified_function_entry.name)
reifying_class_full_name = "%s::%s" % (PyrexTypes.namespace_declaration_code(entry.type), reifying_class_name)
......@@ -1040,12 +995,13 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
reified_arg_decl_list.append(reified_function_entry.type.op_arg_struct.declaration_code(opt_cname))
activated_method_arg_decl_code = ", ".join([sync_interface_type.declaration_code("sync_object")] + reified_arg_decl_list)
function_header = reified_function_entry.type.function_header_code(reified_function_entry.cname, activated_method_arg_decl_code)
active_entry = reified_function_entry.active_entry
function_header = active_entry.type.function_header_code(active_entry.func_cname, activated_method_arg_decl_code)
function_code = result_interface_type.declaration_code(function_header)
code.putln("%s {" % function_code)
code.putln("%s = this->%s();" % (result_interface_type.declaration_code("result_object"), result_attr_cname))
message_constructor_args_list = ["this->%s" % passive_self_attr_cname, "sync_object", "result_object"] + reified_arg_cname_list
message_constructor_args_list = ["this", "sync_object", "result_object"] + reified_arg_cname_list
message_constructor_args_code = ", ".join(message_constructor_args_list)
code.putln("%s * message = new %s(%s);" % (
reifying_class_full_name,
......@@ -1066,7 +1022,6 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
code.putln("/* Return result object */")
code.putln("return result_object;")
code.putln("}")
code.putln("};")
def generate_cyp_class_reifying_entries(self, entry, code):
"""
......@@ -1593,9 +1548,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
has_virtual_methods = False
constructor = None
destructor = None
if entry.type.is_cyp_class and entry.type.activable:
code.putln("struct Activated;")
code.putln("%s::Activated *__activate__();" % entry.type.empty_declaration_code())
for attr in scope.var_entries:
cname = attr.cname
if attr.is_mutable:
......@@ -1622,8 +1575,11 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
is_implementing = 'init_module' in code.globalstate.parts
for reified in scope.reified_entries:
# declare message class
reifying_class_name = "%s%s" % (Naming.cypclass_reified_prefix, reified.name)
code.putln("struct %s;" % reifying_class_name)
# declare active method
code.putln("virtual %s;" % reified.active_entry.type.declaration_code(reified.active_entry.cname))
def generate_cpp_constructor_code(arg_decls, arg_names, is_implementing, py_attrs, constructor):
if is_implementing:
......@@ -1751,6 +1707,8 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
or e.static_cname is not None) # mro-resolve the virtual methods used to dispatch static methods
and not e.type.has_varargs # avoid dealing with varargs for now (is this ever required anyway ?)
]
inherited_activated_methods = [e.active_entry for e in inherited_methods if e.active_entry is not None]
inherited_methods.extend(inherited_activated_methods)
if inherited_methods:
code.putln("")
code.putln("/* make all inherited (non overriden) methods resolve correctly according to the MRO */")
......
......@@ -172,6 +172,7 @@ cypclass_wrapper_layout_type = "CyPyObject"
# active cypclass
cypclass_reified_prefix = builtin_prefix + 'active_'
cypclass_active_func_prefix = func_prefix + 'active_'
cypclass_active_self_cname = "_active_self"
# the h and api guards get changed to:
......
......@@ -4802,12 +4802,6 @@ class QualifiedCypclassType(BaseType):
if for_display:
decl = self.qual_base_type.declaration_code(entity_code, for_display, dll_linkage, pyrex, template_params, deref)
return "%s %s" % (self.qualifier, decl)
if self.qualifier == 'active':
if not deref:
entity_code = "*%s" % entity_code
namespace_decl = namespace_declaration_code(self.qual_base_type)
return "%s::Activated %s" % (namespace_decl, entity_code)
else:
return self.qual_base_type.declaration_code(entity_code, for_display, dll_linkage, pyrex, template_params, deref)
def empty_declaration_code(self):
......
......@@ -178,7 +178,7 @@ class Entry(object):
#
# original_name string The original name of a cpp or cypclass method
#
# is_asyncable boolean Is a cypclass method that can be called asynchronously
# active_entry Entry Entry for the active version of an asyncable cypclass method
# TODO: utility_code and utility_code_definition serves the same purpose...
......@@ -256,7 +256,7 @@ class Entry(object):
from_type = None
static_cname = None
original_name = None
is_asyncable = False
active_entry = None
def __init__(self, name, cname, type, pos = None, init = None):
self.name = name
......@@ -2821,7 +2821,34 @@ class CppClassScope(Scope):
if entry.type.has_varargs:
error(entry.pos, "Could not reify method with ellipsis (you can use optional arguments)")
self.reified_entries.append(entry)
entry.is_asyncable = True
# create corresponding active entry
from . import Builtin
result_type = Builtin.acthon_result_type
sync_type = Builtin.acthon_sync_type
activated_method_sync_attr_type = PyrexTypes.CFuncTypeArg(
EncodedString("sync_method"),
PyrexTypes.CConstOrVolatileType(sync_type, is_const=1),
entry.pos,
"sync_method",
)
activated_method_type = PyrexTypes.CFuncType(
result_type,
[activated_method_sync_attr_type] + entry.type.args,
nogil=entry.type.nogil,
has_varargs = entry.type.has_varargs,
optional_arg_count = entry.type.optional_arg_count,
)
if hasattr(entry.type, 'op_arg_struct'):
activated_method_type.op_arg_struct = entry.type.op_arg_struct
activated_method_cname = "%s%s" % (Naming.cypclass_active_func_prefix, entry.cname)
activated_method_entry = Entry(entry.name, activated_method_cname, activated_method_type, entry.pos)
activated_method_entry.func_cname = "%s::%s" % (self.type.empty_declaration_code(), activated_method_cname)
activated_method_entry.visibility = 'extern'
activated_method_entry.scope = self
activated_method_entry.is_cfunction = 1
activated_method_entry.is_variable = 1
entry.active_entry = activated_method_entry
# Return the type declaration string if stripped_name corresponds to a known type, None otherwise.
# The returned string is intended to be used to build an operator of the form "operator <type name>".
......@@ -3255,32 +3282,15 @@ class ActiveCypclassScope(QualifiedCypclassScope):
def resolve(self, name):
base_entry = self.base_type_scope.lookup_here(name)
if base_entry is None or not base_entry.is_asyncable:
if base_entry is None or base_entry.active_entry is None:
return None
from . import Builtin
result_type = Builtin.acthon_result_type
sync_type = Builtin.acthon_sync_type
activated_method_sync_attr_type = PyrexTypes.CFuncTypeArg(
EncodedString("sync_method"),
PyrexTypes.CConstOrVolatileType(sync_type, is_const=1),
base_entry.pos,
"sync_method",
)
activated_method_type = PyrexTypes.CFuncType(
result_type,
[activated_method_sync_attr_type] + base_entry.type.args,
nogil=base_entry.type.nogil,
has_varargs = base_entry.type.has_varargs,
optional_arg_count = base_entry.type.optional_arg_count,
)
if hasattr(base_entry.type, 'op_arg_struct'):
activated_method_type.op_arg_struct = base_entry.type.op_arg_struct
activated_method_entry = Entry(base_entry.name, base_entry.cname, activated_method_type, base_entry.pos)
activated_method_entry.visibility = 'extern'
activated_method_entry.scope = self
activated_method_entry.is_cfunction = 1
activated_method_entry.is_variable = 1
return activated_method_entry
active_alternatives = []
for e in base_entry.all_alternatives():
# all alternatives should be equally activable
assert e.active_entry is not None
e.active_entry.overloaded_alternatives = active_alternatives
active_alternatives.append(e.active_entry)
return base_entry.active_entry
class TemplateScope(Scope):
......
......@@ -362,7 +362,6 @@
struct ActhonActivableClass : public CyObject {
ActhonQueueInterface *_active_queue_class = NULL;
void *_active_self = NULL;
ActhonResultInterface *(*_active_result_class)(void);
ActhonActivableClass(){} // Used in Activated classes inheritance chain (base Activated calls this, derived calls the 2 args version below)
ActhonActivableClass(ActhonQueueInterface * queue_object, ActhonResultInterface *(*result_constructor)(void));
......@@ -454,9 +453,10 @@
* Activate a passive Cyobject.
*/
template <typename T>
static inline typename T::Activated * activate(T * ob) {
static inline T * activate(T * ob) {
static_assert(std::is_convertible<T *, ActhonActivableClass *>::value, "wrong type for activate");
return ob->__activate__();
Cy_INCREF(ob);
return ob;
}
/*
......
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