379 lines
11 KiB
C++
379 lines
11 KiB
C++
// Registrar.h -- Registrar template class
|
|
|
|
// (c) Copyright Schlumberger Technology Corp., unpublished work, created
|
|
// 1999. This computer program includes Confidential, Proprietary
|
|
// Information and is a Trade Secret of Schlumberger Technology Corp. All
|
|
// use, disclosure, and/or reproduction is prohibited unless authorized
|
|
// in writing. All Rights Reserved.
|
|
|
|
#if !defined(SLBCSP_REGISTRAR_H)
|
|
#define SLBCSP_REGISTRAR_H
|
|
|
|
#include <map>
|
|
#include <functional>
|
|
#include <algorithm>
|
|
|
|
#include "Guarded.h"
|
|
#include "Registry.h"
|
|
#include "MasterLock.h"
|
|
|
|
template<class Key, class T, class Cmp = std::less<Key> >
|
|
class Registrar
|
|
{
|
|
public:
|
|
// Types
|
|
typedef T *EnrolleeType;
|
|
typedef Key KeyType;
|
|
typedef std::map<Key, EnrolleeType, Cmp> CollectionType;
|
|
typedef Registry<CollectionType> RegistryType;
|
|
typedef Registry<CollectionType const> ConstRegistryType;
|
|
|
|
// C'tors/D'tors
|
|
// Operators
|
|
// Operations
|
|
// Removes the enrollee identified by the key from the registry.
|
|
static void
|
|
Discard(Key const &rkey);
|
|
|
|
// Return the enrollee identified by the key, creating it if it
|
|
// doesn't exist.
|
|
static EnrolleeType
|
|
Instance(Key const &rkey);
|
|
|
|
// Access
|
|
// Return the enrollee identified by the key if it exists, 0 otherwise.
|
|
static EnrolleeType
|
|
Find(Key const &rKey);
|
|
|
|
static ConstRegistryType &
|
|
Registry();
|
|
|
|
// Predicates
|
|
|
|
protected:
|
|
// Types
|
|
// C'tors/D'tors
|
|
explicit
|
|
Registrar(Key const &rkey); // allow subclassing
|
|
|
|
virtual
|
|
~Registrar() = 0; // make base abstract
|
|
|
|
|
|
// Operators
|
|
// Operations
|
|
// Puts the enrollee into the registry identified by the key if
|
|
// not already listed.
|
|
static void
|
|
Enroll(Key const &rkey,
|
|
EnrolleeType enrollee);
|
|
// Removes an entry from the registry.
|
|
static void
|
|
RemoveEnrollee(Key const &rkey);
|
|
|
|
// Inserts an entry into the registry.
|
|
static void
|
|
InsertEnrollee(Key const &rkey, EnrolleeType enrollee);
|
|
|
|
|
|
// Operation to perform after removing the enrollee from the
|
|
// registry. Default does nothing.
|
|
virtual void
|
|
DiscardHook();
|
|
|
|
|
|
// Subclass must define
|
|
// Factory Method, operation returning a new enrollee for the key
|
|
static EnrolleeType
|
|
DoInstantiation(Key const &rkey);
|
|
|
|
// Operation to perform after putting the enrollee into the
|
|
// registry. Default does nothing.
|
|
virtual void
|
|
EnrollHook();
|
|
|
|
// Access
|
|
// Predicates
|
|
// Returns true if the enrollee should remain in the registry;
|
|
// false otherwise. Default returns true.
|
|
virtual bool
|
|
KeepEnrolled();
|
|
|
|
// Static Variables
|
|
// Variables
|
|
|
|
private:
|
|
// Types
|
|
typedef typename Registrar<Key, T, Cmp> *BaseType;
|
|
typedef CollectionType::iterator Iterator;
|
|
typedef CollectionType::value_type ValueType;
|
|
|
|
|
|
|
|
// C'tors/D'tors
|
|
Registrar(Registrar const &); // don't allow copies
|
|
|
|
// Operators
|
|
Registrar<Key, T> &
|
|
operator=(Registrar const &); // don't allow initialization
|
|
|
|
// Operations
|
|
static void
|
|
Discard(Iterator const &rit);
|
|
|
|
static void
|
|
RemoveEnrollee(Iterator const &rit);
|
|
|
|
static EnrolleeType
|
|
FindEnrollee(Key const &rkey);
|
|
|
|
static void
|
|
SetupRegistry();
|
|
|
|
// Access
|
|
static CollectionType &
|
|
Collection();
|
|
|
|
// Predicates
|
|
static bool
|
|
PassesReview(EnrolleeType enrollee);
|
|
|
|
// Variables
|
|
static RegistryType *m_pregistry;
|
|
};
|
|
|
|
///////////////////////// TEMPLATE METHODS ///////////////////////////////
|
|
|
|
/////////////////////////// PUBLIC /////////////////////////////////
|
|
|
|
// C'tors/D'tors
|
|
// Operators
|
|
// Operations
|
|
template<class Key, class T, class Cmp>
|
|
void
|
|
Registrar<Key, T, Cmp>::Discard(Key const &rkey)
|
|
{
|
|
if (m_pregistry)
|
|
{
|
|
Guarded<RegistryType *> gregistry(m_pregistry); // serialize registry access
|
|
|
|
CollectionType &rcollection = Collection();
|
|
Iterator it = rcollection.find(rkey);
|
|
|
|
if (rcollection.end() != it)
|
|
Discard(it);
|
|
}
|
|
}
|
|
|
|
template<class Key, class T, class Cmp>
|
|
Registrar<Key, T, Cmp>::EnrolleeType
|
|
Registrar<Key, T, Cmp>::Instance(Key const &rkey)
|
|
{
|
|
// The Template Method pattern is used to allow the instantiator
|
|
// of the template to specify how the the enrollee is found and,
|
|
// if necessary, created. Template Method can be found in "Design
|
|
// Patterns: Elements of Reusable Object-Oriented Software,"
|
|
// Gamma, Helm, Johnson, Vlissides, Addison-Wesley
|
|
|
|
SetupRegistry();
|
|
|
|
Guarded<RegistryType *> gregistry(m_pregistry); // serialize registry access
|
|
|
|
EnrolleeType enrollee = FindEnrollee(rkey);
|
|
if (EnrolleeType() == enrollee)
|
|
{
|
|
enrollee = T::DoInstantiation(rkey);
|
|
Enroll(rkey, enrollee);
|
|
}
|
|
|
|
return enrollee;
|
|
}
|
|
|
|
// Access
|
|
template<class Key, class T, class Cmp>
|
|
Registrar<Key, T, Cmp>::EnrolleeType
|
|
Registrar<Key, T, Cmp>::Find(Key const &rkey)
|
|
{
|
|
EnrolleeType enrollee = EnrolleeType();
|
|
|
|
if (m_pregistry)
|
|
{
|
|
Guarded<RegistryType *> guard(m_pregistry); // serialize registry access
|
|
|
|
enrollee = FindEnrollee(rkey);
|
|
}
|
|
|
|
return enrollee;
|
|
}
|
|
|
|
template<class Key, class T, class Cmp>
|
|
Registrar<Key, T, Cmp>::ConstRegistryType &
|
|
Registrar<Key, T, Cmp>::Registry()
|
|
{
|
|
SetupRegistry();
|
|
|
|
// this "safe" cast is necessary to enforce the constness of the collection
|
|
return reinterpret_cast<ConstRegistryType &>(*m_pregistry);
|
|
}
|
|
|
|
// Predicates
|
|
// Static Variables
|
|
|
|
/////////////////////////// PROTECTED /////////////////////////////////
|
|
|
|
// C'tors/D'tors
|
|
template<class Key, class T, class Cmp>
|
|
Registrar<Key, T, Cmp>::Registrar(Key const &rkey)
|
|
{}
|
|
|
|
template<class Key, class T, class Cmp>
|
|
Registrar<Key, T, Cmp>::~Registrar()
|
|
{}
|
|
|
|
// Operators
|
|
// Operations
|
|
template<class Key, class T, class Cmp>
|
|
void
|
|
Registrar<Key, T, Cmp>::DiscardHook()
|
|
{}
|
|
|
|
template<class Key, class T, class Cmp>
|
|
void
|
|
Registrar<Key, T, Cmp>::EnrollHook()
|
|
{}
|
|
|
|
template<class Key, class T, class Cmp>
|
|
void
|
|
Registrar<Key, T, Cmp>::RemoveEnrollee(Key const &rkey)
|
|
{
|
|
if (m_pregistry)
|
|
{
|
|
Guarded<RegistryType *> gregistry(m_pregistry); // serialize registry access
|
|
|
|
CollectionType &rcollection = Collection();
|
|
Iterator it = rcollection.find(rkey);
|
|
|
|
if (rcollection.end() != it)
|
|
RemoveEnrollee(it);
|
|
}
|
|
}
|
|
|
|
template<class Key, class T, class Cmp>
|
|
void
|
|
Registrar<Key, T, Cmp>::InsertEnrollee(Key const &rkey,
|
|
Registrar<Key, T, Cmp>::EnrolleeType enrollee)
|
|
{
|
|
ValueType registration(rkey, enrollee);
|
|
Guarded<RegistryType *> guard(m_pregistry); // serialize registry access
|
|
Collection().insert(registration);
|
|
}
|
|
|
|
// Access
|
|
// Predicates
|
|
template<class Key, class T, class Cmp>
|
|
bool
|
|
Registrar<Key, T, Cmp>::KeepEnrolled()
|
|
{
|
|
return true;
|
|
}
|
|
|
|
template<class Key, class T, class Cmp>
|
|
void
|
|
Registrar<Key, T, Cmp>::Enroll(Key const &rkey,
|
|
Registrar<Key, T, Cmp>::EnrolleeType enrollee)
|
|
{
|
|
Guarded<RegistryType *> guard(m_pregistry); // serialize registry access
|
|
|
|
InsertEnrollee(rkey, enrollee);
|
|
|
|
BaseType base = enrollee;
|
|
base->EnrollHook();
|
|
}
|
|
|
|
|
|
/////////////////////////// PRIVATE /////////////////////////////////
|
|
|
|
// C'tors/D'tors
|
|
// Operators
|
|
// Operations
|
|
template<class Key, class T, class Cmp>
|
|
void
|
|
Registrar<Key, T, Cmp>::Discard(Registrar<Key, T, Cmp>::Iterator const &rit)
|
|
{
|
|
BaseType base = rit->second;
|
|
RemoveEnrollee(rit);
|
|
base->DiscardHook();
|
|
}
|
|
|
|
template<class Key, class T, class Cmp>
|
|
void
|
|
Registrar<Key, T, Cmp>::RemoveEnrollee(Registrar<Key, T, Cmp>::Iterator const &rit)
|
|
{
|
|
Collection().erase(rit);
|
|
}
|
|
|
|
template<class Key, class T, class Cmp>
|
|
Registrar<Key, T, Cmp>::EnrolleeType
|
|
Registrar<Key, T, Cmp>::FindEnrollee(Key const &rkey)
|
|
{
|
|
EnrolleeType enrollee = EnrolleeType();
|
|
|
|
CollectionType &rcollection = Collection();
|
|
if (!rcollection.empty())
|
|
{
|
|
Iterator it = rcollection.find(rkey);
|
|
if (rcollection.end() != it)
|
|
{
|
|
enrollee = it->second;
|
|
|
|
if (!PassesReview(enrollee))
|
|
{
|
|
Discard(it);
|
|
enrollee = EnrolleeType();
|
|
}
|
|
}
|
|
}
|
|
|
|
return enrollee;
|
|
}
|
|
|
|
template<class Key, class T, class Cmp>
|
|
void
|
|
Registrar<Key, T, Cmp>::SetupRegistry()
|
|
{
|
|
// Use Double-Checked Lock pattern for proper setup in the case of
|
|
// preemptive multi-threading
|
|
if (!m_pregistry)
|
|
{
|
|
Guarded<Lockable *> gmaster(&TheMasterLock());
|
|
if (!m_pregistry)
|
|
m_pregistry = new RegistryType;
|
|
}
|
|
|
|
}
|
|
|
|
// Access
|
|
template<class Key, class T, class Cmp>
|
|
Registrar<Key, T, Cmp>::CollectionType &
|
|
Registrar<Key, T, Cmp>::Collection()
|
|
{
|
|
return (*m_pregistry)();
|
|
}
|
|
|
|
// Predicates
|
|
template<class Key, class T, class Cmp>
|
|
bool
|
|
Registrar<Key, T, Cmp>::PassesReview(Registrar<Key, T, Cmp>::EnrolleeType enrollee)
|
|
{
|
|
bool fPassed = false;
|
|
if (EnrolleeType() != enrollee)
|
|
{
|
|
BaseType base = enrollee;
|
|
fPassed = base->KeepEnrolled();
|
|
}
|
|
|
|
return fPassed;
|
|
}
|
|
|
|
#endif // SLBCSP_REGISTRAR_H
|