cleanup: remove the old factory template

This template was a leftover from the early days
of Lumiera development and doesn't provide any
substantial value as an abstraction.

For the more intricate cases, we're using the
lib::MultiFact template, which allows to install
several "fabrication" functions at runtime
This commit is contained in:
Fischlurch 2012-10-14 01:30:08 +02:00
parent 23cac22a9f
commit 62bfccd67b
12 changed files with 48 additions and 661 deletions

View file

@ -1,144 +0,0 @@
/*
FACTORY.hpp - template for object/smart-pointer factories
Copyright (C) Lumiera.org
2008, 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.
*/
#ifndef LIB_FACTORY_H
#define LIB_FACTORY_H
#include <tr1/memory>
namespace lib {
namespace factory {
/**
* Wrapping any object created by the Factory into some smart ptr class.
* The Factory class inherits this functionality, so it can be exchanged
* independently from the actual object creation behaviour. For example,
* an Factory implementing some elaborate subclass creation scheme could
* be instantiated to either produce auto-ptrs or shared-ptrs.
*/
template
< class T, // the product to be created
class SMP =std::auto_ptr<T> // smart-pointer actually returned
>
class Wrapper
{
protected:
SMP wrap (T* product) { return SMP (product); }
public:
typedef SMP PType;
};
/**
* Basic Factory Template, for defining flexible Factory classes.
* These encapsulate the logic for creating of new objects, maybe
* delegating the memory allocation to the backend layer. Usually,
* the clients get just a smart-pointer or similar handle to the
* created object, which will manage the ownership.
*
* The provided default implementation uses just std::auto_ptr.
*/
template
< class T, // the product to be created
class WR = Wrapper<T> // used for fabricating the wrapper
>
class Factory : public WR
{
public:
/** Object creating facility.
* Intended to be over/written/ with a variant taking
* the appropriate number of parameters and maybe
* using some special custom allocator.
* Note: non-virtual.
*/
typename WR::PType operator() () { return wrap (new T ); }
};
/* -- some example and default instantiations -- */
using std::tr1::shared_ptr;
/**
* a frequently used instantiation of the Wrapper,
* Utilising the refcounting tr1::shared_ptr.
*/
template<class T>
class Wrapper<T, shared_ptr<T> >
{
protected:
shared_ptr<T> wrap (T* product) { return shared_ptr<T> (product); }
public:
typedef shared_ptr<T> PType;
};
/**
* Shortcut: commonly used (partial) instantiation of the Factory,
* generating refcounting shared_ptr wrapped Objects. Built upon
* the corresponding special instantiation of the Wrapper template.
*/
template<class T>
class RefcountFac : public Factory<T, Wrapper<T,shared_ptr<T> > >
{
public:
typedef shared_ptr<T> PType;
};
/**
* another convenience instantiation: auto_ptr-to-Impl-Factory.
* Creating an implementation subclass and wraps into auto_ptr.
* @warning the TImpl object will typically be destroyed by the
* smart ptr using an T*, so ~T() needs to be virtual.
*/
template
< class T, // Interface class
class TImpl // Implementation class to be created
>
class PImplFac : public Factory<T, Wrapper<T> >
{
public:
typedef std::auto_ptr<T> PType;
PType operator() (){ return wrap (static_cast<T*> (new TImpl)); };
};
} // namespace factory
/// @note Factory can be usable as-is (wraps into std::auto_ptr)
using factory::Factory;
} // namespace lib
#endif

View file

