/** @file $Id$ $Date$ $Author$ @copy © Marc Wäckerlin @license LGPL, see file COPYING $Log$ Revision 1.7 2004/12/20 07:40:35 marc documentation improved, new grouping Revision 1.6 2004/10/11 16:48:29 marc better comment and operators -> and * for AutoPtr Revision 1.5 2004/10/11 16:05:02 marc new AutoPtr Revision 1.4 2004/10/07 09:24:08 marc enhance windoze compatibility Revision 1.3 2004/08/28 16:21:25 marc mrw-c++-0.92 (mrw) - new file: version.cpp - new file header for all sources - work around warning in mrw::auto - possibility to compile without log4cxx - work around bugs in demangle.h and libiberty.h - corrections in documentation - added simple tracing mechanism - more warnings - small corrections in Auto<>::Free and a new test for it - possibility to compile without stack trace */ #ifndef __MRW_AUTO_HPP__ #define __MRW_AUTO_HPP__ #include // size_t #include // munmap, PROT_READ, MAP_SHARED #include // close #include // 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 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 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 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