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.
342 lines
13 KiB
342 lines
13 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> |
|
|
|
// 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 / 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 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
|
|
|