LUMIERA.clone/src/proc/mobject/placement-ref.hpp

253 lines
7.9 KiB
C++

/*
PLACEMENT-REF.hpp - generic reference to an individual placement added to the session
Copyright (C) Lumiera.org
2009, 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 placement-ref.hpp
**
** @note there is a twist concerning the nominal Placement hierarchy
** as generated by the return type of PlacementRef::operator*().
** While the original Placement (as added to the session) might been
** defined to mimic a more elaborate hierarchy (e.g. Placement<Track>
** inherits from Placement<Meta>), the Placement returned here in
** these cases will just be a subclass or Placement<MObject>
** (which in the mentioned example would mean it couldn't be
** passed to a API function expecting a Placement<Meta>).
** This is ugly, but doesn't seem to bear any danger.
**
** @see Placement
** @see PlacementRef_test
**
*/
#ifndef MOBJECT_PLACEMENT_REF_H
#define MOBJECT_PLACEMENT_REF_H
//#include "pre.hpp"
//#include "proc/mobject/session/locatingpin.hpp"
//#include "proc/asset/pipe.hpp"
#include "lib/error.hpp"
#include "proc/mobject/placement.hpp"
#include "proc/mobject/explicitplacement.hpp" /////////////TODO this is ugly! Why can't placement::resolve() return a reference??
//#include <tr1/memory>
namespace mobject {
// using std::tr1::shared_ptr;
class MObject;
namespace session {
// see placement-index.cpp
Placement<MObject> & fetch_PlacementIndex(Placement<MObject>::ID const&) ;
bool checkContains_PlacementIndex (Placement<MObject>::ID const& pID) ;
}
LUMIERA_ERROR_DECLARE (INVALID_PLACEMENTREF); ///< unresolvable placement reference, or of incompatible type
/**
* TODO type comment
*/
template<class MO =MObject>
class PlacementRef
{
typedef Placement<MO> PlacementMO;
typedef Placement<MObject>::ID _ID; ////TODO: could we define const& here??
typedef Placement<MObject>::Id<MO> _Id;
_Id id_;
public:
/**
* Creating a PlacementRef from a compatible reference source.
* Any source allowing to infer a \em compatible mobject::Placement
* is accepted. Here, compatibility is decided based on the run time
* type of the pointee, in comparison to the template parameter Y.
* In any case, for this ctor to succeed, the provided ref or ID
* needs to be resolvable to a placement by the implicit PlacementIndex
* facility used by all PlacementRef instances (typically the Session).
* @note there is no default ctor, a reference source is mandatory.
* @param refID reference resolvable to a placement via Index, especially
* - an existing Placement
* - just an Placement::ID
* - a plain LUID
* @throw error::Invalid on incompatible run time type of the resolved ID
*/
template<class Y>
explicit
PlacementRef (Y const& refID)
: id_(recast (refID))
{
validate(id_);
}
/** Default is an NIL Placement ref. It throws on any access. */
PlacementRef ()
: id_()
{
REQUIRE (!isValid(), "hash-ID clash with existing ID");
}
PlacementRef (PlacementRef const& r) ///< copy ctor
: id_(r.id_)
{
validate(id_);
}
template<class X>
PlacementRef (PlacementRef<X> const& r) ///< extended copy ctor, when type X is assignable to MO
: id_(recast(r))
{
validate(id_);
}
PlacementRef&
operator= (PlacementRef const& r)
{
validate(r.id_);
id_ = r.id_;
return *this;
}
template<class X>
PlacementRef&
operator= (PlacementRef<X> const& r)
{
validate(recast (r));
id_ = recast(r);
return *this;
}
template<class Y>
PlacementRef&
operator= (Y const& refID)
{
validate (recast (refID));
id_ = recast (refID);
return *this;
}
/* == forwarding smart-ptr operations == */
PlacementMO& operator*() const { return access(id_); } ///< dereferencing fetches referred Placement from Index
PlacementMO& operator->() const { return access(id_); } ///< provide access to pointee API by smart-ptr chaining
operator string() const { return access(id_).operator string(); }
size_t use_count() const { return access(id_).use_count(); }
/* == accessing the embedded ID == */
operator _Id const&() const { return id_; }
LumieraUid getLUID() const { return id_.get(); }
template<class O>
bool operator== (PlacementRef<O> const& o) const { return id_ == o; }
template<class O>
bool operator!= (PlacementRef<O> const& o) const { return id_ != o; }
typedef _Id PlacementRef::*__unspecified_bool_type; ////////TICKET #178 : implement by lib::BoolCheckable?
/** implicit conversion to "bool" */
operator __unspecified_bool_type() const { return isValid()? &PlacementRef::id_ : 0; } // never throws
bool operator! () const { return !isValid(); } // ditto
/* == forwarding part of the Placement-API == */
bool isValid() const
{
if (checkValidity())
try
{
return access(id_).isValid();
}
catch (lumiera::error::Invalid&) {}
return false;
}
ExplicitPlacement resolve() const { return access(id_).resolve();}
////////////////TODO more operations to come....
private:
bool
checkValidity () const
{
return session::checkContains_PlacementIndex(this->id_);
}
static void
validate (_Id const& rId)
{
PlacementMO& pRef (access (rId));
if (!(pRef.template isCompatible<MO>()))
throw lumiera::error::Invalid("actual type of the resolved placement is incompatible",LUMIERA_ERROR_INVALID_PLACEMENTREF);
////////////////////////TODO: 1. better message, including type?
////////////////////////TODO: 2. define a separate error-ID for the type mismatch!
}
static _Id const&
recast (_ID const& someID)
{
return static_cast<_Id const&> (someID);
}
static _Id const&
recast (const LumieraUid luid)
{
REQUIRE (luid);
return reinterpret_cast<_Id const&> (*luid);
}
static PlacementMO&
access (_Id const& placementID)
{
Placement<MObject> & pla (session::fetch_PlacementIndex (placementID)); // may throw
REQUIRE (pla.isValid());
ASSERT (pla.isCompatible<MO>());
return static_cast<PlacementMO&> (pla);
}
};
/** frequently-used shorthand */
typedef PlacementRef<MObject> RefPlacement;
} // namespace mobject
#endif