LUMIERA.clone/src/proc/asset/struct-factory-impl.hpp

251 lines
8.4 KiB
C++
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
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