LUMIERA.clone/src/lib/handle.hpp

136 lines
4.8 KiB
C++

/*
HANDLE.hpp - opaque handle to an implementation entity, automatically managing lifecycle
Copyright (C) Lumiera.org
2009, 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.
*/
/** @file handle.hpp
** A generic opaque handle to an implementation entity, including lifecycle management.
** The intended use is for some public interface to return such a handle to track the
** lifecycle or registration of a dedicated service created for this call. The handle
** is implemented as refcounting smart-ptr on top of shared_ptr, which especially
** means for the client code that the handle has value semantics, can be copied and
** stored, while the referred service will stay alive as long as there is still an
** handle in use. A handle may be empty ("null handle") or closed; the latter
** also decreases the ref count and can be used to close a service explicitly.
**
** Possibly a service may use an extension of the handle template carrying dedicated
** API functions. In this case, the handle acts like a PImpl; the actual definition
** of the implementation class the handle points at is necessary only in the
** translation unit implementing such an extended handle.
**
** @see proc::DummyPlayer::Process usage example
**
*/
#ifndef LIB_HANDLE_H
#define LIB_HANDLE_H
#include "lib/nobug-init.hpp"
#include "lib/sync.hpp"
#include <tr1/memory>
namespace lib {
using std::tr1::shared_ptr;
using std::tr1::weak_ptr;
/**
* Generic opaque reference counting handle, for accessing a service
* and managing its lifecycle. Usually such a handle is created by
* an service interface and \link #activate activated \endlink by
* setting up the link to some internal implementation object.
* This setup can only be done by a friend or derived class,
* while client code is free to copy and store handle objects.
* Finally, any handle can be closed, thereby decrementing
* the use count.
*/
template<class IMP>
class Handle
{
protected:
std::tr1::shared_ptr<IMP> smPtr_;
public:
/** by default create an Null handle.
* Typically this is followed by activating
* the handle by the managing service.
*/
Handle ( )
: smPtr_()
{ }
Handle (Handle const& r) : smPtr_(r.smPtr_) { }
template<class Y> explicit Handle (shared_ptr<Y> const& r) : smPtr_(r) { }
template<class Y> explicit Handle (weak_ptr<Y> const& wr) : smPtr_(wr) { }
template<class Y> explicit Handle (std::auto_ptr<Y> & ar) : smPtr_(ar) { }
Handle& operator=(Handle const& r) { smPtr_ = r.smPtr_; return *this; }
template<class Y> Handle& operator=(shared_ptr<Y> const& sr) { smPtr_ = sr; return *this; }
template<class Y> Handle& operator=(std::auto_ptr<Y> & ar) { smPtr_ = ar; return *this; }
/** Activation of the handle by the managing service.
* @param impl the implementation object this handle is tied to
* @param whenDead functor to be invoked when reaching end-of-life
*/
template<typename DEL>
Handle&
activate (IMP* impl, DEL whenDead)
{
smPtr_.reset (impl, whenDead);
return *this;
}
/** deactivate this handle, so it isn't tied any longer
* to the associated implementation or service object.
* When all handles have either been deactivated or
* went out of scope, the associated implementation
* reaches end-of-life.
*/
void close () { smPtr_.reset(); }
typedef std::tr1::shared_ptr<IMP> Handle::*__unspecified_bool_type;
/** implicit conversion to "bool" */
operator __unspecified_bool_type() const { return &Handle::smPtr_; } // never throws
bool operator! () const { return !bool(smPtr_); } // dito
protected:
IMP&
impl()
{
REQUIRE (smPtr_.get(), "Lifecycle-Error");
return *(smPtr_.get());
}
};
} // namespace lib
#endif