| //===-- 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 functionality |
| // 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 <int, int> fd(open("/tmp/a.txt", O_RDONLY, 0), -1, close); |
| // |
| // // malloc/free example |
| // CleanUp <void *, void> malloced_bytes(malloc(32), NULL, free); |
| //---------------------------------------------------------------------- |
| template <typename T, typename R = void> |
| 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 <typename T, typename R, typename A0> |
| 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_ |