Commit c24cf134 authored by Roland Levillain's avatar Roland Levillain
Browse files

Extensible entry points in a class hierarchy (first version).

	* stc/entry.hh: New.
	* tests/entry.cc: New test.
	* stc/Makefile.am (nobase_stc_HEADERS): Add entry.hh.
	* tests/Makefile.am (check_PROGRAMS): Add `entry'.
	(entry_SOURCES): New.


git-svn-id: https://svn.lrde.epita.fr/svn/oln/trunk@438 4aad255d-cdde-0310-9447-f3009e2ae8c0
parent 6b8b5dd5
2006-03-23 Roland Levillain <roland@lrde.epita.fr>
Extensible entry points in a class hierarchy (first version).
* stc/entry.hh: New.
* tests/entry.cc: New test.
* stc/Makefile.am (nobase_stc_HEADERS): Add entry.hh.
* tests/Makefile.am (check_PROGRAMS): Add `entry'.
(entry_SOURCES): New.
2006-03-22 Roland Levillain <roland@lrde.epita.fr>
Catch up with changes in Metalic.
......@@ -17,4 +27,3 @@
(stc_set_pseudosuper, stc_pseudosuper, stc_pseudosuper_): New
macros.
* tests/properties.cc: Adjust.
......@@ -2,4 +2,5 @@
stcdir = $(includedir)/stc
nobase_stc_HEADERS = \
entry.hh \
properties.hh
// Copyright (C) 2006 EPITA Research and Development Laboratory
//
// This file is part of the Olena Library. This library is free
// software; you can redistribute it and/or modify it under the terms
// of the GNU General Public License version 2 as published by the
// Free Software Foundation.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this library; see the file COPYING. If not, write to
// the Free Software Foundation, 59 Temple Place - Suite 330, Boston,
// MA 02111-1307, USA.
//
// As a special exception, you may use this file as part of a free
// software library without restriction. Specifically, if other files
// instantiate templates or use macros or inline functions from this
// file, or you compile this file and link it with other files to
// produce an executable, this file does not by itself cause the
// resulting executable to be covered by the GNU General Public
// License. This exception does not however invalidate any other
// reasons why the executable file might be covered by the GNU General
// Public License.
#ifndef STATIC_ENTRY_HH
# define STATIC_ENTRY_HH
/** \file stc/entry.hh
\brief Extensible entry points in a class hierarchy.
The following simplified diagram shows a typical use of this
facility.
First hierarchy Second hierarchy
/A/ /B/
^ ^
| |
,-----+-----. ,-----+-----.
| | | |
/A1/ /A2/ /B1/ /B2/
| | | |
o o o o
o o
| |
stc::set_entry_node<C,1> stc::set_entry_node<C,2>
(first selector) (second selector)
^ ^
| |
`------------+------------'
|
stc::entry
^
|
C
(a client class)
Actually, the inheritance tree is (almost) linear, and the real
code rather looks like this:
/B/
^
|
,-----+-----.
| |
/B1/ /B2/
| |
o o
o
|
stc::set_entry_node<C,2>
^
|
/A/
^
|
,-----+-----.
| |
/A1/ /A2/
| |
o o
o
|
stc::set_entry_node<C,1>
^
|
stc::entry
^
|
C
*/
#include <mlc/if.hh>
#include <mlc/is_a.hh>
#include <mlc/comma.hh>
namespace stc
{
namespace internal
{
// End of the recurring inheritance.
struct none {};
// No user class should derive from this class.
struct not_user_defined {};
}
/** \brief Entry point of a hierarchy.
To be possibly specialized by the user.
This class is use as selector ``plugging'' itself (inheriting)
to (from) a bottom class in one of the multiple hierarchies. */
template <typename exact, unsigned num>
struct set_entry_node : public internal::not_user_defined
{
// Nothing.
};
namespace internal
{
// Not to be defined by the user.
// FIXME: Use a lock?
template <typename exact, unsigned num>
struct get_entry_node :
public set_entry_node<exact, num>,
public mlc::if_< mlc_is_a( mlc_comma_1( set_entry_node<exact, num + 1> ),
internal::not_user_defined ),
internal::none,
internal::get_entry_node<exact, num + 1> >::ret
{
};
}
/** \brief Bottom entry point.
This class must not to be specialized by the user. However,
this class is meant to be super class of classes below the
multiple hierarchies. */
template <typename exact>
struct entry : public internal::get_entry_node<exact, 1>
{
};
} // end of namespace stc
#endif // ! STATIC_ENTRY_HH
......@@ -8,8 +8,10 @@ AM_CPPFLAGS = -I$(top_srcdir)/static -I$(top_srcdir)/metalic
# when oln.m4 is available in the distribution.
check_PROGRAMS = \
entry \
properties
properties_SOURCES = properties.cc
entry_SOURCES = entry.cc
TESTS = $(check_PROGRAMS)
/// Test the extensible entry points in a class hierarchy.
#include <stc/entry.hh>
#include <mlc/case.hh>
#include <mlc/assert.hh>
#include <mlc/is_a.hh>
// FIXME: Fake. Remove this when mlc::abort_ is added to the project.
namespace mlc
{
template <typename T>
class abort_ {};
}
/*----------.
| Library. |
`----------*/
/* Simplified class diagram.
/top/
^
|
,------------+------------.
| |
/property1/ /property2/
^ ^
| |
,-----+-----. ,-----+-----.
| | | |
/property1a/ /property1b/ /property2a/ /property2b/
| | | |
o o o o
o o
| |
stc::set_entry_node<C,1> stc::set_entry_node<C,1>
(first selector) (second selector)
^ ^
| |
`------------+------------'
|
entry
^
|
foo
In fact, this is closer to this :
/top/
^
|
|
/property2/
^
|
,-----+-----.
| |
/property2a/ /property2b/
| |
o o
o
|
stc::set_entry_node<foo,2>
(second selector)
^
|
/property1/
^
|
,-----+-----.
| |
/property1a/ /property1b/
| |
o o
o
|
stc::set_entry_node<foo,1>
(first selector)
^
|
entry
^
|
foo
*/
namespace my_lib
{
// Virtual types.
// We don't use all the equipment of stc/properties.hh for
// simplicity purpose.
template <typename T>
struct vtypes
{
// Nothing.
};
/// Top of the hierachy.
struct top {};
/// Property 1.
/// \{
struct property1 : virtual public top {};
struct property1a : public property1 {};
struct property1b : public property1 {};
/// \}
/// Property 2.
/// \{
struct property2 : virtual public top {};
struct property2a : public property2 {};
struct property2b : public property2 {};
/// \}
}
mlc_case_equipment_for_namespace(my_lib);
// -------------------------- //
// Equipment for property 1. //
// -------------------------- //
namespace my_lib
{
// Switch on property 1.
/// \{
struct prop1_tag;
template <typename prop1_type>
struct case_<prop1_tag, prop1_type, 1> :
// Test.
public mlc::where_< mlc_is_a(prop1_type, int) >
{
// Super class if test succeed.
typedef property1a ret;
};
template <typename prop1_type>
struct case_<prop1_tag, prop1_type, 2> :
// Test.
public mlc::where_< mlc_is_a(prop1_type, long) >
{
// Super class if test succeed.
typedef property1b ret;
};
template <typename prop1_type>
struct default_case_<prop1_tag, prop1_type>
{
typedef mlc::abort_<prop1_tag> ret;
};
/// \}
} // End of namespace my_lib
// FIXME: Maybe set/get_entry_node should be moved inside a macro?
namespace stc
{
/// Property 1.
/// E is for Exact.
template <typename E>
struct set_entry_node<E, 1> :
public my_lib::switch_<my_lib::prop1_tag,
typename my_lib::vtypes<E>::prop1>::ret
{
};
}
// -------------------------- //
// Equipment for property 2. //
// -------------------------- //
namespace my_lib
{
// Switch on property 2.
/// \{
struct prop2_tag;
template <typename prop2_type>
struct case_<prop2_tag, prop2_type, 1> :
// Test.
public mlc::where_< mlc_is_a(prop2_type, float) >
{
// Super class if test succeed.
typedef property2a ret;
};
template <typename prop2_type>
struct case_<prop2_tag, prop2_type, 2> :
// Test.
public mlc::where_< mlc_is_a(prop2_type, double) >
{
// Super class if test succeed.
typedef property2b ret;
};
template <typename prop2_type>
struct default_case_<prop2_tag, prop2_type>
{
typedef mlc::abort_<prop2_tag> ret;
};
/// \}
} // End of namespace my_lib
// FIXME: Maybe set/get_entry_node should be moved inside a macro?
namespace stc
{
/// Property 2.
/// E is for Exact.
template <typename E>
struct set_entry_node<E, 2> :
public my_lib::switch_<my_lib::prop2_tag,
typename my_lib::vtypes<E>::prop2>::ret
{
};
}
/*--------------.
| Client code. |
`--------------*/
// Fwd decl.
namespace client
{
struct foo;
}
// client::foo's vtypes.
namespace my_lib
{
template <>
struct vtypes<client::foo>
{
typedef int prop1;
typedef double prop2;
};
}
namespace client
{
struct foo : public stc::entry<foo>
{
};
}
int
main ()
{
mlc::assert_<mlc_is_a_(client::foo, my_lib::top)>::check();
mlc::assert_<mlc_is_a_(client::foo, my_lib::property1)>::check();
mlc::assert_<mlc_is_a_(client::foo, my_lib::property1a)>::check();
mlc::assert_<mlc_is_not_a_(client::foo, my_lib::property1b)>::check();
mlc::assert_<mlc_is_a_(client::foo, my_lib::property2)>::check();
mlc::assert_<mlc_is_not_a_(client::foo, my_lib::property2a)>::check();
mlc::assert_<mlc_is_a_(client::foo, my_lib::property2b)>::check();
}
Supports Markdown
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