C++ Library containing a lot of needful things: Stack Trace, Command Line Parser, Resource Handling, Configuration Files, Unix Command Execution, Directories, Regular Expressions, Tokenizer, Function Trace, Standard Extensions.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

433 lines
16 KiB

/** @file
$Id$
$Date$
$Author$
@copy © Marc Wäckerlin
@license LGPL, see file <a href="license.html">COPYING</a>
*/
#ifndef __MRW_AUTO_HPP__
#define __MRW_AUTO_HPP__
#include <sys/types.h> // size_t
#include <sys/mman.h> // munmap, PROT_READ, MAP_SHARED
#include <unistd.h> // close
#include <stdexcept>
#include <cassert>
#include <cstdlib> // 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<ClassName> 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<char*>::Free xxx((char*)malloc(15));
@endcode
- mrw::SmartPointer<> is a shared pointer that deletes memory
when all owners have died
@code
mrw::SmartPointer<ClassName> 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<int, int(*)(int), &close, int, -1> mrw::AutoFile;
@endcode
*/
//@{
/** @brief Automatically frees a resource when destructed.
@pre \#include <mrw/auto.hpp>
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<int, int(*)(int), &close, int, -1> AutoFile;
typedef mrw::AutoResource<bfd*, int(*)(bfd*), &bfd_close, int> AutoBfd;
template<class T> class Auto {
public:
typedef mrw::AutoResource<T, void(*)(void*), &free, int, 0> 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<typename RESOURCE_TYPE,
typename FUNCTION_PTR,
FUNCTION_PTR FREE_FUNCTION,
typename INITIAL_VALUE_TYPE = RESOURCE_TYPE,
INITIAL_VALUE_TYPE INITIAL_VALUE = 0,
typename FREE_TYPE = RESOURCE_TYPE>
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<AutoResource&>(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/auto.hpp>
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&nbsp;/ std::map problem,
then this class may become deprecated.
@param T type of the pointer to manage
*/
template <typename T>
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<AutoPtr&>(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/auto.hpp>
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&nbsp;/ std::map problem,
then this class may become deprecated.
@param T type of the pointer to manage
*/
template <typename T>
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<AutoPtrAry&>(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 <mrw/auto.hpp>
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<int, int(*)(int), &close, int, -1> 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 <mrw/auto.hpp>
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<MMapHandle, void(*)(MMapHandle&), &mrw::munmap, int>
AutoMapper;
/** @brief Automatically calls @c bfd_close for @c bfd*.
@pre \#include <mrw/auto.hpp>
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<bfd*, int(*)(bfd*), &bfd_close, int> AutoBfd;
/** @brief Automatically calls @c free for @c malloc allocated memory.
Instanciate it as @c mrw::Auto<TYPE*>::Free.
@pre \#include <mrw/auto.hpp>
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<char*>::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 T> class Auto {
public:
typedef mrw::AutoResource<T, void(*)(void*), &free, int, 0, void*> 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