Factory impl now complete (hopfully).
Added Tests/Examples for the more advanced use cases * using custom allocation (e.g. C-style malloc) * using placement new * creating Objects via private ctor * example for the 'PImpl' pattern
This commit is contained in:
parent
b1ea774ef1
commit
c0dcccebd9
6 changed files with 486 additions and 55 deletions
|
|
@ -118,6 +118,8 @@ namespace cinelerra
|
|||
/**
|
||||
* another convienience instantiiation: auto_ptr-to-Impl-Factory.
|
||||
* Creating an implementation subclass and wraps into auto_ptr.
|
||||
* @warning the TImpl object will typically be destoyed by the
|
||||
* smart ptr using an T*, so ~T() needs to be virtual.
|
||||
*/
|
||||
template
|
||||
< class T, // Interface class
|
||||
|
|
@ -128,7 +130,7 @@ namespace cinelerra
|
|||
public:
|
||||
typedef std::auto_ptr<T> PType;
|
||||
|
||||
PType operator() (){ return wrap (new TImpl); };
|
||||
PType operator() (){ return wrap (static_cast<T*> (new TImpl)); };
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -71,6 +71,34 @@ out: dtor ~TargetObj(5) successfull
|
|||
END
|
||||
|
||||
|
||||
TEST "Factory_special_test" Factory_special_test 5 <<END
|
||||
out: checkPlacement--------
|
||||
out: ctor TargetObj(5) successfull
|
||||
out: created 3 shared_ptrs to Object placed in static buffer.
|
||||
out: .....TargetObj(5): data="*****", array[5]={0,1,2,3,4,}
|
||||
out: dtor ~TargetObj(5) successfull
|
||||
out: ctor TargetObj(6) successfull
|
||||
out: created 4 shared_ptrs to Object placed in static buffer.
|
||||
out: dtor ~TargetObj(6) successfull
|
||||
out: checkPrivate--------
|
||||
out: ctor TargetObj(5) successfull
|
||||
out: created 3 shared_ptrs to paranoid Object.
|
||||
out: .....TargetObj(5): data="*****", array[5]={0,1,2,3,4,}
|
||||
out: dtor ~TargetObj(5) successfull
|
||||
out: checkMalloc--------
|
||||
out: ctor TargetObj(7) successfull
|
||||
out: created auto_ptr to malloc-ed Object.
|
||||
out: .....TargetObj(7): data="*******", array[7]={0,1,2,3,4,5,6,}
|
||||
out: dtor ~TargetObj(7) successfull
|
||||
out: checkPImpl--------
|
||||
out: ctor TargetObj(12) successfull
|
||||
out: created auto_ptr to Interface Object.
|
||||
out: .....ImplObj::funky() called
|
||||
out: .....TargetObj(12): data="************", array[12]={0,1,2,3,4,5,6,7,8,9,10,11,}
|
||||
out: dtor ~TargetObj(12) successfull
|
||||
END
|
||||
|
||||
|
||||
TEST "TestOption_test" TestOption_test <<END
|
||||
out: Testing invocation with cmdline: ...
|
||||
out: --> Testgroup=ALL
|
||||
|
|
|
|||
|
|
@ -65,7 +65,10 @@ artifacts['testsuite'] = ts = [ SingleTestExecutableSubdir(env, dir) for dir in
|
|||
# - the product of running the Testsuite is the ",testlog"
|
||||
# - it depends on all artifacts defined as "ts" above
|
||||
#
|
||||
runTs = env.Command(',testlog', ts, "./test.sh", chdir=1)
|
||||
testEnv = env.Clone()
|
||||
testEnv.Append(ENV = {'VALGRINDFLAGS' : 'DISABLE'})
|
||||
|
||||
runTs = testEnv.Command(',testlog', ts, "./test.sh", chdir=1)
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
327
tests/components/common/factoryspecialtest.cpp
Normal file
327
tests/components/common/factoryspecialtest.cpp
Normal file
|
|
@ -0,0 +1,327 @@
|
|||
/*
|
||||
Factory-Special(Test) - testing the more advanced features of factory
|
||||
|
||||
Copyright (C) CinelerraCV
|
||||
2007, Christian Thaeter <ct@pipapo.org>
|
||||
|
||||
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.
|
||||
|
||||
* *****************************************************/
|
||||
|
||||
|
||||
#include "common/testtargetobj.hpp"
|
||||
#include "common/factory.hpp"
|
||||
|
||||
#include "common/test/run.hpp"
|
||||
#include "common/util.hpp"
|
||||
#include "nobugcfg.h"
|
||||
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/format.hpp>
|
||||
#include <iostream>
|
||||
|
||||
using boost::lexical_cast;
|
||||
using boost::format;
|
||||
using util::isnil;
|
||||
using std::string;
|
||||
using std::cout;
|
||||
|
||||
|
||||
namespace cinelerra
|
||||
{
|
||||
namespace test
|
||||
{
|
||||
|
||||
/**
|
||||
* Example Allocator using plain C memory management.
|
||||
*/
|
||||
class MallocAllocator
|
||||
{
|
||||
public:
|
||||
void* operator new (size_t siz) { return malloc (siz); };
|
||||
void operator delete (void* p) { if (p) free (p); };
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Simple subclass used for custom alloc and as Interface class
|
||||
*/
|
||||
class TargetO : public TestTargetObj
|
||||
{
|
||||
long additional_member;
|
||||
|
||||
public:
|
||||
TargetO (uint cnt) : TestTargetObj(cnt) {}
|
||||
virtual ~TargetO () {};
|
||||
|
||||
/** Example Base/Interface function */
|
||||
virtual void funky()
|
||||
{
|
||||
cout << string(*this) << "\n";
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Subclass of the Interface class TargetO, could be an implementation class.
|
||||
*/
|
||||
class ImplObj : public TargetO
|
||||
{
|
||||
public:
|
||||
ImplObj () : TargetO(12) {}
|
||||
|
||||
/** Example Implementation function */
|
||||
virtual void funky()
|
||||
{
|
||||
cout << ".....ImplObj::funky() called\n";
|
||||
TargetO::funky();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Another special Subclass, using custom allocation.
|
||||
*/
|
||||
class MallocO : public TestTargetObj, public MallocAllocator
|
||||
{
|
||||
public:
|
||||
MallocO () : TestTargetObj (7) {}
|
||||
};
|
||||
|
||||
|
||||
|
||||
class Factory2;
|
||||
|
||||
/**
|
||||
* Special Subclass prohibiting public use of ctor
|
||||
*/
|
||||
class ParanoidObj : public TestTargetObj
|
||||
{
|
||||
private:
|
||||
ParanoidObj (uint cnt) : TestTargetObj(cnt) {}
|
||||
~ParanoidObj () {}
|
||||
|
||||
friend class Factory2;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
/* ===== several specialized Factories ====== */
|
||||
|
||||
using std::tr1::shared_ptr;
|
||||
|
||||
/**
|
||||
* Factory creating refcounting TargetO pointers
|
||||
* and using placement Allocation.
|
||||
*/
|
||||
class Factory1 : public Factory<TargetO>
|
||||
{
|
||||
public:
|
||||
typedef shared_ptr<TargetO> PType;
|
||||
|
||||
/** specialized Factory method
|
||||
* doing placement new and invoking
|
||||
* a special constructor. */
|
||||
PType operator() (uint param) { return wrap (new(alloc()) TargetO(param) ); }
|
||||
|
||||
protected:
|
||||
PType wrap (TargetO* tO) { return PType (tO, &destroy); } ///< note: providing custom deleter func
|
||||
|
||||
static void destroy (TargetO* victim) { victim->~TargetO(); } ///< call dtor but don't delete mem
|
||||
static void* alloc () { return buff; } ///< returning raw mem for new object
|
||||
static char buff[]; ///< we place our (single) instance here
|
||||
};
|
||||
char Factory1::buff[sizeof(TargetO)];
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Factory usable if object can be constructed only by friends
|
||||
*/
|
||||
class Factory2 : public Factory<ParanoidObj>
|
||||
{
|
||||
public:
|
||||
typedef shared_ptr<ParanoidObj> PType;
|
||||
|
||||
/** allowed to call ctor because
|
||||
* it's a friend of ParanoidObj.
|
||||
* Note passing custom deleter.
|
||||
*/
|
||||
PType operator() (uint param) { return PType (new ParanoidObj(param), &destroy); }
|
||||
|
||||
protected:
|
||||
/** custom deleter func is allowed to call
|
||||
* ~ParanoidObj() because of friendship
|
||||
*/
|
||||
static void destroy (ParanoidObj* victim) { delete victim; }
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* === Factory instances ==============*/
|
||||
|
||||
typedef Factory<MallocO> FactoryM;
|
||||
typedef factory::PImplPtr<TargetO,ImplObj> FactoryP;
|
||||
|
||||
static Factory1 placement_fac;
|
||||
static Factory2 paranoid_fac;
|
||||
static FactoryM malloc_fac;
|
||||
static FactoryP pimpl_fac;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*******************************************************************
|
||||
* testing the more advanced Factory variants and possibilities.
|
||||
* We use several customized Factory subclasses supporting custom
|
||||
* allocation, placement allocation, private construcors and
|
||||
* the PIpmpl design pattern. All creating smart pointers.
|
||||
*/
|
||||
class Factory_special_test : public Test
|
||||
{
|
||||
virtual void run(Arg arg)
|
||||
{
|
||||
uint num= isnil(arg)? 1 : lexical_cast<uint>(arg[1]);
|
||||
|
||||
checkPlacement (num);
|
||||
checkPrivate (num);
|
||||
checkMalloc ();
|
||||
checkPImpl () ;
|
||||
}
|
||||
|
||||
|
||||
/** @test using direct object placement instead of heap allocation.
|
||||
* Factory1 will place every new object into the same static buffer
|
||||
* and return a refcounting pointer
|
||||
*/
|
||||
void checkPlacement (uint cnt)
|
||||
{
|
||||
cout << "checkPlacement--------\n";
|
||||
|
||||
typedef Factory1::PType P;
|
||||
format msg ("created %d shared_ptrs to Object placed in static buffer.\n");
|
||||
void* raw (0);
|
||||
P pX;
|
||||
ASSERT (0 == pX.use_count());
|
||||
|
||||
{
|
||||
P p1 (placement_fac (cnt));
|
||||
P p2 (p1);
|
||||
P pX = p2;
|
||||
|
||||
cout << msg % p2.use_count()
|
||||
<< string (*pX) << "\n";
|
||||
|
||||
raw = p1.get(); // remember raw mem address
|
||||
}
|
||||
|
||||
ASSERT (0 == pX.use_count());
|
||||
|
||||
{
|
||||
P p1 (placement_fac (cnt+1));
|
||||
P p2 (p1);
|
||||
P p3 (p1);
|
||||
P pX = p2;
|
||||
|
||||
cout << msg % p2.use_count();
|
||||
|
||||
ASSERT (raw == p1.get(), "explicit object placement at fixed buffer doesn't work.");
|
||||
}
|
||||
|
||||
ASSERT (0 == pX.use_count());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/** @test simple factory creating std::auto_ptr wrapped instances
|
||||
* of an object with only private ctor and dtor.
|
||||
*/
|
||||
void checkPrivate (uint cnt)
|
||||
{
|
||||
cout << "checkPrivate--------\n";
|
||||
|
||||
typedef Factory2::PType P;
|
||||
format msg ("created %d shared_ptrs to paranoid Object.\n");
|
||||
P pX;
|
||||
|
||||
ASSERT (0 == pX.use_count());
|
||||
{
|
||||
P p1 (paranoid_fac (cnt));
|
||||
P p2 (p1);
|
||||
P pX = p2;
|
||||
|
||||
cout << msg % p2.use_count()
|
||||
<< string (*pX) << "\n";
|
||||
}
|
||||
ASSERT (0 == pX.use_count());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/** @test simple factory creating std::auto_ptr wrapped instances,
|
||||
* but of a class using a custom allocation scheme (here implemented
|
||||
* by direct C-style malloc calls)
|
||||
*/
|
||||
void checkMalloc (void)
|
||||
{
|
||||
cout << "checkMalloc--------\n";
|
||||
|
||||
typedef FactoryM::PType P;
|
||||
|
||||
P p1 (malloc_fac ());
|
||||
P p2 = p1;
|
||||
cout << ("created auto_ptr to malloc-ed Object.\n")
|
||||
<< string (*p2) << "\n";
|
||||
|
||||
ASSERT (!p1.get());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/** @test using direct object placement instead of heap allocation.
|
||||
* Factory1 will place every new object into the same static buffer
|
||||
* and return a refcounting pointer
|
||||
*/
|
||||
void checkPImpl (void)
|
||||
{
|
||||
cout << "checkPImpl--------\n";
|
||||
|
||||
typedef FactoryP::PType P;
|
||||
|
||||
P p1 (pimpl_fac ());
|
||||
P p2 = p1;
|
||||
cout << ("created auto_ptr to Interface Object.\n");
|
||||
p2->funky(); // call a Interface function
|
||||
|
||||
ASSERT (!p1.get());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/** Register this test class... */
|
||||
LAUNCHER (Factory_special_test, "unit common");
|
||||
|
||||
|
||||
|
||||
} // namespace test
|
||||
|
||||
} // namespace cinelerra
|
||||
|
|
@ -21,18 +21,16 @@
|
|||
* *****************************************************/
|
||||
|
||||
|
||||
#include "common/testtargetobj.hpp"
|
||||
|
||||
#include "common/test/run.hpp"
|
||||
#include "common/factory.hpp"
|
||||
#include "common/util.hpp"
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/format.hpp>
|
||||
#include <iostream>
|
||||
|
||||
using boost::algorithm::join;
|
||||
using boost::lexical_cast;
|
||||
using boost::format;
|
||||
using util::isnil;
|
||||
using std::string;
|
||||
using std::cout;
|
||||
|
|
@ -45,66 +43,28 @@ namespace cinelerra
|
|||
|
||||
class ObjFactory;
|
||||
|
||||
|
||||
/**
|
||||
* Target object to be created by the Test-Factory.
|
||||
* Allocates a variable amount of additional heap memory
|
||||
* and prints diagnostic messages.
|
||||
* and prints diagnostic messages. Note we provide a
|
||||
* static member TargetObj::create for the client
|
||||
* code to generate smart ptr wrapped instances.
|
||||
*/
|
||||
class TargetObj
|
||||
class TargetObj : public TestTargetObj
|
||||
{
|
||||
uint cnt_;
|
||||
string* heapData_;
|
||||
string* heapArray_;
|
||||
|
||||
|
||||
TargetObj(uint num)
|
||||
: cnt_ (num),
|
||||
heapData_ (new string(num,'*')),
|
||||
heapArray_ (new string[num])
|
||||
{
|
||||
for (uint i=0; i<cnt_; ++i)
|
||||
heapArray_[i] = lexical_cast<string>(i);
|
||||
cout << format("ctor TargetObj(%i) successfull\n") % cnt_;
|
||||
}
|
||||
|
||||
|
||||
~TargetObj() throw()
|
||||
{
|
||||
delete heapData_;
|
||||
delete[] heapArray_;
|
||||
cout << format("dtor ~TargetObj(%i) successfull\n") % cnt_;
|
||||
}
|
||||
|
||||
friend class ObjFactory;
|
||||
friend class std::tr1::_Sp_deleter<TargetObj>;
|
||||
|
||||
|
||||
public:
|
||||
static ObjFactory create;
|
||||
TargetObj (uint cnt) : TestTargetObj(cnt) {}
|
||||
|
||||
operator string () const
|
||||
{
|
||||
string array_contents = "{";
|
||||
for (uint i=0; i<cnt_; ++i)
|
||||
array_contents += heapArray_[i]+",";
|
||||
array_contents+="}";
|
||||
|
||||
return str (format(".....TargetObj(%1%): data=\"%2%\", array[%1%]=%3%")
|
||||
% cnt_
|
||||
% *heapData_
|
||||
% array_contents
|
||||
);
|
||||
}
|
||||
static ObjFactory create;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** Test-Factory specialized to create TargetObj instances
|
||||
* using the 1-argument constructor TargetObj::TargetObj(int).
|
||||
* It will create boost::shared_ptr instances, because
|
||||
* factory::RefcountPtr was parametrized with this smart pointer type.
|
||||
* @note ObjFactory can use the private constructor because it's a friend.
|
||||
*/
|
||||
class ObjFactory : public factory::RefcountPtr<TargetObj>
|
||||
{
|
||||
|
|
@ -119,7 +79,7 @@ namespace cinelerra
|
|||
|
||||
};
|
||||
|
||||
|
||||
|
||||
/** shorthand for the created smart-pointer class,
|
||||
* here it's a (refcounting) boost::shared_ptr
|
||||
*/
|
||||
|
|
|
|||
111
tests/components/common/testtargetobj.hpp
Normal file
111
tests/components/common/testtargetobj.hpp
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
/*
|
||||
TESTTARGETOBJ.hpp - a test (stub) target object for testing the factories
|
||||
|
||||
Copyright (C) CinelerraCV
|
||||
2007, Christian Thaeter <ct@pipapo.org>
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#ifndef CINELERRA_TEST_TESTTARGETOBJ_H
|
||||
#define CINELERRA_TEST_TESTTARGETOBJ_H
|
||||
|
||||
|
||||
#include "common/test/run.hpp"
|
||||
#include "common/factory.hpp"
|
||||
//#include "common/util.hpp"
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/format.hpp>
|
||||
#include <iostream>
|
||||
|
||||
using boost::algorithm::join;
|
||||
using boost::lexical_cast;
|
||||
using boost::format;
|
||||
using std::string;
|
||||
using std::cout;
|
||||
|
||||
|
||||
namespace cinelerra
|
||||
{
|
||||
namespace test
|
||||
{
|
||||
/**
|
||||
* Target object to be created by the Test-Factory.
|
||||
* Allocates a variable amount of additional heap memory
|
||||
* and prints diagnostic messages.
|
||||
*/
|
||||
class TestTargetObj
|
||||
{
|
||||
uint cnt_;
|
||||
string* heapData_;
|
||||
string* heapArray_;
|
||||
|
||||
public:
|
||||
TestTargetObj(uint num);
|
||||
~TestTargetObj() throw();
|
||||
|
||||
operator string () const;
|
||||
};
|
||||
|
||||
|
||||
|
||||
inline
|
||||
TestTargetObj::TestTargetObj(uint num)
|
||||
: cnt_ (num),
|
||||
heapData_ (new string(num,'*')),
|
||||
heapArray_ (new string[num])
|
||||
{
|
||||
for (uint i=0; i<cnt_; ++i)
|
||||
heapArray_[i] = lexical_cast<string>(i);
|
||||
cout << format("ctor TargetObj(%i) successfull\n") % cnt_;
|
||||
}
|
||||
|
||||
|
||||
inline
|
||||
TestTargetObj::~TestTargetObj() throw()
|
||||
{
|
||||
delete heapData_;
|
||||
delete[] heapArray_;
|
||||
cout << format("dtor ~TargetObj(%i) successfull\n") % cnt_;
|
||||
}
|
||||
|
||||
|
||||
|
||||
inline
|
||||
TestTargetObj::operator string () const
|
||||
{
|
||||
string array_contents = "{";
|
||||
for (uint i=0; i<cnt_; ++i)
|
||||
array_contents += heapArray_[i]+",";
|
||||
array_contents+="}";
|
||||
|
||||
return str (format(".....TargetObj(%1%): data=\"%2%\", array[%1%]=%3%")
|
||||
% cnt_
|
||||
% *heapData_
|
||||
% array_contents
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
} // namespace test
|
||||
|
||||
} // namespace cinelerra
|
||||
#endif
|
||||
Loading…
Reference in a new issue