* MObjectRef_test pass *
This is the integration of some months of work
This commit is contained in:
parent
0f9fc7e3dd
commit
f6cf3195cf
6 changed files with 167 additions and 73 deletions
|
|
@ -28,6 +28,8 @@
|
|||
|
||||
|
||||
|
||||
/////////////////////////TODO: 1/2010 very likely the handling of the clip-asset needs to be rewritten
|
||||
|
||||
namespace asset
|
||||
{
|
||||
/**
|
||||
|
|
@ -38,7 +40,7 @@ namespace asset
|
|||
/** media source of this clip */
|
||||
const Media& source_;
|
||||
|
||||
/** the corresponding (dependant) clip-MO */
|
||||
/** the corresponding (dependent) clip-MO */
|
||||
PClipMO clipMO_;
|
||||
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@
|
|||
|
||||
|
||||
/** @file mobject-ref.hpp
|
||||
** External MObject/Placement reference.
|
||||
** External MObject/Placement reference.
|
||||
** This smart-handle referres to an MObject, attached (placed) into the session.
|
||||
** It is a copyable value object, implemented by an LUID (hash) and an shared_ptr.
|
||||
** Holding an MObject ref keeps the referred MObject alive, but gives no guarantees
|
||||
|
|
@ -42,10 +42,10 @@
|
|||
** Like any smart-ptr MObjectRef is templated on the actual type of the pointee.
|
||||
** It can be built or re-assigned from a variety of sources, given the runtime type
|
||||
** of the referred pointee is compatible to this template parameter type. This
|
||||
** allows flexibly to re-gain a specifically typed context, even based just
|
||||
** allows flexibly to re-gain a specifically typed context, even based just
|
||||
** on a plain LUID. This functionality is implemented by accessing the
|
||||
** PlacementIndex within the session, and then by using the RTTI of
|
||||
** the fetched Placement's pointee.
|
||||
** the fetched Placement's pointee.
|
||||
**
|
||||
** @see MObject
|
||||
** @see Session
|
||||
|
|
@ -65,6 +65,8 @@
|
|||
#include "proc/mobject/placement.hpp"
|
||||
#include "proc/mobject/placement-ref.hpp"
|
||||
|
||||
#include <string>
|
||||
|
||||
|
||||
///////////////////////////////////////////TODO: define an C-API representation here, make the header multilingual!
|
||||
|
||||
|
|
@ -110,12 +112,18 @@ namespace mobject {
|
|||
return smPtr_.operator-> ();
|
||||
}
|
||||
|
||||
|
||||
Placement<MO>& getPlacement() const
|
||||
{
|
||||
if (!isValid())
|
||||
throw lumiera::error::State("Accessing inactive MObject ref"
|
||||
,LUMIERA_ERROR_BOTTOM_MOBJECTREF);
|
||||
|
||||
ENSURE (INSTANCEOF (MO, smPtr_.get()));
|
||||
return *pRef_;
|
||||
}
|
||||
|
||||
|
||||
/** resolves the referred placement to an
|
||||
* ExplicitPlacement and returns the found start time
|
||||
*/
|
||||
|
|
@ -160,12 +168,11 @@ namespace mobject {
|
|||
activate (REF const& pRefID)
|
||||
{
|
||||
PlacementRef<MO> newRef (pRefID);
|
||||
if (newRef.isValid()
|
||||
&& pRef_ != newRef )
|
||||
{
|
||||
return activate (*newRef); // STRONG exception safe
|
||||
}
|
||||
else return *this;
|
||||
|
||||
if (isValid() && pRef_ == newRef )
|
||||
return *this; // self assignment detected
|
||||
else
|
||||
return activate (*newRef); // STRONG exception safe
|
||||
}
|
||||
|
||||
/** build and activate an MObject reference based on
|
||||
|
|
@ -208,13 +215,14 @@ namespace mobject {
|
|||
bool
|
||||
isValid() const
|
||||
{
|
||||
return pRef_.isValid();
|
||||
return _Handle::isValid()
|
||||
&& pRef_.isValid();
|
||||
}
|
||||
|
||||
size_t
|
||||
use_count() const
|
||||
{
|
||||
return pRef_.use_count();
|
||||
return isValid()? pRef_.use_count() : 0;
|
||||
}
|
||||
|
||||
template<class MOX>
|
||||
|
|
@ -225,6 +233,12 @@ namespace mobject {
|
|||
&& (*pRef_).isCompatible<MOX>();
|
||||
}
|
||||
|
||||
operator string() const ///////////////////////TICKET #527 should be better integrated with the other object types
|
||||
{
|
||||
return isValid()? string(getPlacement())
|
||||
: "MRef-NIL";
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -234,54 +248,62 @@ namespace mobject {
|
|||
bool
|
||||
operator== (MORef<MOX> const& oRef) const
|
||||
{
|
||||
return oRef == this->pRef_;
|
||||
return isValid()
|
||||
&& oRef == this->pRef_;
|
||||
}
|
||||
|
||||
template<class MOX>
|
||||
bool
|
||||
operator!= (MORef<MOX> const& oRef) const
|
||||
{
|
||||
return oRef != this->pRef_;
|
||||
return !isValid()
|
||||
|| oRef != this->pRef_;
|
||||
}
|
||||
|
||||
template<class MOX>
|
||||
friend bool
|
||||
operator== (MORef const& oRef, PlacementRef<MOX> const& pRef)
|
||||
{
|
||||
return oRef.pRef_ == pRef;
|
||||
return oRef.isValid()
|
||||
&& oRef.pRef_ == pRef;
|
||||
}
|
||||
|
||||
template<class MOX>
|
||||
friend bool
|
||||
operator!= (MORef const& oRef, PlacementRef<MOX> const& pRef)
|
||||
{
|
||||
return oRef.pRef_ != pRef;
|
||||
return !oRef.isValid()
|
||||
|| oRef.pRef_ != pRef;
|
||||
}
|
||||
|
||||
template<class MOX>
|
||||
friend bool
|
||||
operator== (PlacementRef<MOX> const& pRef, MORef const& oRef)
|
||||
{
|
||||
return pRef == oRef.pRef_;
|
||||
return oRef.isValid()
|
||||
&& pRef == oRef.pRef_;
|
||||
}
|
||||
|
||||
template<class MOX>
|
||||
friend bool
|
||||
operator!= (PlacementRef<MOX> const& pRef, MORef const& oRef)
|
||||
{
|
||||
return pRef != oRef.pRef_;
|
||||
return !oRef.isValid()
|
||||
|| pRef != oRef.pRef_;
|
||||
}
|
||||
|
||||
bool
|
||||
operator== (PlacementMO::ID const& pID) const
|
||||
{
|
||||
return PlacementMO::ID (pRef_) == pID;
|
||||
return isValid()
|
||||
&& PlacementMO::ID (pRef_) == pID;
|
||||
}
|
||||
|
||||
bool
|
||||
operator!= (PlacementMO::ID const& pID) const
|
||||
{
|
||||
return PlacementMO::ID (pRef_) != pID;
|
||||
return !isValid()
|
||||
|| PlacementMO::ID (pRef_) != pID;
|
||||
}
|
||||
|
||||
};
|
||||
|
|
|
|||
|
|
@ -232,12 +232,8 @@ namespace mobject {
|
|||
static void
|
||||
validate (_Id const& rId)
|
||||
{
|
||||
PlacementMX& pRef (access (rId));
|
||||
if (!(pRef.template isCompatible<MX>()))
|
||||
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!
|
||||
access (rId); // may throw
|
||||
/////////////////////////////TODO more to check on each PlacementRef creation?
|
||||
}
|
||||
|
||||
static _Id const&
|
||||
|
|
@ -267,10 +263,16 @@ namespace mobject {
|
|||
throw lumiera::error::Logic ("Attempt to access a NIL PlacementRef"
|
||||
,LUMIERA_ERROR_BOTTOM_PLACEMENTREF);
|
||||
|
||||
Placement<MObject> & pla (session::SessionServiceFetch::resolveID (placementID)); // may throw
|
||||
REQUIRE (pla.isValid());
|
||||
ASSERT (pla.isCompatible<MX>());
|
||||
return static_cast<PlacementMX&> (pla);
|
||||
Placement<MObject> & genericPlacement (session::SessionServiceFetch::resolveID (placementID)); // may throw
|
||||
REQUIRE (genericPlacement.isValid());
|
||||
|
||||
if (!(genericPlacement.template isCompatible<MX>()))
|
||||
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!
|
||||
|
||||
return static_cast<PlacementMX&> (genericPlacement);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -29,7 +29,44 @@ PLANNED "DeleteClip_test" DeleteClip_test <<END
|
|||
END
|
||||
|
||||
|
||||
PLANNED "external MObject references" MObjectRef_test <<END
|
||||
TEST "external MObject references" MObjectRef_test <<END
|
||||
out: MRef-NIL
|
||||
out: sizeof\( .+MORef.+session.Clip.+ \) = (32)|(24)
|
||||
out: Placement<.+Clip.> ............... use-cnt=4
|
||||
out: Asset\(VIDEO:lumi.test-1 v1\)
|
||||
out: Placement<.+Clip.> ............... use-cnt=4
|
||||
out: MRef-NIL
|
||||
out: sizeof\( .+MORef.+session.Clip.+ \) = (32)|(24)
|
||||
out: Placement<.+Clip.> ............... use-cnt=4
|
||||
out: Asset\(VIDEO:lumi.test-2 v1\)
|
||||
out: Placement<.+Clip.> ............... use-cnt=4
|
||||
out: MRef-NIL
|
||||
out: sizeof\( .+MORef.+session.Clip.+ \) = (32)|(24)
|
||||
out: Placement<.+Clip.> ............... use-cnt=4
|
||||
out: Asset\(VIDEO:lumi.test-1 v1\)
|
||||
out: Placement<.+Clip.> ............... use-cnt=4
|
||||
out: MRef-NIL
|
||||
out: sizeof\( .+MORef.+session.Clip.+ \) = (32)|(24)
|
||||
out: Placement<.+Clip.> ............... use-cnt=4
|
||||
out: Asset\(VIDEO:lumi.test-2 v1\)
|
||||
out: Placement<.+Clip.> ............... use-cnt=4
|
||||
out: MRef-NIL
|
||||
out: sizeof\( .+MORef.+session.Clip.+ \) = (32)|(24)
|
||||
out: Placement<.+Clip.>.+ use-cnt=4
|
||||
out: Asset\(VIDEO:lumi.test-1 v1\)
|
||||
out: Placement<.+Clip.> ............... use-cnt=4
|
||||
out: MRef-NIL
|
||||
out: sizeof\( .+MORef.+session.Clip.+ \) = (32)|(24)
|
||||
out: Placement<.+Clip.> ............... use-cnt=4
|
||||
out: Asset\(VIDEO:lumi.test-1 v1\)
|
||||
out: Placement<.+Clip.> ............... use-cnt=4
|
||||
out: MRef-NIL
|
||||
out: sizeof\( .+MORef.+session.Clip.+ \) = (32)|(24)
|
||||
out: Placement<.+Clip.> ............... use-cnt=4
|
||||
out: Asset\(VIDEO:lumi.test-2 v1\)
|
||||
out: Placement<.+Clip.> ............... use-cnt=4
|
||||
out: Placement<.+Clip.> ............... use-cnt=5
|
||||
out: \(VIDEO:lumi.test-1 v1\)
|
||||
END
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -46,8 +46,30 @@ using std::endl;
|
|||
namespace mobject {
|
||||
namespace test {
|
||||
|
||||
namespace { // shortcut for checking use-counts
|
||||
|
||||
bool
|
||||
checkUseCount (size_t cnt, uint additional=0)
|
||||
{
|
||||
static uint base_count=0;
|
||||
if (!additional) // called for init
|
||||
base_count = cnt;
|
||||
|
||||
return cnt == base_count + additional;
|
||||
}
|
||||
|
||||
template<class REF>
|
||||
bool
|
||||
checkUseCount (REF const& ref, uint additional)
|
||||
{
|
||||
return checkUseCount(ref.use_count(), additional);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
using lumiera::Time;
|
||||
using session::Clip;
|
||||
using session::PMedia;
|
||||
|
||||
using session::SessionServiceMockIndex;
|
||||
using session::PPIdx;
|
||||
|
|
@ -105,6 +127,10 @@ namespace test {
|
|||
PMObj& pClip1 = index->find(clip1ID);
|
||||
PMObj& pClip2 = index->find(clip2ID);
|
||||
|
||||
ASSERT (3 == pClip1.use_count()); // clip-Asset, original placement, new placement in index
|
||||
ASSERT (3 == pClip2.use_count());
|
||||
checkUseCount(pClip1.use_count()); // set ref point for later checks
|
||||
|
||||
// extract various kinds of IDs and refs
|
||||
PMObj & rP1 (pClip1);
|
||||
PMObj const& rP2 (pClip2);
|
||||
|
|
@ -147,25 +173,29 @@ namespace test {
|
|||
|
||||
template<typename REF>
|
||||
void
|
||||
checkBuildMObjectRef (REF refObj, void* placementAdr)
|
||||
checkBuildMObjectRef (REF& refObj, void* placementAdr)
|
||||
{
|
||||
MORef<Clip> rMO;
|
||||
ASSERT (!rMO); // still empty (not bound)
|
||||
cout << rMO << endl;
|
||||
ASSERT (0==rMO.use_count());
|
||||
cout << string(rMO) << endl; /////////////////////TICKET #527
|
||||
cout << showSizeof(rMO) << endl;
|
||||
|
||||
// activate by binding to provided ref
|
||||
rMO.activate(refObj);
|
||||
ASSERT (rMO); // now bound
|
||||
cout << rMO << endl;
|
||||
cout << string(rMO) << endl; /////////////////////TICKET #527
|
||||
|
||||
// access MObject (Clip API)
|
||||
// cout << rMO->operator string() << endl; /////////////////////TICKET #428
|
||||
cout << string(rMO->getMedia()->ident) << endl; /////////////////////TICKET #520
|
||||
PMedia media = rMO->getMedia();
|
||||
cout << str(media) << endl; /////////////////////TICKET #520
|
||||
Time mediaLength = media->getLength();
|
||||
ASSERT (Time(0) < mediaLength);
|
||||
ASSERT (rMO->isValid());
|
||||
|
||||
// access the Placement-API
|
||||
ASSERT (3 == rMO.use_count()); // now rMO shares ownership with the Placement
|
||||
ASSERT (checkUseCount(rMO, 1)); // now rMO shares ownership with the Placement --> use-count += 1
|
||||
ASSERT (Time(0) < rMO.getStartTime()); // (internally, this resolves to an ExplicitPlacement) /////////TICKET #332
|
||||
ASSERT ( rMO.isCompatible<MObject>());
|
||||
ASSERT ( rMO.isCompatible<Clip>());
|
||||
|
|
@ -175,14 +205,15 @@ namespace test {
|
|||
// re-link to the Placement (note we get the Clip API!)
|
||||
Placement<Clip> & refP = rMO.getPlacement();
|
||||
ASSERT (refP.isValid());
|
||||
ASSERT (3 == refP.use_count());
|
||||
ASSERT (refP.use_count() == rMO.use_count());
|
||||
ASSERT (checkUseCount(refP, 1)); // use count not changed
|
||||
ASSERT (&refP == placementAdr); // actually denotes the address of the original Placement in the "session"
|
||||
cout << string(refP) << endl;
|
||||
|
||||
ExplicitPlacement exPla = refP.resolve();
|
||||
ASSERT (exPla.time == start); // recovered Placement resolves to the same time as provided by the proxied API
|
||||
ASSERT (4 == refP.use_count()); // but now we've indeed created an additional owner (exPla)
|
||||
ASSERT (4 == rMO.use_count());
|
||||
ASSERT (checkUseCount(refP, 2)); // but now we've indeed created an additional owner (exPla)
|
||||
ASSERT (checkUseCount(rMO, 2));
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -243,21 +274,21 @@ namespace test {
|
|||
|
||||
ASSERT (!(rM == pRef1) && !(pRef1 == rM));
|
||||
ASSERT ( (rM != pRef1) && (pRef1 != rM));
|
||||
ASSERT (!(rM != pRef2) && !(pRef2 != rM));
|
||||
ASSERT ( (rM == pRef2) && (pRef2 == rM));
|
||||
ASSERT ( (rM != pRef2) && (pRef2 != rM));
|
||||
ASSERT (!(rM == pRef2) && !(pRef2 == rM));
|
||||
|
||||
ASSERT (!(rM == p1.getID()) );
|
||||
ASSERT ( (rM != p1.getID()) );
|
||||
ASSERT (!(rM != p2.getID()) );
|
||||
ASSERT ( (rM == p2.getID()) );
|
||||
ASSERT ( (rM != p2.getID()) );
|
||||
ASSERT (!(rM == p2.getID()) );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
checkLifecycle (PMObj const& p1, PMObj const& p2)
|
||||
{
|
||||
ASSERT (2 == p1.use_count());
|
||||
ASSERT (2 == p2.use_count());
|
||||
ASSERT (checkUseCount(p1, 0));
|
||||
ASSERT (checkUseCount(p2, 0));
|
||||
|
||||
MORef<Clip> rMO;
|
||||
ASSERT (!rMO);
|
||||
|
|
@ -266,27 +297,27 @@ namespace test {
|
|||
rMO.activate(p1);
|
||||
ASSERT (rMO);
|
||||
ASSERT (rMO->getMedia()->getFilename() == "test-1");
|
||||
ASSERT (3 == rMO.use_count());
|
||||
ASSERT (3 == p1.use_count());
|
||||
ASSERT (2 == p2.use_count());
|
||||
ASSERT (checkUseCount(rMO, 1));
|
||||
ASSERT (checkUseCount(p1, 1)); // sharing ownership
|
||||
ASSERT (checkUseCount(p2, 0));
|
||||
|
||||
rMO.activate(p2);
|
||||
ASSERT (rMO);
|
||||
ASSERT (rMO->getMedia()->getFilename() == "test-2");
|
||||
ASSERT (3 == rMO.use_count());
|
||||
ASSERT (2 == p1.use_count());
|
||||
ASSERT (3 == p2.use_count());
|
||||
ASSERT (checkUseCount(rMO, 1));
|
||||
ASSERT (checkUseCount(p1, 0)); // detached, use count dropped to previous value
|
||||
ASSERT (checkUseCount(p2, 1)); // sharing ownership
|
||||
|
||||
rMO.activate(p2);
|
||||
ASSERT (3 == rMO.use_count());
|
||||
ASSERT (checkUseCount(rMO, 1)); // no change
|
||||
|
||||
rMO.close();
|
||||
ASSERT (!rMO);
|
||||
ASSERT (2 == p1.use_count());
|
||||
ASSERT (2 == p2.use_count());
|
||||
ASSERT (checkUseCount(p1, 0));
|
||||
ASSERT (checkUseCount(p2, 0));
|
||||
|
||||
VERIFY_ERROR (INVALID_PLACEMENTREF, rMO.getPlacement() );
|
||||
VERIFY_ERROR (BOTTOM_MOBJECTREF, rMO->getMedia() );
|
||||
VERIFY_ERROR (BOTTOM_MOBJECTREF, rMO.getPlacement() );
|
||||
VERIFY_ERROR (BOTTOM_MOBJECTREF, rMO->getMedia() );
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -296,19 +327,19 @@ namespace test {
|
|||
MORef<Clip> rClip;
|
||||
MORef<TestSubMO1> rSub1;
|
||||
|
||||
ASSERT (0 == rMObj.use_count());
|
||||
ASSERT (0 == rClip.use_count());
|
||||
ASSERT (0 == rSub1.use_count());
|
||||
ASSERT ( ! rMObj.use_count());
|
||||
ASSERT ( ! rClip.use_count());
|
||||
ASSERT ( ! rSub1.use_count());
|
||||
|
||||
rMObj.activate(luid);
|
||||
ASSERT (3 == rMObj.use_count());
|
||||
ASSERT (0 == rClip.use_count());
|
||||
ASSERT (0 == rSub1.use_count());
|
||||
ASSERT (checkUseCount(rMObj, 1));
|
||||
ASSERT ( ! rClip.use_count());
|
||||
ASSERT ( ! rSub1.use_count());
|
||||
|
||||
rClip.activate(rMObj); // attach on existing MObjectRef
|
||||
ASSERT (4 == rMObj.use_count());
|
||||
ASSERT (4 == rClip.use_count());
|
||||
ASSERT (0 == rSub1.use_count());
|
||||
ASSERT (checkUseCount(rMObj, 2));
|
||||
ASSERT (checkUseCount(rClip, 2));
|
||||
ASSERT ( ! rSub1.use_count());
|
||||
|
||||
// impossible, because Clip isn't a subclass of TestSubMO1:
|
||||
VERIFY_ERROR (INVALID_PLACEMENTREF, rSub1.activate(luid) );
|
||||
|
|
@ -322,15 +353,15 @@ namespace test {
|
|||
// rMObj->getMedia();
|
||||
|
||||
rClip.close();
|
||||
ASSERT (3 == rMObj.use_count());
|
||||
ASSERT (0 == rClip.use_count());
|
||||
ASSERT (checkUseCount(rMObj, 1));
|
||||
ASSERT ( ! rClip.use_count());
|
||||
|
||||
// can assign, because the actual type checked:
|
||||
// can assign, because the actual type is checked:
|
||||
rClip = rMObj;
|
||||
ASSERT (4 == rMObj.use_count());
|
||||
ASSERT (4 == rClip.use_count());
|
||||
ASSERT (checkUseCount(rMObj, 2));
|
||||
ASSERT (checkUseCount(rClip, 2));
|
||||
|
||||
cout << rClip << endl;
|
||||
cout << string(rClip) << endl; //////////TICKET #527
|
||||
cout << string(rClip->getMedia()->ident) << endl; //////////TICKET #520
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -71,8 +71,8 @@ namespace test{
|
|||
|
||||
namespace { // test data and helpers...
|
||||
|
||||
const uint MAX_FAMILIES = 5; ///< maximum separate "families", each sharing a TypedCounter
|
||||
const uint MAX_MEMBERS = 20; ///< maximum members per family (member == test thread)
|
||||
const uint MAX_FAMILIES = 4; ///< maximum separate "families", each sharing a TypedCounter
|
||||
const uint MAX_MEMBERS = 10; ///< maximum members per family (member == test thread)
|
||||
const uint MAX_ITERATIONS = 50; ///< maximum iterations within a single test thread
|
||||
const uint MAX_DELAY_ms = 3; ///< maximum delay between check iterations
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue