Re: [pygccxml-development] Implicit virtual functions in derived classes
Brought to you by:
mbaas,
roman_yakovenko
From: Roman Y. <rom...@gm...> - 2008-02-16 18:52:22
|
On Feb 16, 2008 9:56 AM, Roman Yakovenko <rom...@gm...> wrote: > > On Sat, Feb 16, 2008 at 8:58 AM, Julian Scheid <jul...@rs...> wrote: > > Julian Scheid wrote: > > > Due to the way funcs.update works (?) this will put A.foo into "funcs" > > > instead of B.foo when generating the wrapper for C. This in turn will > > > lead to the following wrapper code for class C to be generated: > > > > To elaborate, the order in which "A::foo" and "B::foo" are traversed in > > the "for f in funcs" loop depends on details of Python's Hashset > > implementation - they might or might not be traversed in the right order > > depending on how they are hashed. The right order being B::foo first and > > then A::foo second so that B::foo is added and A::foo is later rejected > > when tested with is_same_function. > > > > I haven't actually checked how things turn out for my hypothetical > > example from the previous mail, if you can't reproduce it using that > > example try using different class names (swapping A and B so that A is > > derived from B and C is derived from A should do the trick). > > > > I found that this problem can be avoided simply by using a list instead > > of a set for "funcs" and extend'ing it instead of update'ing it. While > > possibly a tad less efficient, this seems to work fine and guarantees > > that later on the right superclass is used. > > > > There is another intricacy. In the previous example (with classes A, B > > and C) consider that mb.class_("B").member_functions("foo").exclude() > > has been called. Now, if you use "not ignored and exportable" in the > > query as I suggested originally, what happens is that only A.foo ends up > > in "funcs" and the generated code for C_wrapper will incorrectly > > dispatch to A::foo. What works better is either to disregard whether or > > not a function is marked as ignore (downside being that exclude won't > > affect derived classes) or, better, to filter the resulting list > > "functions" at the very end of "redefined_funcs" and remove all methods > > that are marked as ignore. > > > > My final results are attached as a patch. It seems to solve all issues > > except for the overhead problem. (I was wrong about the static modifier > > - this turned out not to be necessary.) > > > > Cheers, > > > > Julian > > > > --- class_wrapper.py 2008-02-16 17:52:10.000000000 +1100 > > +++ class_wrapper_derived_virtuals.py 2008-02-16 17:53:30.000000000 +1100 > > @@ -442,19 +442,20 @@ > > all_included = declarations.custom_matcher_t( lambda decl: decl.ignore == False and decl.exportable ) > > all_protected = declarations.access_type_matcher_t( 'protected' ) & all_included > > all_pure_virtual = declarations.virtuality_type_matcher_t( VIRTUALITY_TYPES.PURE_VIRTUAL ) > > - all_not_pure_virtual = ~all_pure_virtual > > + all_virtual = declarations.virtuality_type_matcher_t( VIRTUALITY_TYPES.VIRTUAL ) & (declarations.access_type_matcher_t( 'public' ) | declarations.access_type_matcher_t( 'protected' )) > > + all_not_pure_virtual = ~(all_pure_virtual | all_virtual) > > > > query = all_protected | all_pure_virtual > > relevant_opers = declarations.custom_matcher_t( lambda decl: decl.symbol in ('()', '[]') ) > > - funcs = set() > > + funcs = [] > > defined_funcs = set() > > > > for base in self.recursive_bases: > > if base.access == ACCESS_TYPES.PRIVATE: > > continue > > base_cls = base.related_class > > - funcs.update( base_cls.member_functions( query, allow_empty=True ) ) > > - funcs.update( base_cls.member_operators( relevant_opers & query, allow_empty=True ) ) > > + funcs.extend( base_cls.member_functions( query | (all_virtual & declarations.custom_matcher_t( lambda decl: decl.parent.alias == base_cls.alias )), allow_empty=True ) ) > > + funcs.extend( base_cls.member_operators( relevant_opers & query, allow_empty=True ) ) > > > > defined_funcs.update( base_cls.member_functions( all_not_pure_virtual, allow_empty=True ) ) > > defined_funcs.update( base_cls.member_operators( all_not_pure_virtual & relevant_opers, allow_empty=True ) ) > > @@ -481,7 +482,7 @@ > > break > > else: > > not_reimplemented_funcs.add( f ) > > - functions = list( not_reimplemented_funcs ) > > + functions = filter( lambda f: not f.ignore and f.exportable, list( not_reimplemented_funcs ) ) > > functions.sort( cmp=lambda f1, f2: cmp( ( f1.name, f1.location.as_tuple() ) > > , ( f2.name, f2.location.as_tuple() ) ) ) > > self._redefined_funcs = functions > > > > > > Thank you very much!!! > > I am learning your patch and run through all my tests. If everything > is okey I will commit it today. Can I ask you to submit some kind of unit test - something very simple, that will map your class hierarchy. I would like to be sure next time I touch the code the things will continue to work. Thanks -- Roman Yakovenko C++ Python language binding http://www.language-binding.net/ |