working example implementation of the access mechanism to session internal APIs

This commit is contained in:
Fischlurch 2009-11-09 02:08:37 +01:00
parent 2765981db9
commit 043d4f42fa
5 changed files with 185 additions and 38 deletions

View file

@ -42,8 +42,14 @@ This code is heavily inspired by
** Helpers for working with lumiera::typelist::Types (i.e. lists-of-types).
** The main purpose is to build interfaces and polymorphic implementations
** (using virtual functions) based on templated Types or Collections of types,
** which is not possible without Template Metaprogrmming.
** which is not possible without Template Metaprogramming.
**
** The facilities in this header work by instantiating another template,
** which is passed in as (template template) parameter, for each of a
** given sequence of types. What varies is the way how this "for each"
** instantiation is mixed or inherited into the resulting product.
**
** @see generator-test.cpp
** @see lumiera::query::ConfigRules usage example
** @see typelist.hpp
**
@ -99,6 +105,13 @@ namespace typelist{
};
/** Helper to just inherit from the given type(s) */
template<typename T>
struct InheritFrom : T
{ };
/**
* Build a single inheritance chain of template instantiations.

View file

@ -33,6 +33,7 @@
#define MOBJECT_SESSION_SESSION_SERVICES_H
#include "proc/mobject/session.hpp"
#include "lib/meta/generator.hpp"
//#include <boost/scoped_ptr.hpp>
//#include <vector>
@ -46,10 +47,34 @@ namespace session {
//using std::vector;
//using boost::scoped_ptr;
//using std::tr1::shared_ptr;
using lumiera::typelist::InstantiateChained;
using lumiera::typelist::InheritFrom;
using lumiera::typelist::NullType;
template<class API, class IMPL>
struct ServiceAccessPoint;
/**
* Collection of configured implementation-level services
* to provide by the Session. An instance of this template
* is created on top of SessionImpl, configured such as
* to inherit from all the concrete services to be
* exposed for use by Proc-Lyer's internals.
*/
template< typename IMPS
, class FRONT
, class BA =NullType
>
class SessionServicesX
: public InstantiateChained<typename IMPS::List, ServiceAccessPoint, BA>
{
static FRONT& entrance_;
};
}} // namespace mobject::session
#endif

View file

