//===-- CleanUp.h -----------------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #ifndef liblldb_CleanUp_h_ #define liblldb_CleanUp_h_ #include "lldb/lldb-public.h" namespace lldb_utility { //---------------------------------------------------------------------- // Templated class that guarantees that a cleanup callback function will // be called. The cleanup function will be called once under the // following conditions: // - when the object goes out of scope // - when the user explicitly calls clean. // - the current value will be cleaned up when a new value is set using // set(T value) as long as the current value hasn't already been cleaned. // // This class is designed to be used with simple types for type T (like // file descriptors, opaque handles, pointers, etc). If more complex // type T objects are desired, we need to probably specialize this class // to take "const T&" for all input T parameters. Yet if a type T is // complex already it might be better to build the cleanup funcionality // into T. // // The cleanup function must take one argument that is of type T. // The calback function return type is R. The return value is currently // needed for "CallbackType". If there is an easy way to get around the // need for the return value we can change this class. // // The two template parameters are: // T - The variable type of value that will be stored and used as the // sole argument for the cleanup callback. // R - The return type for the cleanup function. // // EXAMPLES // // Use with file handles that get opened where you want to close // // them. Below we use "int open(const char *path, int oflag, ...)" // // which returns an integer file descriptor. -1 is the invalid file // // descriptor so to make an object that will call "int close(int fd)" // // automatically we can use: // // CleanUp fd(open("/tmp/a.txt", O_RDONLY, 0), -1, close); // // // malloc/free example // CleanUp malloced_bytes(malloc(32), NULL, free); //---------------------------------------------------------------------- template class CleanUp { public: typedef T value_type; typedef R (*CallbackType)(value_type); //---------------------------------------------------------------------- // Constructor that sets the current value only. No values are // considered to be invalid and the cleanup function will be called // regardless of the value of m_current_value. //---------------------------------------------------------------------- CleanUp (value_type value, CallbackType callback) : m_current_value (value), m_invalid_value (), m_callback (callback), m_callback_called (false), m_invalid_value_is_valid (false) { } //---------------------------------------------------------------------- // Constructor that sets the current value and also the invalid value. // The cleanup function will be called on "m_value" as long as it isn't // equal to "m_invalid_value". //---------------------------------------------------------------------- CleanUp (value_type value, value_type invalid, CallbackType callback) : m_current_value (value), m_invalid_value (invalid), m_callback (callback), m_callback_called (false), m_invalid_value_is_valid (true) { } //---------------------------------------------------------------------- // Automatically cleanup when this object goes out of scope. //---------------------------------------------------------------------- ~CleanUp () { clean(); } //---------------------------------------------------------------------- // Access the value stored in this class //---------------------------------------------------------------------- value_type get() { return m_current_value; } //---------------------------------------------------------------------- // Access the value stored in this class //---------------------------------------------------------------------- const value_type get() const { return m_current_value; } //---------------------------------------------------------------------- // Reset the owned value to "value". If a current value is valid and // the cleanup callback hasn't been called, the previous value will // be cleaned up (see void CleanUp::clean()). //---------------------------------------------------------------------- void set (const value_type value) { // Cleanup the current value if needed clean (); // Now set the new value and mark our callback as not called m_callback_called = false; m_current_value = value; } //---------------------------------------------------------------------- // Checks is "m_current_value" is valid. The value is considered valid // no invalid value was supplied during construction of this object or // if an invalid value was supplied and "m_current_value" is not equal // to "m_invalid_value". // // Returns true if "m_current_value" is valid, false otherwise. //---------------------------------------------------------------------- bool is_valid() const { if (m_invalid_value_is_valid) return m_current_value != m_invalid_value; return true; } //---------------------------------------------------------------------- // This function will call the cleanup callback provided in the // constructor one time if the value is considered valid (See is_valid()). // This function sets m_callback_called to true so we don't call the // cleanup callback multiple times on the same value. //---------------------------------------------------------------------- void clean() { if (m_callback && !m_callback_called) { m_callback_called = true; if (is_valid()) m_callback(m_current_value); } } //---------------------------------------------------------------------- // Cancels the cleanup that would have been called on "m_current_value" // if it was valid. This function can be used to release the value // contained in this object so ownership can be transfered to the caller. //---------------------------------------------------------------------- value_type release () { m_callback_called = true; return m_current_value; } private: value_type m_current_value; const value_type m_invalid_value; CallbackType m_callback; bool m_callback_called; bool m_invalid_value_is_valid; // Outlaw default constructor, copy constructor and the assignment operator DISALLOW_COPY_AND_ASSIGN (CleanUp); }; template class CleanUp2 { public: typedef T value_type; typedef R (*CallbackType)(value_type, A0); //---------------------------------------------------------------------- // Constructor that sets the current value only. No values are // considered to be invalid and the cleanup function will be called // regardless of the value of m_current_value. //---------------------------------------------------------------------- CleanUp2 (value_type value, CallbackType callback, A0 arg) : m_current_value (value), m_invalid_value (), m_callback (callback), m_callback_called (false), m_invalid_value_is_valid (false), m_argument(arg) { } //---------------------------------------------------------------------- // Constructor that sets the current value and also the invalid value. // The cleanup function will be called on "m_value" as long as it isn't // equal to "m_invalid_value". //---------------------------------------------------------------------- CleanUp2 (value_type value, value_type invalid, CallbackType callback, A0 arg) : m_current_value (value), m_invalid_value (invalid), m_callback (callback), m_callback_called (false), m_invalid_value_is_valid (true), m_argument(arg) { } //---------------------------------------------------------------------- // Automatically cleanup when this object goes out of scope. //---------------------------------------------------------------------- ~CleanUp2 () { clean(); } //---------------------------------------------------------------------- // Access the value stored in this class //---------------------------------------------------------------------- value_type get() { return m_current_value; } //---------------------------------------------------------------------- // Access the value stored in this class //---------------------------------------------------------------------- const value_type get() const { return m_current_value; } //---------------------------------------------------------------------- // Reset the owned value to "value". If a current value is valid and // the cleanup callback hasn't been called, the previous value will // be cleaned up (see void CleanUp::clean()). //---------------------------------------------------------------------- void set (const value_type value) { // Cleanup the current value if needed clean (); // Now set the new value and mark our callback as not called m_callback_called = false; m_current_value = value; } //---------------------------------------------------------------------- // Checks is "m_current_value" is valid. The value is considered valid // no invalid value was supplied during construction of this object or // if an invalid value was supplied and "m_current_value" is not equal // to "m_invalid_value". // // Returns true if "m_current_value" is valid, false otherwise. //---------------------------------------------------------------------- bool is_valid() const { if (m_invalid_value_is_valid) return m_current_value != m_invalid_value; return true; } //---------------------------------------------------------------------- // This function will call the cleanup callback provided in the // constructor one time if the value is considered valid (See is_valid()). // This function sets m_callback_called to true so we don't call the // cleanup callback multiple times on the same value. //---------------------------------------------------------------------- void clean() { if (m_callback && !m_callback_called) { m_callback_called = true; if (is_valid()) m_callback(m_current_value, m_argument); } } //---------------------------------------------------------------------- // Cancels the cleanup that would have been called on "m_current_value" // if it was valid. This function can be used to release the value // contained in this object so ownership can be transfered to the caller. //---------------------------------------------------------------------- value_type release () { m_callback_called = true; return m_current_value; } private: value_type m_current_value; const value_type m_invalid_value; CallbackType m_callback; bool m_callback_called; bool m_invalid_value_is_valid; A0 m_argument; // Outlaw default constructor, copy constructor and the assignment operator DISALLOW_COPY_AND_ASSIGN (CleanUp2); }; } // namespace lldb_utility #endif // #ifndef liblldb_CleanUp_h_