Making PlacementRef default constructible this way would resolve the immediate problems; as any access goes through an index lookup and thus will throw. The bool check on this special ref yields false, so this solution seems to fill the bill.
252 lines
7.8 KiB
C++
252 lines
7.8 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;
|
|
|
|
// 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 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 (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
|