/** @file
$ Id $
$ Date $
$ Author $
@ copy & copy ; Marc W & auml ; 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>
// 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 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