251 lines
8.4 KiB
C++
251 lines
8.4 KiB
C++
/*
|
||
STRUCT-FACTORY-IMPL.hpp - crating structural assets (impl details)
|
||
|
||
Copyright (C) Lumiera.org
|
||
2008,2010, Hermann Vosseler <Ichthyostega@web.de>
|
||
|
||
This program is free software; you can redistribute it and/or
|
||
modify it under the terms of the GNU General Public License as
|
||
published by the Free Software Foundation; either version 2 of
|
||
the License, or (at your option) any later version.
|
||
|
||
This program 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 program; if not, write to the Free Software
|
||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||
|
||
*/
|
||
|
||
|
||
/** @file struct-factory-impl.hpp
|
||
** Private implementation details of creating various structural assets.
|
||
** Details how to fabricate specific kinds of structural assets, based
|
||
** on capability information encoded into a query (goal).
|
||
** @internal to be used by struct.cpp
|
||
**
|
||
** @see ConfigQuery
|
||
**
|
||
*/
|
||
|
||
|
||
#ifndef ASSET_STRUCT_FACTORY_IMPL_H
|
||
#define ASSET_STRUCT_FACTORY_IMPL_H
|
||
|
||
|
||
#include "proc/mobject/session.hpp"
|
||
#include "proc/mobject/session/binding.hpp"
|
||
#include "proc/mobject/session/mobjectfactory.hpp"
|
||
#include "proc/mobject/session/element-query.hpp"
|
||
#include "proc/mobject/session/session-query.hpp"
|
||
#include "proc/mobject/session/scope.hpp"
|
||
#include "common/config-rules.hpp"
|
||
#include "common/query.hpp"
|
||
#include "proc/asset/timeline.hpp"
|
||
#include "proc/asset/sequence.hpp"
|
||
#include "proc/asset/procpatt.hpp"
|
||
#include "proc/asset/pipe.hpp"
|
||
|
||
#include "proc/asset/struct-scheme.hpp"
|
||
|
||
#include "lib/format-string.hpp"
|
||
#include "lib/query-util.hpp"
|
||
#include "lib/symbol.hpp"
|
||
#include "lib/error.hpp"
|
||
#include "lib/util.hpp"
|
||
|
||
#include <cstdlib>
|
||
|
||
|
||
|
||
namespace proc {
|
||
namespace asset {
|
||
|
||
using lib::Symbol;
|
||
using util::_Fmt;
|
||
using util::uNum;
|
||
using util::isnil;
|
||
using util::contains;
|
||
using lumiera::Query;
|
||
using lumiera::query::LUMIERA_ERROR_CAPABILITY_QUERY;
|
||
using lib::query::extractID;
|
||
|
||
using proc::mobject::Session;
|
||
using proc::mobject::MObject;
|
||
using proc::mobject::session::Scope;
|
||
using proc::mobject::session::match_specificFork;
|
||
using proc::mobject::session::RBinding;
|
||
using proc::mobject::session::ForkID;
|
||
using proc::mobject::session::RFork;
|
||
using proc::mobject::session::Fork;
|
||
|
||
using idi::StructTraits;
|
||
|
||
|
||
namespace {
|
||
|
||
Symbol genericIdSymbol ("id");
|
||
Symbol seqNrPredicate ("ord");
|
||
|
||
}
|
||
|
||
|
||
|
||
|
||
/**
|
||
* Implementation details, especially concerning how configuration
|
||
* queries are resolved and when to create new objects automatically.
|
||
* @todo better use a general struct traits class, esp.for creating the Ident
|
||
* @todo shouldn't some of the generic factory logic be moved over into the struct baseclass? ////////////////TICKET #565
|
||
*/
|
||
class StructFactoryImpl
|
||
{
|
||
|
||
/** @internal derive a sensible asset ident tuple when creating
|
||
* structural asset instances based on a capability query
|
||
*/
|
||
template<class STRU>
|
||
const Asset::Ident
|
||
createIdent (Query<STRU> const& query)
|
||
{
|
||
// does the query somehow specify the desired name-ID?
|
||
string nameID = query.extractID (genericIdSymbol);
|
||
if (isnil (nameID))
|
||
nameID = query.extractID (StructTraits<STRU>::idSymbol());
|
||
if (isnil (nameID))
|
||
{
|
||
// no name-ID contained in the query...
|
||
// so we'll create a new one
|
||
static int i=0;
|
||
nameID = _Fmt("%s.%d")
|
||
% StructTraits<STRU>::namePrefix()
|
||
% (++i);
|
||
}
|
||
ENSURE (!isnil (nameID));
|
||
|
||
// does the query actually demand the Nth instance/element?
|
||
string seqID = query.extractID (seqNrPredicate);
|
||
if (!isnil (seqID) && 1 < uNum(seqID))
|
||
nameID += "."+seqID;
|
||
|
||
Category cat (STRUCT, StructTraits<STRU>::catFolder());
|
||
return Asset::Ident (nameID, cat );
|
||
}
|
||
|
||
|
||
/** either fetch or build a suitable fork root for a new sequence */
|
||
RFork
|
||
getFork_forSequence (string const& desiredID)
|
||
{
|
||
RFork fork;
|
||
if (!isnil (desiredID))
|
||
fork = Session::current->elements.pick (match_specificFork (desiredID));
|
||
|
||
if (fork && !Scope::containing (fork.getRef()).isRoot())
|
||
{
|
||
UNIMPLEMENTED ("how to deal with 'stealing' a fork sub-tree to a new sequence??");
|
||
}
|
||
if (!fork)
|
||
fork = Session::current->getRoot().attach (MObject::create (ForkID (desiredID)));
|
||
|
||
return fork;
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
/** used for issuing recursive create calls to top level */
|
||
StructFactory& recursive_create_;
|
||
|
||
public:
|
||
StructFactoryImpl (StructFactory& interface)
|
||
: recursive_create_(interface)
|
||
{ }
|
||
|
||
|
||
|
||
/** make a new structural asset instance.
|
||
* @warning default/fallback implementation just throws.
|
||
* @todo a real implementation using a resolution engine.
|
||
*/
|
||
template<class STRU>
|
||
STRU* fabricate (Query<STRU> const& caps)
|
||
{
|
||
throw error::Config ("The following Query could not be resolved: " + caps.asKey()
|
||
, LUMIERA_ERROR_CAPABILITY_QUERY );
|
||
}
|
||
|
||
};
|
||
|
||
|
||
/* ============= specialisations =========================== */
|
||
|
||
template<>
|
||
inline const ProcPatt*
|
||
StructFactoryImpl::fabricate (Query<const ProcPatt> const& caps)
|
||
{
|
||
TODO ("actually extract properties/capabilities from the query...");
|
||
return new ProcPatt (createIdent (caps));
|
||
} ///////////////////////TICKET #565 maybe store the capabilities query within the Struct asset somehow?
|
||
|
||
template<>
|
||
inline Pipe*
|
||
StructFactoryImpl::fabricate (Query<Pipe> const& caps)
|
||
{
|
||
const Asset::Ident idi (createIdent (caps));
|
||
string streamID = caps.extractID ("stream");
|
||
if (isnil (streamID)) streamID = "default";
|
||
PProcPatt processingPattern = Session::current->defaults (Query<const ProcPatt>("stream("+streamID+")"));
|
||
return new Pipe( idi
|
||
, streamID
|
||
, processingPattern
|
||
); ///////////////////////TICKET #565 maybe store the capabilities query within the Struct asset somehow?
|
||
}
|
||
|
||
template<>
|
||
inline Timeline*
|
||
StructFactoryImpl::fabricate (Query<Timeline> const& caps)
|
||
{
|
||
TODO ("extract additional properties/capabilities from the query...");
|
||
const Asset::Ident idi (createIdent (caps));
|
||
string sequenceID = caps.extractID ("sequence");
|
||
Query<Sequence> desiredSequence (isnil (sequenceID)? "" : "id("+sequenceID+")");
|
||
PSequence sequence = recursive_create_(desiredSequence);
|
||
ASSERT (sequence);
|
||
RBinding newBinding = Session::current->getRoot().attach (MObject::create (sequence));
|
||
ASSERT (newBinding);
|
||
PTimeline newTimeline = Timeline::create (idi, newBinding);
|
||
ENSURE (newTimeline); ///////////////////////TICKET #565 maybe store the capabilities query within the Struct asset somehow?
|
||
return newTimeline.get();
|
||
}
|
||
|
||
template<>
|
||
inline Sequence*
|
||
StructFactoryImpl::fabricate (Query<Sequence> const& caps)
|
||
{
|
||
// when we reach this point it is clear a suitable sequence doesn't yet exist in the model
|
||
TODO ("actually extract properties/capabilities from the query...");
|
||
string forkID = caps.extractID ("fork");
|
||
Query<Fork> desiredFork (isnil (forkID)? "" : "id("+forkID+")");
|
||
// PFork fork = Session::current->query (desiredFork); ///////////////////////////////////TICKET #639
|
||
// TODO: handle the following cases
|
||
// - fork doesn't exist --> create and attach it as root
|
||
// - fork exists and is root attached, but belongs already to a sequence --> throw
|
||
// - fork exists, but isn't root attached ---> what do do here? steal it??
|
||
PSequence newSequence = Sequence::create (createIdent (caps)); ///////////TODO fed fork in here
|
||
ENSURE (newSequence); ///////////////////////TICKET #565 maybe store the capabilities query within the Struct asset somehow?
|
||
return newSequence.get();
|
||
}
|
||
|
||
|
||
|
||
|
||
}} // namespace proc::asset
|
||
#endif
|