There are still things to be improved, but at least we have (almost)
all the desired functionality. The missing features that I can see
are:
- handling multiple inheritance (both declaration of super classes and
recursive retrieval of vtypes);
- using exact() in typeof_ to fetch vtypes from the exact static type
(needs mlc::any).
I'll try to factor this code (some incriminated sections have been
tagged as such).
https://svn.lrde.epita.fr/svn/oln/trunk
Index: ChangeLog
from Roland Levillain <roland(a)lrde.epita.fr>
Revamp the virtual types (aka properties) system.
No longer use the C++'s inheritance mechanism to ``pack'' the
internal vtypes of a class. Rely on a metacode algorithm to
recursively look for vtypes in internal and external vtypes
instead, using both the super link and a ``pseudosuper'' link to
visit the upper classes. The set/get classes have been replaced
by a single class (in fact, by two classes, one for internal
vtypes, the other for external vtypes). The pseudosuper link is
used to inherit (or fetch) the vtypes from a given class, without
needing to inherit from this class.
* metalic/mlc/properties.hh (mlc_equip_namespace_with_properties):
Rewrite this macro.
(set_types, set_ext_types): Rename as...
(vtypes, ext_vtypes): ...this.
(get_types, get_ext_type): Remove.
* metalic/tests/properties.cc: Update the test.
Check for new cases (external vtype, pseudo inheritance of
vtypes).
(rec_get_vtype, rec_get_ext_vtype): New.
This class holds the algorithm for the recursive retrieval of
internal/external vtypes.
(typeof_): Adjust.
mlc/properties.hh | 281 +++++++++++++++++++++++++++++++++++-----------------
tests/properties.cc | 95 ++++++++++++-----
2 files changed, 261 insertions(+), 115 deletions(-)
Index: metalic/tests/properties.cc
--- metalic/tests/properties.cc (revision 413)
+++ metalic/tests/properties.cc (working copy)
@@ -14,22 +14,23 @@
namespace my
{
- /*----------------------.
- | Namespace equipment. |
- `----------------------*/
-
- mlc_equip_namespace_with_properties();
-
-
/*-----------.
| Typedefs. |
`-----------*/
- mlc_decl_typedef(ptr_type);
mlc_decl_typedef(foo_type);
mlc_decl_typedef(bar_type);
mlc_decl_typedef(baz_type);
mlc_decl_typedef(quux_type);
+ mlc_decl_typedef(yin_type);
+ mlc_decl_typedef(zorg_type);
+
+
+ /*----------------------.
+ | Namespace equipment. |
+ `----------------------*/
+
+ mlc_equip_namespace_with_properties();
/*-----------.
@@ -43,7 +44,6 @@
}
-
/*----.
| A. |
`----*/
@@ -51,10 +51,9 @@
// Forward declaration.
struct A;
- // FIXME: Rename as set_types<> when mlc/properties.hh is updated.
- // Associated types.
+ /// Types associated to my::A.
template<>
- struct set_types<category::my_cat, my::A>
+ struct vtypes<category::my_cat, my::A>
{
typedef int foo_type;
typedef float bar_type;
@@ -80,47 +79,93 @@
// Warning, this sugar might me remove from properties.hh.
mlc_set_super(B, A);
- /// \brief Redefined types associated to \a B.
- ///
- /// Keeping the inheritance is absolutely capital here (i.e., when
- /// you redefine an associated type with redefine_types).
+ /// Types associated to my::B.
template<>
- struct redefine_types<category::my_cat, B> :
- mlc_super_types_(category::my_cat, B)
+ struct vtypes<category::my_cat, B>
{
+ // (foo is left untouched.)
+
// A type redefined here.
typedef double bar_type;
// A type defined here (but declared abstract in the super class).
typedef char baz_type;
+ // A type defined only here (and not in the super class).
+ typedef long quux_type;
};
- /// \brief New types associated to \a B.
+ /// An external type associated to my::B.
template<>
- struct set_types<category::my_cat, B>
+ struct ext_vtype<category::my_cat, B, typedef_::yin_type>
{
- // A type defined only here (and not in the super class).
- typedef long quux_type;
+ typedef unsigned long ret;
};
- struct B : public mlc_super(B)
+ struct B : public mlc_super_(B)
{
// Aliases.
typedef my_type_of_(B, foo) foo_type;
typedef my_type_of_(B, bar) bar_type;
typedef my_type_of_(B, baz) baz_type;
typedef my_type_of_(B, quux) quux_type;
+ typedef my_type_of_(B, yin) yin_type;
};
+
+
+ /*---.
+ | C. |
+ `---*/
+
+ // Forward declaration.
+ struct C;
+
+ // C do not derive from B, but we want its vtypes to ``inherit''
+ // from B's vtypes (see the specilization
+ // vtypes<category::my_cat, C>.
+
+ /// Types associated to my::C.
+ template<>
+ struct vtypes<category::my_cat, C>
+ {
+ // FIXME: Having this link here is not elegant when you consider
+ // ext_vtype<>: this means that even if you have only a vtype
+ // declared as ext_vtype, you'll still have to define a
+ // corresponding vtypes<>, at least to define the pseudosuper
+ // class. What about externalizing this information, maybe with
+ // set_pseudosuper_type<>, and a macro set_pseudosuper() as sugar?
+
+ /// Link to B (``pseudo'' inheritance).
+ typedef B pseudosuper_type;
+
+ // A type defined only here (and not in the super class).
+ typedef double zorg_type;
+ };
+
+ struct C // no inheritance
+ {
+ // Aliases.
+ typedef my_type_of_(C, foo) foo_type;
+ typedef my_type_of_(C, quux) quux_type;
+ typedef my_type_of_(C, zorg) zorg_type;
+ };
+
}
+
int
main()
{
- // Check associated types.
+ // Check types associated to A.
mlc_eq(my::A::foo_type, int)::ensure ();
mlc_eq(my::A::bar_type, float)::ensure ();
- // Check associated types.
+ // Check types associated to B.
mlc_neq(my::B::bar_type, my::A::bar_type)::ensure ();
mlc_eq(my::B::baz_type, char)::ensure ();
mlc_eq(my::B::quux_type, long)::ensure ();
+ mlc_eq(my::B::yin_type, unsigned long)::ensure ();
+
+ // Check types associated to C.
+ mlc_eq(my::C::foo_type, int)::ensure ();
+ mlc_eq(my::C::quux_type, long)::ensure ();
+ mlc_eq(my::C::zorg_type, double)::ensure ();
}
Index: metalic/mlc/properties.hh
--- metalic/mlc/properties.hh (revision 413)
+++ metalic/mlc/properties.hh (working copy)
@@ -52,9 +52,21 @@
// FIXME: Add support for hierarchies with several super classes.
# define mlc_equip_namespace_with_properties() \
\
- /* ------------------------- */ \
- /* Inheritance declaration. */ \
- /* ------------------------- */ \
+ /* ----------------------- */ \
+ /* Typedefs declarations. */ \
+ /* ----------------------- */ \
+ \
+ /* FIXME: Should we use the `ret' typdef defined in the global */ \
+ /* namespace instead ? (see at the end mlc/typedef.hh). */ \
+ mlc_decl_typedef(ret); \
+ \
+ /* Declare the ``uplink'' typedef (access to a pseudosuper class). */ \
+ mlc_decl_typedef(pseudosuper_type); \
+ \
+ \
+ /* ------------- */ \
+ /* Inheritance. */ \
+ /* ------------- */ \
\
template <typename type> \
struct set_super_type \
@@ -63,58 +75,36 @@
}; \
\
\
- /* ---------------------------------------- */ \
- /* ``Internal'' associated types facility. */ \
- /* ---------------------------------------- */ \
+ /* --------------- */ \
+ /* Virtual types. */ \
+ /* --------------- */ \
\
- /** Fwd decl. */ \
- namespace internal { \
- template <typename category, typename from_type> struct get_types; \
- } \
- \
- /** Specialize this class to set ``internal'' associated types. */ \
+ /** \brief Internal virtual types associated to \a from_type. */ \
+ /** */ \
+ /** Specialize this class for the desired \a from_type. */ \
template <typename category, typename from_type> \
- struct set_types \
+ struct vtypes \
{ \
}; \
\
- /** \brief Specialize this class to redefine ``internal'' */ \
- /** associated types. */ \
- /** */ \
- /** Notice the inheritance relation, which enable the automatic */ \
- /** retrieval of the types associated to the super class of \a */ \
- /** from_type. */ \
- template <typename category, typename from_type> \
- struct redefine_types : public mlc_super_types(category, from_type) \
+ /** End of the recursive construction of any vtypes hierarchy. */ \
+ template <typename category> \
+ struct vtypes<category, mlc::none> \
{ \
}; \
\
- \
- /* ----------------------------------------- */ \
- /* ``External'' associated types machinery. */ \
- /* ----------------------------------------- */ \
- \
- /** Fwd decl. */ \
- namespace internal { \
- template <typename category, typename from_type, typename typedef_type> \
- struct get_ext_type; \
- } \
- \
- /** Specialize this class to set an ``external'' associated type. */ \
+ /** \brief An external virtual type associated to \a from_type. */ \
+ /** */ \
+ /** Specialize this class for the desired \a from_type. */ \
template <typename category, typename from_type, typename typedef_type> \
- struct set_ext_type \
+ struct ext_vtype \
{ \
}; \
\
- /** \brief Specialize this class to redefine an ``external'' */ \
- /** associated type. */ \
- /** */ \
- /** Notice the inheritance relation, which enable the automatic */ \
- /** retrieval of the types associated to the super class of \a */ \
- /** from_type. */ \
- template <typename category, typename from_type, typename typedef_type> \
- struct redefine_ext_type : \
- public mlc_super_ext_type(category, from_type, typedef_type) \
+ /** End of the recursive construction of any ext_vtype<> */ \
+ /** hierarchy. */ \
+ template <typename category, typename typedef_type> \
+ struct ext_vtype<category, mlc::none, typedef_type> \
{ \
}; \
\
@@ -128,34 +118,162 @@
/** retrieval mechanism). */ \
namespace internal \
{ \
- template <typename category, typename from_type> \
- struct get_types : \
- public set_types<category, from_type>, \
- public redefine_types<category, from_type> \
+ /* ------------------------------------------ */ \
+ /* Recursive retrieval of an internal vtype. */ \
+ /* ------------------------------------------ */ \
+ \
+ /* FIXME: Do a basic scheme of the algorithm in pseudo-code. */ \
+ \
+ /* FIXME: Check for mlc::undefined? */ \
+ \
+ /* FIXME: The presence of `vtypes' is the only thing that makes */ \
+ /* this code different from the retrieval within an external */ \
+ /* vtype. How can we factor this? */ \
+ template <typename category, typename from_type, typename typedef_type> \
+ struct rec_get_vtype \
{ \
+ /** Set of vtypes associated with FROM_TYPE. */ \
+ typedef vtypes<category, from_type> types; \
+ /** Typedef in the current vtypes (maybe mlc::not_found). */ \
+ typedef mlc_internal_get_typedef(types, typedef_type) type; \
+ \
+ /** Implicit parent (i.e. super), if any. */ \
+ typedef mlc_super(from_type) super; \
+ /** Pseudosuper class, if any. */ \
+ typedef mlc_internal_get_typedef(types, typedef_::pseudosuper_type) \
+ pseudosuper; \
+ \
+ typedef typename \
+ mlc::if_< \
+ mlc::neq_< type, mlc::not_found >, \
+ /* then */ \
+ /* return it */ \
+ /* (the typedef has been found in the vtypes */ \
+ /* associated to FROM_TYPE) */ \
+ type, \
+ /* else */ \
+ /* check if the vtype of the `super' of FROM_TYPE */ \
+ /* has the typedef */ \
+ typename \
+ mlc::if_< mlc::neq_< typename rec_get_vtype< category, \
+ super, \
+ typedef_type >::ret, \
+ mlc::not_found >, \
+ /* then */ \
+ /* return it */ \
+ typename rec_get_vtype< category, \
+ super, \
+ typedef_type >::ret, \
+ /* else */ \
+ /* check if the FROM_TYPE has a decl_parent */ \
+ /* and try to retrieve the typedef from it. */ \
+ typename rec_get_vtype< category, \
+ pseudosuper, \
+ typedef_type >::ret >::ret >::ret \
+ ret; \
}; \
\
- /** End of the recursive construction of any get_types<> hierarchy. */ \
- template <typename category> \
- struct get_types<category, mlc::none> \
+ /** Ends of the recursive retrieval (mlc::none is at the end of the */ \
+ /** transitive closure of every `super' relation). */ \
+ /** \{ */ \
+ /** Case where \a from_type = mlc::none (end of a recursive */ \
+ /** retrieval following `super' types). */ \
+ template <typename category, typename typedef_type> \
+ struct rec_get_vtype<category, mlc::none, typedef_type> \
+ { \
+ typedef mlc::not_found ret; \
+ }; \
+ /** Case where \a from_type = mlc::not_found (end of a recursive */ \
+ /** retrieval following `super' types). */ \
+ template <typename category, typename typedef_type> \
+ struct rec_get_vtype<category, mlc::not_found, typedef_type> \
{ \
+ typedef mlc::not_found ret; \
}; \
+ /** \} */ \
+ \
+ /* ------------------------------------------ */ \
+ /* Recursive retrieval of an external vtype. */ \
+ /* ------------------------------------------ */ \
+ \
+ /* FIXME: Merge this with rec_get_vtype. */ \
\
template <typename category, typename from_type, typename typedef_type> \
- struct get_ext_type : \
- public set_ext_type<category, from_type, typedef_type>, \
- public redefine_ext_type<category, from_type, typedef_type> \
+ struct rec_get_ext_vtype \
{ \
+ /** Set of vtypes associated with FROM_TYPE. */ \
+ typedef ext_vtype<category, from_type, typedef_type> ext_type; \
+ /** Typedef in the current vtypes (maybe mlc::not_found). */ \
+ typedef mlc_internal_get_typedef(ext_type, typedef_::ret) type; \
+ \
+ /** Implicit parent (i.e. super), if any. */ \
+ typedef mlc_super(from_type) super; \
+ /** Pseudosuper class, if any. */ \
+ /* FIXME: Looking for this information is not elegant. Have a */ \
+ /* look at metalic/tests/properties.cc for a better suggestion. */ \
+ typedef vtypes<category, from_type> types; \
+ typedef mlc_internal_get_typedef(types, typedef_::pseudosuper_type) \
+ pseudosuper; \
+ \
+ typedef typename \
+ mlc::if_< \
+ mlc::neq_< type, mlc::not_found >, \
+ /* then */ \
+ /* return it */ \
+ /* (the typedef has been found in the vtypes */ \
+ /* associated to FROM_TYPE) */ \
+ type, \
+ /* else */ \
+ /* check if the vtype of the `super' of FROM_TYPE */ \
+ /* has the typedef */ \
+ typename \
+ mlc::if_< mlc::neq_< typename rec_get_ext_vtype< category, \
+ super, \
+ typedef_type >::ret, \
+ mlc::not_found >, \
+ /* then */ \
+ /* return it */ \
+ typename rec_get_ext_vtype< category, \
+ super, \
+ typedef_type >::ret, \
+ /* else */ \
+ /* check if the FROM_TYPE has a decl_parent */ \
+ /* and try to retrieve the typedef from it. */ \
+ typename rec_get_ext_vtype< category, \
+ pseudosuper, \
+ typedef_type >::ret>::ret>::ret \
+ ret; \
}; \
\
- /** End of the recursive construction of any get_ext_type<> */ \
- /** hierarchy. */ \
+ /** Ends of the recursive retrieval (mlc::none is at the end of the */ \
+ /** transitive closure of every `super' relation). */ \
+ /** \{ */ \
+ /** Case where \a from_type = mlc::none (end of a recursive */ \
+ /** retrieval following `super' types). */ \
+ template <typename category, typename typedef_type> \
+ struct rec_get_ext_vtype<category, mlc::none, typedef_type> \
+ { \
+ typedef mlc::not_found ret; \
+ }; \
+ /** Case where \a from_type = mlc::not_found (end of a recursive */ \
+ /** retrieval following `super' types). */ \
template <typename category, typename typedef_type> \
- struct get_ext_type<category, mlc::none, typedef_type> \
+ struct rec_get_ext_vtype<category, mlc::not_found, typedef_type> \
{ \
+ typedef mlc::not_found ret; \
}; \
+ /** \} */ \
+ \
+ /* ------------------------------------- */ \
+ /* External/internal typedef selection. */ \
+ /* ------------------------------------- */ \
\
- /** Typedef selector. */ \
+ /** \brief Typedef selector. */ \
+ /** */ \
+ /** A virtual type is considered valid if and only if it has been */ \
+ /** found as an internal vtype or (exclusive) as an external vtype. */ \
+ /** Other cases (no definition or a double definition) are invalid. */ \
+ /** */ \
/** \{ */ \
/** Fwd decl. */ \
template <bool external_typedef_p, bool internal_typedef_p, \
@@ -196,26 +314,21 @@
} /** End of namespace internal. */ \
\
\
- /** FIXME: Don't query from_type directly, but */ \
- /** exact_type(from_type) instead */ \
+ /* FIXME: Don't query from_type directly, but exact_type(from_type) */ \
+ /* instead. We need mlc::any for this. */ \
template <typename category, typename from_type, typename typedef_type> \
struct typeof_ \
{ \
- typedef internal::get_types<category, from_type> types; \
- /* FIXME: Add a check in typeof_ to ensure that get_ext_type */ \
- /* derives from get_ext_type<none> */ \
- typedef \
- internal::get_ext_type<category, from_type, typedef_type> ext_type; \
- /* FIXME: Add a check in typeof_ to ensure that get_ext_type */ \
- /* derives from get_ext_type<none> */ \
- \
- /** Look for the typedef as an external type. */ \
- typedef \
- mlc_internal_get_typedef(ext_type, typedef_::ret) external_typedef; \
- /** Look for the typedef in internal types. */ \
- typedef \
- mlc_internal_get_typedef(types, typedef_type) internal_typedef; \
+ /* Look for the typedef as an external type. */ \
+ typedef typename \
+ internal::rec_get_ext_vtype<category, from_type, typedef_type>::ret \
+ external_typedef; \
+ /* Look for the typedef in internal types. */ \
+ typedef typename \
+ internal::rec_get_vtype<category, from_type, typedef_type>::ret \
+ internal_typedef; \
\
+ /* Did we found the virtual type? */ \
static const bool found_external_p = \
mlc::is_found<external_typedef>::value; \
static const bool found_internal_p = \
@@ -243,25 +356,13 @@
typedef Super ret; \
}
-/// \def Get the immediate base class of T
+/// \def Get the immediate base class of T (version with typename).
# define mlc_super(T) \
- set_super_type<T>::ret
+ typename set_super_type<T>::ret
-// FIXME: Doc.
-# define mlc_super_types(Category, FromType) \
- internal::get_types<Category, typename mlc_super(FromType)>
-
-// FIXME: Doc.
-# define mlc_super_types_(Category, FromType) \
- internal::get_types<Category, mlc_super(FromType)>
-
-// FIXME: Doc.
-# define mlc_super_ext_type(Category, FromType, Typedef) \
- internal::get_ext_type<Category, typename mlc_super(FromType), Typedef>
-
-// FIXME: Doc.
-# define mlc_super_ext_type_(Category, FromType, Typedef) \
- internal::get_ext_type<Category, mlc_super(FromType), Typedef>
+/// \def Get the immediate base class of T (version without typename).
+# define mlc_super_(T) \
+ set_super_type<T>::ret
/// Get the property \a Typedef from \a FromType (version with typename).
#define mlc_typeof(Category, FromType, Typedef) \