@ -20,7 +20,7 @@
*/
/** @file multifact.hpp
/** @file multifact-arg.hpp
** Extension allowing the MultiFact to pass arguments to the fabrication.
** This extension is implemented by template specialisations and thus kicks in
** when specifying a function \em signature as factory "product type". The resulting

View file

@ -21,12 +21,13 @@
*/
/** @file multifact.hpp
** Building blocks to create a configurable factory, generating families of related objects.
** Serving the "classical" factory situation: obtaining objects of various kinds, which
** are related somehow (usually through an common interface). The creation of these
** objects is non-trivial while number and exact parametrisation aren't known beforehand
** and need to be figured out at runtime. Thus, a number of "fabrication lines" is set up,
** to be selected on invocation through an ID (which may be symbolic, hashed or structural).
** Framework for building a configurable factory, to generae families of related objects.
** These building blocks are targeted towards the "classical" factory situation: obtaining
** objects of various kinds, which are related somehow (usually through an common interface).
** The creation of these objects might be non-trivial, while the number of flavours to be
** produced and the exact parametrisation isn't known beforehand and needs to be figured out
** at runtime. As a solution, thus a number of "fabrication lines" is set up, to be selected
** on invocation through an ID (which may be symbolic, hashed or structural).
**
** Usually, the issue of object and storage management is closely related, while it is
** desirable to keep the object production logic clean of these rather technical concerns.
@ -38,7 +39,7 @@
** function.
**
** \par Singleton generation
** For the very common situation of needing various singleton objects, accessible by ID,
** For the very common situation of building a family of singleton objects, accessible by ID,
** there is a convenience shortcut: The nested MultiFact::Singleton template can be instantiated
** within the context providing the objects (usually a static context). In itself a lib::Singleton
** factory, it automatically registers the singleton access function as "fabrication" function
@ -48,6 +49,7 @@
** for the special case when the fabrication functions need additional invocation arguments.
**
** @see multifact-test.cpp
** @see multifact-argument-test.cpp
** @see SingletonFactory
** @see lib::factory::Factory
*/
@ -70,7 +72,7 @@
namespace lib {
namespace factory {
/////////////////////////////////TICKET #470 : couldn't these wrappers be extracted into a separate header?
// Helpers to wrap the factory's product
/**
* Dummy "wrapper",

View file

@ -36,11 +36,12 @@
#define ASSET_MEDIA_H
#include "proc/asset.hpp"
#include "lib/factory.hpp"
#include "lib/time/timevalue.hpp"
#include "proc/mobject/mobject.hpp"
#include "proc/mobject/session/clip.hpp"
#include <boost/noncopyable.hpp>
namespace proc {
@ -138,7 +139,8 @@ namespace asset {
/**
* Factory specialised for creating Media Asset objects.
*/
class MediaFactory : public lib::Factory<asset::Media>
class MediaFactory
: boost::noncopyable
{
public:
typedef P<Media> PType;

View file

@ -60,8 +60,8 @@
#include "proc/asset.hpp"
#include "proc/asset/entry-id.hpp"
#include "lib/factory.hpp"
#include <boost/noncopyable.hpp>
namespace proc {
@ -145,7 +145,8 @@ namespace asset {
/**
* Factory specialised for creating Metadata Asset objects.
*/
class MetaFactory : public lib::Factory<asset::Meta>
class MetaFactory
: boost::noncopyable
{
public:
typedef P<asset::Meta> PType;

View file

@ -36,9 +36,10 @@
#define ASSET_PROC_H
#include "proc/asset.hpp"
#include "lib/factory.hpp"
#include "proc/streamtype.hpp"
#include <boost/noncopyable.hpp>
namespace proc {
@ -113,7 +114,8 @@ namespace asset {
/**
* Factory specialised for creating Processor Asset objects.
*/
class ProcFactory : public lib::Factory<asset::Proc>
class ProcFactory
: boost::noncopyable
{
public:
typedef P<asset::Proc> PType;

View file

@ -59,10 +59,9 @@
#include "proc/asset.hpp"
#include "lib/query.hpp"
#include "lib/factory.hpp"
#include "lib/singleton.hpp"
#include "lib/symbol.hpp"
#include <boost/noncopyable.hpp>
#include <boost/scoped_ptr.hpp>
#include <string>
@ -134,7 +133,8 @@ namespace asset {
/**
* Factory specialised for creating Structural Asset objects.
*/
class StructFactory : public lib::Factory<asset::Struct>
class StructFactory
: boost::noncopyable
{
scoped_ptr<StructFactoryImpl> impl_;

View file

@ -280,42 +280,6 @@ out: caught error::Logic: LUMIERA_ERROR_LOGIC:internal logic broken \(the big ba
END
TEST "Factory_test" Factory_test 5 <<END
out: ctor TargetObj\(5\) successful
out: now the smart-ptr has refcount=3
out: .....TargetObj\(5\): data="\*\*\*\*\*", array\[5\]=\{0,1,2,3,4,\}
out: dtor ~TargetObj\(5\) successful
END
TEST "Factory_special_test" Factory_special_test 5 <<END
out: checkPlacement--------
out: ctor TargetObj\(5\) successful
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\) successful
out: ctor TargetObj\(6\) successful
out: created 4 shared_ptrs to Object placed in static buffer.
out: dtor ~TargetObj\(6\) successful
out: checkPrivate--------
out: ctor TargetObj\(5\) successful
out: created 3 shared_ptrs to paranoid Object.
out: .....TargetObj\(5\): data="\*\*\*\*\*", array\[5\]=\{0,1,2,3,4,\}
out: dtor ~TargetObj\(5\) successful
out: checkMalloc--------
out: ctor TargetObj\(7\) successful
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\) successful
out: checkPImpl--------
out: ctor TargetObj\(12\) successful
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\) successful
END
TEST "formatting/diagnostics helpers" FormatHelper_test <<END
out: Displaying some types....
out: «..util.test.Reticent.»

View file

@ -25,7 +25,6 @@
#include "lib/util.hpp"
#include "proc/mobject/session/defs-registry.hpp"
#include "lib/factory.hpp"
#include "lib/query.hpp"
#include "lib/p.hpp"
@ -83,6 +82,13 @@ namespace test {
template<int I>
string Dummy<I>::name = str (typePatt % I);
template<int I>
inline P<Dummy<I> >
fabricate()
{
return P<Dummy<I> >(new Dummy<I>);
}
@ -109,22 +115,21 @@ namespace test {
typedef DefsRegistry::Iter<Dummy<23> > Iter23;
// fabricating Objects wrapped into smart-ptrs
lib::factory::RefcountFac<Dummy<13> > oFac;
lib::factory::RefcountFac<Dummy<23> > pFac;
// some test objects...
Obj o1, o2, o3;
Q13 q1, q2, q3, q4, q5;
map<Q23, Prd> ps;
public:
DefsRegistryImpl_test ()
: o1 (oFac()), o2 (oFac()), o3 (oFac()),
q1 (garbage_query (1)),
q2 (garbage_query (2)),
q3 (garbage_query (3)),
q4 (garbage_query (4)),
q5 (garbage_query (5))
: o1 (fabricate<13>())
, o2 (fabricate<13>())
, o3 (fabricate<13>())
, q1 (garbage_query (1))
, q2 (garbage_query (2))
, q3 (garbage_query (3))
, q4 (garbage_query (4))
, q5 (garbage_query (5))
{ }
@ -158,7 +163,7 @@ namespace test {
ps.clear();
for (int i=0; i<100; ++i)
{
Prd px (pFac());
Prd px (fabricate<23>());
Q23 qx (garbage_query());
ps[qx] = px;
reg_->put (px, qx);
@ -276,7 +281,7 @@ namespace test {
CHECK (!reg_->forget (o1)); // failure, because it's already removed
CHECK ( reg_->forget (o2));
o3 = oFac(); // another object is another object (it's irrelevant...)
o3 = fabricate<13>(); // another object is another object (it's irrelevant...)
i = reg_->candidates(q2);
CHECK (! (*i)); // empty

View file

@ -1,322 +0,0 @@
/*
Factory-Special(Test) - testing the more advanced features of factory
Copyright (C) Lumiera.org
2008, 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.
* *****************************************************/
#include "lib/test/run.hpp"
#include "lib/util.hpp"
#include "testtargetobj.hpp"
#include "lib/factory.hpp"
#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 lib {
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 specialised 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;
/** Specialised 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 function
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::PImplFac<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 customised Factory subclasses supporting custom
* allocation, placement allocation, private constructors 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;
CHECK (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
}
CHECK (0 == pX.use_count());
{
P p1 (placement_fac (cnt+1));
P p2 (p1);
P p3 (p1);
P pX = p2;
cout << msg % p2.use_count();
CHECK (raw == p1.get(), "explicit object placement at fixed buffer doesn't work.");
}
CHECK (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;
CHECK (0 == pX.use_count());
{
P p1 (paranoid_fac (cnt));
P p2 (p1);
P pX = p2;
cout << msg % p2.use_count()
<< string (*pX) << "\n";
}
CHECK (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";
CHECK (!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
CHECK (!p1.get());
}
};
/** Register this test class... */
LAUNCHER (Factory_special_test, "unit common");
}} // lib::test

View file

@ -1,124 +0,0 @@
/*
Factory(Test) - unittest for the object creating factory
Copyright (C) Lumiera.org
2008, 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.
* *****************************************************/
#include "testtargetobj.hpp"
#include "lib/test/run.hpp"
#include "lib/factory.hpp"
#include "lib/util.hpp"
#include <boost/lexical_cast.hpp>
#include <iostream>
using boost::lexical_cast;
using util::isnil;
using std::string;
using std::cout;
namespace lib {
namespace test{
class ObjFactory;
/**
* Target object to be created by the Test-Factory.
* Allocates a variable amount of additional heap memory
* and prints diagnostic messages. Note we provide a
* static member TargetObj::create for the client
* code to generate smart ptr wrapped instances.
*/
class TargetObj : public TestTargetObj
{
public:
TargetObj (uint cnt) : TestTargetObj(cnt) {}
static ObjFactory create;
};
/** Test-Factory specialised to create TargetObj instances
* using the 1-argument constructor TargetObj::TargetObj(int).
* It will create std::shared_ptr instances, because
* factory::RefcountFac was parametrised with this smart pointer type.
*/
class ObjFactory : public factory::RefcountFac<TargetObj>
{
public:
/** specialised Factory method for creating TargetObj instances.
* Here, we invoke a special constructor, but basically we could
* do everything we want, creating instances of sub classes,
* registering objects etc. Further, we could have used a
* custom allocator or a special deleter function.
*/
PType operator() (uint param) { return wrap (new TargetObj(param) ); }
};
/** shorthand for the created smart-pointer class,
* here it's a (refcounting) std::shared_ptr
*/
typedef ObjFactory::PType pTarget;
ObjFactory TargetObj::create;
/*******************************************************************
* @test the basic object creation Factory behaviour: We declared
* a static field TargetObj::create to be a ObjFactory. So,
* by invoking this functor, we get a std::shared_ptr
* wrapping a new TargetObj instance. From this we copy
* further shared-ptrs, invoke a member function and
* finally, when leaving the scope, our TargetObj
* will be destroyed automatically.
* @see lib::Factory
*/
class Factory_test : public Test
{
virtual void run(Arg arg)
{
uint num= isnil(arg)? 1 : lexical_cast<uint>(arg[1]);
pTarget p1 (TargetObj::create (num));
pTarget p2 (p1);
pTarget p3 = p2;
cout << "now the smart-ptr has refcount=" << p1.use_count() << "\n"
<< string (*p3) << "\n";
}
};
/** Register this test class... */
LAUNCHER (Factory_test, "unit common");
}} // namespace lib::test

View file

@ -85,10 +85,11 @@ namespace test{
* @test define a MultiFact (factory with dynamic registration),
* which accepts additional arguments and passes them
* through to the registered factory function(s).
* @note we set up fabrication functions by binding such as to match
* the function signature declared in the factory; thereby one
* argument remains unclosed, which is the argument to be
* supplied on each factory invocation by the client code.
* @note we set up fabrication functions by binding the functions
* in such a way as to match the function signature declared
* in the factory; thereby one argument remains unclosed,
* which is the argument to be supplied on each
* factory invocation by the client code.
*
* @see lib::MultiFact
* @see query-resolver.cpp