/** @file
$Id$
$Date$
$Author$
@copy © Marc Wäckerlin
@license LGPL, see file COPYING
*/
#ifndef __MRW_AUTO_HPP__
#define __MRW_AUTO_HPP__
#include // size_t
#include // munmap, PROT_READ, MAP_SHARED
#include // close
#include
#include
#include // free
// forward
class bfd;
extern "C" int bfd_close(bfd*);
namespace mrw {
/** @defgroup AutoTools Classes for Automated Resource Handling
For pointers that have been allocated with @c new, you can use
std::auto_ptr to automatically free them when you leave the
context. Unfortunately there is no such thing for @c malloc
(except @c malloca that only works for a subset of problems: if
you and not a system call allocates memory), @c open and so on.
These classes can take over the resource ownership.
The following ressource handler are predefined:
- mrw::AutoPtr<> is the same as std::auto_ptr, but can be stored
in STL containers
@code
mrw::AutoPtr xyz(new ClassName(a, b, c));
@endcode
- mrw::MMapHandle frees an @c mmap handle with @c munmap
- mrw::Auto<>::Free frees @c malloc allocated memory with @c free
@code
mrw::Auto::Free xxx((char*)malloc(15));
@endcode
- mrw::SmartPointer<> is a shared pointer that deletes memory
when all owners have died
@code
mrw::SmartPointer xyz(new ClassName(a, b, c));
@endcode
- mrw::Pipe handles UNIX pipes and closes them on exit
- mrw::AutoFile automatically closes open files
- mrw::AutoMapper calls @c munmap on memory mapped files
- mrw::AutoBfd automatically calls @c bfd_close
If this is not enough, you can @c typedef your own ressource
handler from the template class mrw::AutoResource<>. For example,
mrw::AutoFile is defined as:
@code
typedef mrw::AutoResource mrw::AutoFile;
@endcode
*/
//@{
/** @brief Automatically frees a resource when destructed.
@pre \#include
AutoResource works exactly like std::auto_ptr, but for any
resource instead of new allocated pointers. Whenever the context
of AutoResource is left, the resource is freed by a call to the
given function. This way, resources are freed even in case of
exceptions.
Declare an automated file descriptor handler, a BFD handler and
a @c malloc-/ @c free handler (all these typedefs are already
part of the library):
@code
typedef mrw::AutoResource AutoFile;
typedef mrw::AutoResource AutoBfd;
template class Auto {
public:
typedef mrw::AutoResource Free;
};
@endcode
@param RESOURCE_TYPE type of the resource to manage
@param FUNCTION_PTR type of the function that frees the resource
@param FREE_FUNCTION the function that frees the resource
@param INITIAL_VALUE_TYPE type of the initial value
(pointers may have to be initialized by an integer)
@param INITIAL_VALUE value when the resource is unassigned
@param FREE_TYPE type to free, if cast is needed
*/
template
class AutoResource {
public:
/// @brief Construct from an allocated resource.
/// The resource is freed if necessary.
/// AutoResource takes over ownership of the resource.
explicit AutoResource(FREE_TYPE res = INITIAL_VALUE)
throw(std::bad_exception): _res((RESOURCE_TYPE)res) {
}
/// @brief Takeover ownership from another AutoResource.
AutoResource(AutoResource& o) throw(std::bad_exception):
_res(o.release()) {
}
//! @brief Do not use this method!
//! This method had to be introduced for the @c std::map, where
//! @c operator[] first creates an empty element, then assigns it
//! the real value. Because that empty element is temporary, gcc can
//! not use @c AutoResource(AutoResource&) since release 4.0.
AutoResource(const AutoResource& o) throw(std::bad_exception):
_res(INITIAL_VALUE) {
assert(o._res==INITIAL_VALUE);
if (o._res!=INITIAL_VALUE)
_res = const_cast(o).release();
}
/// @brief Free resource. Calls @c reset().
~AutoResource() throw(std::bad_exception) {reset();}
/// @brief Assign new resource. Calls @c reset().
/// The resource is freed if necessary.
AutoResource& operator=(RESOURCE_TYPE res) throw(std::bad_exception) {
return reset(res);
}
/// @brief Takeover ownership from another AutoResource.
/// Calls @c reset() from @c this and @c release() from @c other.
AutoResource& operator=(AutoResource& other) throw(std::bad_exception) {
return reset(other.release());
}
/// @brief Get the resource.
operator const RESOURCE_TYPE&() const throw(std::bad_exception) {
return _res;
}
/// @brief find out, if a value is set
/// @return @c true: resource is valid
operator bool() const throw(std::bad_exception) {
return _res!=INITIAL_VALUE;
}
/// @brief get the resetted resource for resetting it.
/// Calls @c reset and returns the cleaned resource.
/// The intention is, that you can safely assign it a new value
/// (e.g. in an expression).
RESOURCE_TYPE& getClean() throw(std::bad_exception) {
reset();
return _res;
}
/// @brief Give away ownership of the resource.
/// @return old resource
RESOURCE_TYPE release() throw(std::bad_exception) {
RESOURCE_TYPE res(_res); _res=INITIAL_VALUE;
return res;
}
/// @brief Assign a new resource.
/// The old resource of @c this is freed if necessary.
AutoResource& reset(RESOURCE_TYPE res = INITIAL_VALUE)
throw(std::bad_exception) {
if (_res!=INITIAL_VALUE) (*FREE_FUNCTION)((FREE_TYPE)_res);
_res = res;
return *this;
}
private:
RESOURCE_TYPE _res; ///< the resource to be managed
};
/** @brief Automatically deletes a pointer when destructed.
@pre \#include
mrw::AutoPtr is a replacement for std::auto_ptr. The problem with
standard std::auto_ptr is, that it cannot be stored in a std::map.
@warning Use this class with prudence! Should I ever find out,
how to work around the std::auto_ptr / std::map problem,
then this class may become deprecated.
@param T type of the pointer to manage
*/
template
class AutoPtr {
public:
/// @brief Construct from an allocated resource.
/// The resource is freed if necessary.
/// AutoPtr takes over ownership of the resource.
explicit AutoPtr(T* res = 0)
throw(std::bad_exception): _res(res) {
res = 0;
}
/// @brief Takeover ownership from another AutoPtr.
AutoPtr(AutoPtr& o) throw(std::bad_exception):
_res(o.release()) {
}
//! @brief Do not use this method!
//! This method had to be introduced for the @c std::map, where
//! @c operator[] first creates an empty element, then assigns it
//! the real value. Because that empty element is temporary, gcc can
//! not use @c AutoResource(AutoResource&) since release 4.0.
AutoPtr(const AutoPtr& o) throw(std::bad_exception): _res(0) {
assert(o._res==0);
if (o._res!=0)
_res = const_cast(o).release();
}
/// @brief Free resource. Calls @c reset().
~AutoPtr() throw(std::bad_exception) {reset();}
/// @brief Assign new resource. Calls @c reset().
/// The resource is freed if necessary.
AutoPtr& operator=(T* res) throw(std::bad_exception) {
return reset(res);
}
/// @brief Takeover ownership from another AutoResource.
/// Calls @c reset() from @c this and @c release() from @c other.
AutoPtr& operator=(AutoPtr& other) throw(std::bad_exception) {
return reset(other.release());
}
/// @brief Get the resource.
operator T* const() const throw(std::bad_exception) {
return _res;
}
/// @brief find out, if a value is set
/// @return @c true: resource is valid
operator bool() const throw(std::bad_exception) {
return _res!=0;
}
/// @brief Access the AutoPtr like a normal pointer.
T*const operator->() {return _res;}
/// @brief Dereference the AutoPtr like a normal pointer.
T& operator*() {return *_res;}
/// @brief get the resetted resource for resetting it.
/// Calls @c reset and returns the cleaned resource.
/// The intention is, that you can safely assign it a new value
/// (e.g. in an expression).
T* getClean() throw(std::bad_exception) {
reset();
return _res;
}
/// @brief Give away ownership of the resource.
/// @return old resource
T* release() throw(std::bad_exception) {
T* res(_res); _res=0;
return res;
}
/// @brief Assign a new resource.
/// The old resource of @c this is freed if necessary.
AutoPtr& reset(T* res = 0)
throw(std::bad_exception) {
delete _res;
_res = res;
return *this;
}
private:
T* _res; ///< the resource to be managed
};
/** @brief Automatically deletes an array pointer when destructed.
@pre \#include
mrw::AutoPtrAry is a replacement for std::auto_ptr. Other than
mrw::AutoPtr it is for arrays, that means, it calls @c delete[]
instead of @c delete to free the memory. The problem with
standard std::auto_ptr is, that it cannot be stored in a
std::map and it does not call @c delete[].
@warning Use this class with prudence! Should I ever find out,
how to work around the std::auto_ptr / std::map problem,
then this class may become deprecated.
@param T type of the pointer to manage
*/
template
class AutoPtrAry {
public:
/// @brief Construct from an allocated resource.
/// The resource is freed if necessary.
/// AutoPtrAry takes over ownership of the resource.
explicit AutoPtrAry(T* res = 0)
throw(std::bad_exception): _res(res) {
res = 0;
}
/// @brief Takeover ownership from another AutoPtrAry.
AutoPtrAry(AutoPtrAry& o) throw(std::bad_exception):
_res(o.release()) {
}
//! @brief Do not use this method!
//! This method had to be introduced for the @c std::map, where
//! @c operator[] first creates an empty element, then assigns it
//! the real value. Because that empty element is temporary, gcc can
//! not use @c AutoResource(AutoResource&) since release 4.0.
AutoPtrAry(const AutoPtrAry& o) throw(std::bad_exception): _res(0) {
assert(o._res==0);
if (o._res!=0)
_res = const_cast(o).release();
}
/// @brief Free resource. Calls @c reset().
~AutoPtrAry() throw(std::bad_exception) {reset();}
/// @brief Assign new resource. Calls @c reset().
/// The resource is freed if necessary.
AutoPtrAry& operator=(T* res) throw(std::bad_exception) {
return reset(res);
}
/// @brief Takeover ownership from another AutoResource.
/// Calls @c reset() from @c this and @c release() from @c other.
AutoPtrAry& operator=(AutoPtrAry& other) throw(std::bad_exception) {
return reset(other.release());
}
/// @brief Get the resource.
operator T* const() const throw(std::bad_exception) {
return _res;
}
/// @brief find out, if a value is set
/// @return @c true: resource is valid
operator bool() const throw(std::bad_exception) {
return _res!=0;
}
/// @brief Access the AutoPtrAry like a normal pointer.
T*const operator->() {return _res;}
/// @brief Dereference the AutoPtrAry like a normal pointer.
T& operator*() {return *_res;}
/// @brief get the resetted resource for resetting it.
/// Calls @c reset and returns the cleaned resource.
/// The intention is, that you can safely assign it a new value
/// (e.g. in an expression).
T* getClean() throw(std::bad_exception) {
reset();
return _res;
}
/// @brief Give away ownership of the resource.
/// @return old resource
T* release() throw(std::bad_exception) {
T* res(_res); _res=0;
return res;
}
/// @brief Assign a new resource.
/// The old resource of @c this is freed if necessary.
AutoPtrAry& reset(T* res = 0)
throw(std::bad_exception) {
delete[] _res;
_res = res;
return *this;
}
private:
T* _res; ///< the resource to be managed
};
/** @brief Automatically closes a file when destructed.
@pre \#include
AutoFile works exactly like std::auto_ptr, but for files
instead of pointers. Whenever the context of AutoFile is left,
the opened file is close. This way, resources are freed even in
case of exceptions.
*/
typedef mrw::AutoResource AutoFile;
/** @brief Resource handle for @c mmap.
It integrates pointer and size of a memory mapped file similar
to a @c std::pair.
*/
class MMapHandle {
public:
void* first;
size_t second;
/// @brief Constructor that initializes the values through a call to mmap.
MMapHandle(int, size_t=0, void* = 0,
int = PROT_READ, int = MAP_SHARED, off_t = 0)
throw(std::bad_exception);
/// @brief Reset to zero, value of int is ignored.
MMapHandle& operator=(int) throw(std::bad_exception) {
first = 0; second = 0;
return *this;
}
/// @brief Compare to zero, returns true, if i and handle are both zero.
bool operator==(int i) const throw(std::bad_exception) {
return i==0 && first==0 && second==0;
}
};
inline void munmap(MMapHandle& res) throw(std::bad_exception) {
if (res.first!=0 && res.second>0)
::munmap((char*)res.first, res.second); // char* conversion for windoze cygwin compatibility
}
/** @brief Automatically calls @c munmap on destruction for mmaped files.
@pre \#include
It's the same as std::auto_ptr, but for @c mmap instead of @c
new. When the context of @c AutoMapper is left, @c munmap is
called.
*/
typedef mrw::AutoResource
AutoMapper;
/** @brief Automatically calls @c bfd_close for @c bfd*.
@pre \#include
It acts like a @c std::auto_ptr, but for @c bfd*, that means it
calls @c bfd_close whenever the context is left.
*/
typedef mrw::AutoResource AutoBfd;
/** @brief Automatically calls @c free for @c malloc allocated memory.
Instanciate it as @c mrw::Auto::Free.
@pre \#include
It works like a @c std::auto_ptr, but for memory that was
allocated with @c malloc, not @c new. Memory is freed, whenever
the context od @c AutoFree is left.
@code
{ // enter context
Auto::Free cp = (char*)malloc(5);
cp.getClean() = (char*)malloc(10); // old storage of 5 bytes is freed
} // memory is freed on destruction of cp
@endcode
*/
template class Auto {
public:
typedef mrw::AutoResource Free;
private:
/** @internal
work around compiler warning:
"only defines private constructors and has no friends" */
friend class ThisIsADummyToEliminateWarnings;
/// Forbidden to instanciate.
Auto(); Auto(const Auto&);
};
//@}
}
#endif