/* PLACEMENT.hpp - Key Abstraction: a way to place and locate a Media Object Copyright (C) Lumiera.org 2008, Hermann Vosseler 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.hpp ** Placements are at the very core of all editing operations, ** because they act as handles to access the media objects to be manipulated. ** Moreover, Placements are the actual "content" of the Session and Fixture and thus ** are small handle like objects. Many editing tasks include locating some Placement ** within the Session or directly take a ref to a Placement. ** ** Placements are refcounting smart pointers: By acting on the Placement object, ** we can change parameters of the way the media object is placed (e.g. adjust an offset), ** while by dereferencing the Placement object, we access the "real" media object. ** Usually, any MObject is created by a factory and immediately wrapped into a Placement, ** which takes ownership of the MObject. ** ** Besides being a handle, Placements define the logical position where some MObject is ** supposed to be located within the Session or Fixture. The way in which this placing happens ** is controlled and parametrised by a collection (chain) of LocatingPin objects. By adding ** to this chain, the position of the MObject is increasingly constrained. The simplest ** case of such constraining is to add a FixedLocation, thus placing the MObject at one ** absolute position (time, output). ** ** Together, this yields semantics somewhere in between value semantics and reference semantics. ** As any smart-ptr, placements are copyable, but each such copy takes on a distinct identity. ** Moreover, when added to the Session, a placement acts as if it was an \em instance of the object ** it points at, with the purpose to bind this instance into the Session with specific placement ** properties. Thus, such a placement-within-session \em is an distinguishable entity, because ** the settings on the contained LocatingPin chain \em do constitute the relation properties ** of the MObject "placed" by this placement. To support this rather ref-like semantics, any ** placement has an embedded ID (identity). Building on this ID, it is possible to create a ** smart-ptr like PlacementRef to denote a specific placement found within the Session. ** ** Placements are templated on the type of the actual MObject they refer to, so, sometimes ** e.g. we rather use a Placement to be able to use the more specific methods of the ** session::Clip interface. But please note the following detail: this type ** labelling and downcasting is the only difference between these subclasses, ** besides that, they can be replaced literally by one another (slicing is accepted). ** ** @see ExplicitPlacement ** @see LocatingPin interface for controlling the positioning parameters ** */ #ifndef MOBJECT_PLACEMENT_H #define MOBJECT_PLACEMENT_H #include "lib/error.hpp" #include "lib/hash-indexed.hpp" #include "lib/time/timevalue.hpp" #include "proc/mobject/session/locatingpin.hpp" #include "proc/asset/pipe.hpp" //////////////TICKET #109 : get rid of this #include namespace proc { namespace mobject { namespace session{ class MObjectFactory; } class MObject; class ExplicitPlacement; using std::shared_ptr; using std::static_pointer_cast; using lib::HashIndexed; /** * A refcounting Handle to an MObject of type MO, * used to constrain or explicitly specify the location * where the MObject is supposed to be within the Session/Model. * Placements are copyable (like values), but may be distinguished * by their identity (reference semantics), which is based on an * \link lib::HashIndexed hash-ID \endlink. * * Placements are defined to form a hierarchy, thereby mirroring * the relations between their referents to some degree. This allows * for building APIs targeted at specific kinds of MObjects, and * at the same time allows a specific placement to stand-in when * just a unspecific Placement is required. * * @param MO the (compile time) type of the referent * @param B immediate base class of this placement */ template class Placement ; /** * this specialisation forms the root of all placements * and defines all of Placement's actual functionality. */ template<> class Placement : protected shared_ptr , public HashIndexed, lib::hash::LuidH > { protected: typedef HashIndexed, lib::hash::LuidH> HashInd; typedef shared_ptr _SmartPtr; typedef void (*Deleter)(MObject*); typedef lib::time::Time Time; typedef asset::shared_ptr Pipe; ////TICKET #109 : get rid of this public: /** smart pointer: accessing the MObject, * which is subject to placement. * @note we don't provide operator* */ MObject * operator-> () const { ENSURE (*this); return _SmartPtr::operator-> (); } /** run time diagnostics: is the pointee * of this placement compatible to the given type? */ template bool isCompatible () const { return 0 != dynamic_cast (get()); } /** extend shared ownership to the given smart-ptr * @note never throws */ template void extendOwnershipTo (shared_ptr& target) const { REQUIRE (isCompatible()); target = static_pointer_cast(*this); } /** free function to detect two placements sharing a pointee */ friend bool isSharedPointee (Placement const& p1, Placement const& p2) { return static_cast (p1.get()) == static_cast (p2.get()); } operator string() const ; size_t use_count() const { return _SmartPtr::use_count(); } bool isValid() const { return _SmartPtr::use_count(); } virtual ~Placement() {}; /** interface for defining the kind of placement * to employ, and for controlling any additional * constraints and properties. */ session::LocatingPin chain; /** combine and resolve all constraints defined * by the various LocatingPin (\see #chain) and * provide the resulting (explicit) placement. */ virtual ExplicitPlacement resolve () const; //////////////////////////TODO (1) could resolve() return a reference? Otherwise placement-ref.hpp needs to include ExplicitPlacement //////////////////////////TODO (2) does this really need to be virtual. Guess not. It's not abstract and not really polymorphic. But virtual here causes template bloat. ////////////TICKET #439 Placement (Placement const& ref) : _SmartPtr (ref) , HashInd() // creating a new ID! , chain(ref.chain) { } protected: Placement (MObject & subject, Deleter killer) : _SmartPtr (&subject, killer) { }; friend class session::MObjectFactory; /////////////////////////////////////////////////////////TICKET #513 // private: // /** copy assignment prohibited */ // Placement& operator= (Placement const&); /////////////////////////////////////////////////////////TICKET #513 }; /** * any specific placements are supposed to be derived * from Placement, or an intermediary interface, * in case the second template parameter is used. * @note please refrain from adding additional functionality * to these subclasses. Especially, don't add any fields * to the subclass, as Placements are treated like values * at times, and thus slicing will happen, which in this * special case is acceptable. */ template class Placement : public Placement { protected: typedef Placement _Parent; typedef typename _Parent::template Id const& _Id; typedef typename _Parent::Deleter Deleter; typedef typename _Parent::_SmartPtr _SmartPtr; Placement (MO & mo, Deleter killer) : _Parent (mo, killer) { }; friend class session::MObjectFactory; public: MO* operator-> () const { ENSURE (INSTANCEOF (MO, this->get())); return static_cast (_SmartPtr::operator-> ()); } _Id getID () const ///< @note overrides HashIndexed::getID to pass specific type information, { return _Parent::template recastID(); } }; /** @todo cleanup uses of ref-to-placement. See Ticket #115 */ typedef Placement PlacementMO; //‘typedef class mobject::Placement mobject::PlacementMO’ typedef Placement PMO; /* == free functions == */ string format_PlacementID (PlacementMO const&) ; /** compare the properties of placement * @return \c true if all the LocatingPin entries * in both placements are semantically equivalent. */ bool isSameDef (PlacementMO const&, PlacementMO const&); }} // namespace proc::mobject #endif