* MObjectRef_test pass *

This is the integration of some months of work
This commit is contained in:
Fischlurch 2010-01-16 16:34:58 +01:00
parent 0f9fc7e3dd
commit f6cf3195cf
6 changed files with 167 additions and 73 deletions

View file

@ -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:

View file

@ -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;
}
};

View file

@ -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);
}
};

View file

@ -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

View file

@ -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
}
};

View file

@ -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