@ -48,6 +48,11 @@ namespace test {
namespace { // what follows is a simulated (simplified) version
// of the complete Session + SessionManager setup.....
// using boost::noncopyable;
// using session::SessionServices;
using lumiera::typelist::Types;
/* === Interface level === */
@ -73,6 +78,23 @@ namespace test {
};
/* === Service level API === */
struct InternalAPI_1
{
virtual ~InternalAPI_1() {}
virtual uint getMagic() =0;
static InternalAPI_1& access();
};
struct InternalAPI_2
{
static void invokeImplementationService();
};
/* === Implementation level === */
struct TSessionImpl : TSession
@ -86,50 +108,79 @@ namespace test {
void implementationService() ;
/* ==== internals ==== */
TSessionImpl()
{
++magic_;
cout << "creating new Session " << magic_ << endl;
}
operator string() const
TSessionImpl();
operator string() const;
};
template<class API, class IMPL>
struct ServiceAccessPoint;
template<class IMPL>
struct ServiceAccessPoint<InternalAPI_1, IMPL>
: IMPL
, InternalAPI_1
{
uint
getMagic ()
{
return string("Session-Impl(")
+ lexical_cast<string>(magic_)
+ ")";
return IMPL::magic_;
}
};
inline ostream&
operator<< (ostream& os, TSessionImpl const& simpl)
template<class IMPL>
struct ServiceAccessPoint<InternalAPI_2, IMPL>
: IMPL
{
return os << string(simpl);
}
void
forwardServiceInvocation()
{
IMPL::implementationService();
}
};
void
TSessionImpl::externalOperation()
template< typename IMPS
, class FRONT
, class SESS
>
class SessionServices
: public InstantiateChained<typename IMPS::List, ServiceAccessPoint, SESS>
{
cout << *this << "::externalOperation()" << endl;
}
public:
static FRONT& current;
template<class API>
API&
get()
{
return *this;
}
};
/* === storage and basic configuration === */
/* ==== Implementation level API ==== */
void
TSessionImpl::implementationService()
{
cout << *this << "::implementationService()" << endl;
}
struct TSessManagerImpl;
typedef SessionServices< Types<InternalAPI_1,InternalAPI_2>
, TSessManagerImpl
, TSessionImpl
> SessionImplAPI;
struct TSessManagerImpl : TSessManager
{
scoped_ptr<TSessionImpl> pImpl_;
scoped_ptr<SessionImplAPI> pImpl_;
TSessManagerImpl()
: pImpl_(0)
{ }
TSessionImpl*
SessionImplAPI*
operator-> ()
{
if (!pImpl_)
@ -142,18 +193,72 @@ namespace test {
void
reset ()
{
scoped_ptr<TSessionImpl> tmpS (new TSessionImpl);
scoped_ptr<SessionImplAPI> tmpS (new SessionImplAPI);
pImpl_.swap (tmpS);
}
};
/* === storage and basic configuration === */
uint TSessionImpl::magic_;
TSessManager& TSession::current = Singleton<TSessManagerImpl>()();
//note: comes up already during static initialisation
//note: already during static initialisation
template<>
TSessManagerImpl& SessionImplAPI::current = static_cast<TSessManagerImpl&> (TSession::current);
/* === Implementation of service access === */
InternalAPI_1&
InternalAPI_1::access()
{
return SessionImplAPI::current->get<InternalAPI_1>();
}
void
InternalAPI_2::invokeImplementationService()
{
SessionImplAPI::current->forwardServiceInvocation();
}
/* === Implementation of Session internals === */
inline ostream&
operator<< (ostream& os, TSessionImpl const& simpl)
{
return os << string(simpl);
}
TSessionImpl::operator string() const
{
return string("Session-Impl(")
+ lexical_cast<string>(magic_)
+ ")";
}
TSessionImpl::TSessionImpl()
{
++magic_;
cout << "creating new Session " << magic_ << endl;
}
void
TSessionImpl::externalOperation()
{
cout << *this << "::externalOperation()" << endl;
}
/* ==== Implementation level API ==== */
inline void
TSessionImpl::implementationService()
{
cout << *this << "::implementationService()" << endl;
}
} // (END) simulated session management
@ -180,7 +285,7 @@ namespace test {
{
access_defaultSession();
make_newSession();
invoke_implService();
invoke_implServices();
}
@ -201,9 +306,13 @@ namespace test {
void
invoke_implService ()
invoke_implServices ()
{
///////////////////////////////TODO
cout << "current Session-Impl-ID = " << InternalAPI_1::access().getMagic() << endl;
InternalAPI_2::invokeImplementationService();
TSession::current.reset();
InternalAPI_2::invokeImplementationService(); // invocation creates new session as side effect
}

View file

@ -56,7 +56,7 @@ namespace test {
struct Block
{
static string name;
string talk() { return name+"::eat(..)"; }
string talk() { return "__"+name+"__"; }
};
@ -85,7 +85,7 @@ namespace test {
DoIt () { cout << "ctor DoIt<"<< X::name << " >\n";}
virtual ~DoIt() { cout << "dtor DoIt<"<< X::name << " >\n";}
public:
void eat (X& x) { cout << x.talk() << "\n";}
void eat (X& x) { cout << "devouring" << x.talk() << "\n";}
using BASE::eat; // prevent shadowing
};

View file

@ -4021,12 +4021,12 @@ It will contain a global video and audio out pipe, just one timeline holding a s
&amp;rarr; see [[Relation of Project, Timelines and Sequences|TimelineSequences]]
</pre>
</div>
<div title="SessionServices" modifier="Ichthyostega" modified="200911071834" created="200911071825" tags="SessionLogic impl" changecount="4">
<div title="SessionServices" modifier="Ichthyostega" modified="200911090107" created="200911071825" tags="SessionLogic impl" changecount="7">
<pre>Within Lumiera's Proc-Layer, there are some implementation facilities and subsystems needing more specialised access to implementation services provided by the session. Thus, besides the public SessionInterface and the [[lifecycle and state management API|SessionManager]], there are some additional service interfaces exposed by the session through a special access mechanism. This mechanism needs to be special in order to assure clean transactional behaviour when the session is opened, closed, cleared or loaded. Of course, there is the additional requirement to avoid direct dependencies of the mentioned Proc internals on session implementation details.
!Accessing session services
For each of these services, there is an access interface, usually through an class with only static methods. Basically this means access //by name.//
On the //implementation side//&amp;nbsp; of this access interface class (i.e. within a {{{*.cpp}}} file separate from the client code), there is a (down-casting) access through the top-level session-~PImpl pointer, which is then forwarded through another {{{operator-&gt;()}}} on the ~SessionImpl class finally to reach an ~SessionServices instance, owned and managed by ~SessionImpl. This ~SessionServices instance is configured (statically) to mix in implementations for all the exposed service interfaces. Thus, the implementaion of the access functions (to the session service we're discussing here) can use this forwarding mechanism (which technically is located as a static function on class ~SessionServices) to get the actual implementation basically by one-liners. The upside of this (admittedly convoluted) technique is that we've gotten at runtime only a single indirection, which moreover is through the top-level session-~PImpl. The downside is that, due to the separation in {{{*.h}}} and {{{*.c}}} files, we can't use any specifically typed generic operations, which forces us to use type erasure in case we need such (an example being the content discovery queries utilised by all high-level model objects).</pre>
On the //implementation side//&amp;nbsp; of this access interface class (i.e. within a {{{*.cpp}}} file separate from the client code), there is a (down-casting) access through the top-level session-~PImpl pointer, allowing to invoke functions on the ~SessionServices instance. Actually, this ~SessionServices instance is configured (statically) to stack up implementations for all the exposed service interfaces on top of the basic ~SessionImpl class. Thus, each of the individual service implementations is able to use the basic ~SessinImpl (becaus it inherits it) and the implementaion of the access functions (to the session service we're discussing here) is able to use this forwarding mechanism to get the actual implementation basically by one-liners. The upside of this (admittedly convoluted) technique is that we've gotten at runtime only a single indirection, which moreover is through the top-level session-~PImpl. The downside is that, due to the separation in {{{*.h}}} and {{{*.c}}} files, we can't use any specifically typed generic operations, which forces us to use type erasure in case we need such (an example being the content discovery queries utilised by all high-level model objects).</pre>
</div>
<div title="SessionStructureQuery" modifier="Ichthyostega" modified="200910181417" created="200910112322" tags="SessionLogic design draft discuss" changecount="15">
<pre>The frontside interface of the session allows to query for contained objects; it is used to discover the structure and contents of the currently opened session/project. Access point is the public API of the Session class, which, besides exposing those queries, also provides functionality for adding and removing session contents.