1//===-- CleanUp.h -----------------------------------------------*- C++ -*-===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#ifndef liblldb_CleanUp_h_
11#define liblldb_CleanUp_h_
12
13#include "lldb/lldb-public.h"
14
15namespace lldb_utility {
16
17//----------------------------------------------------------------------
18// Templated class that guarantees that a cleanup callback function will
19// be called. The cleanup function will be called once under the
20// following conditions:
21// - when the object goes out of scope
22// - when the user explicitly calls clean.
23// - the current value will be cleaned up when a new value is set using
24//   set(T value) as long as the current value hasn't already been cleaned.
25//
26// This class is designed to be used with simple types for type T (like
27// file descriptors, opaque handles, pointers, etc). If more complex
28// type T objects are desired, we need to probably specialize this class
29// to take "const T&" for all input T parameters. Yet if a type T is
30// complex already it might be better to build the cleanup funcionality
31// into T.
32//
33// The cleanup function must take one argument that is of type T.
34// The calback function return type is R. The return value is currently
35// needed for "CallbackType". If there is an easy way to get around the
36// need for the return value we can change this class.
37//
38// The two template parameters are:
39//    T - The variable type of value that will be stored and used as the
40//      sole argument for the cleanup callback.
41//    R - The return type for the cleanup function.
42//
43// EXAMPLES
44//  // Use with file handles that get opened where you want to close
45//  // them. Below we use "int open(const char *path, int oflag, ...)"
46//  // which returns an integer file descriptor. -1 is the invalid file
47//  // descriptor so to make an object that will call "int close(int fd)"
48//  // automatically we can use:
49//
50//  CleanUp <int, int> fd(open("/tmp/a.txt", O_RDONLY, 0), -1, close);
51//
52//  // malloc/free example
53//  CleanUp <void *, void> malloced_bytes(malloc(32), NULL, free);
54//----------------------------------------------------------------------
55template <typename T, typename R = void>
56class CleanUp
57{
58public:
59    typedef T value_type;
60    typedef R (*CallbackType)(value_type);
61
62    //----------------------------------------------------------------------
63    // Constructor that sets the current value only. No values are
64    // considered to be invalid and the cleanup function will be called
65    // regardless of the value of m_current_value.
66    //----------------------------------------------------------------------
67    CleanUp (value_type value, CallbackType callback) :
68        m_current_value (value),
69        m_invalid_value (),
70        m_callback (callback),
71        m_callback_called (false),
72        m_invalid_value_is_valid (false)
73    {
74    }
75
76    //----------------------------------------------------------------------
77    // Constructor that sets the current value and also the invalid value.
78    // The cleanup function will be called on "m_value" as long as it isn't
79    // equal to "m_invalid_value".
80    //----------------------------------------------------------------------
81    CleanUp (value_type value, value_type invalid, CallbackType callback) :
82        m_current_value (value),
83        m_invalid_value (invalid),
84        m_callback (callback),
85        m_callback_called (false),
86        m_invalid_value_is_valid (true)
87    {
88    }
89
90    //----------------------------------------------------------------------
91    // Automatically cleanup when this object goes out of scope.
92    //----------------------------------------------------------------------
93    ~CleanUp ()
94    {
95        clean();
96    }
97
98    //----------------------------------------------------------------------
99    // Access the value stored in this class
100    //----------------------------------------------------------------------
101    value_type get()
102    {
103        return m_current_value;
104    }
105
106    //----------------------------------------------------------------------
107    // Access the value stored in this class
108    //----------------------------------------------------------------------
109    const value_type
110    get() const
111    {
112        return m_current_value;
113    }
114
115    //----------------------------------------------------------------------
116    // Reset the owned value to "value". If a current value is valid and
117    // the cleanup callback hasn't been called, the previous value will
118    // be cleaned up (see void CleanUp::clean()).
119    //----------------------------------------------------------------------
120    void
121    set (const value_type value)
122    {
123        // Cleanup the current value if needed
124        clean ();
125        // Now set the new value and mark our callback as not called
126        m_callback_called = false;
127        m_current_value = value;
128    }
129
130    //----------------------------------------------------------------------
131    // Checks is "m_current_value" is valid. The value is considered valid
132    // no invalid value was supplied during construction of this object or
133    // if an invalid value was supplied and "m_current_value" is not equal
134    // to "m_invalid_value".
135    //
136    // Returns true if "m_current_value" is valid, false otherwise.
137    //----------------------------------------------------------------------
138    bool
139    is_valid() const
140    {
141        if (m_invalid_value_is_valid)
142            return m_current_value != m_invalid_value;
143        return true;
144    }
145
146    //----------------------------------------------------------------------
147    // This function will call the cleanup callback provided in the
148    // constructor one time if the value is considered valid (See is_valid()).
149    // This function sets m_callback_called to true so we don't call the
150    // cleanup callback multiple times on the same value.
151    //----------------------------------------------------------------------
152    void
153    clean()
154    {
155        if (m_callback && !m_callback_called)
156        {
157            m_callback_called = true;
158            if (is_valid())
159                m_callback(m_current_value);
160        }
161    }
162
163    //----------------------------------------------------------------------
164    // Cancels the cleanup that would have been called on "m_current_value"
165    // if it was valid. This function can be used to release the value
166    // contained in this object so ownership can be transfered to the caller.
167    //----------------------------------------------------------------------
168    value_type
169    release ()
170    {
171        m_callback_called = true;
172        return m_current_value;
173    }
174
175private:
176            value_type      m_current_value;
177    const   value_type      m_invalid_value;
178            CallbackType    m_callback;
179            bool            m_callback_called;
180            bool            m_invalid_value_is_valid;
181
182    // Outlaw default constructor, copy constructor and the assignment operator
183    DISALLOW_COPY_AND_ASSIGN (CleanUp);
184};
185
186template <typename T, typename R, typename A0>
187class CleanUp2
188{
189public:
190    typedef T value_type;
191    typedef R (*CallbackType)(value_type, A0);
192
193    //----------------------------------------------------------------------
194    // Constructor that sets the current value only. No values are
195    // considered to be invalid and the cleanup function will be called
196    // regardless of the value of m_current_value.
197    //----------------------------------------------------------------------
198    CleanUp2 (value_type value, CallbackType callback, A0 arg) :
199    m_current_value (value),
200    m_invalid_value (),
201    m_callback (callback),
202    m_callback_called (false),
203    m_invalid_value_is_valid (false),
204    m_argument(arg)
205    {
206    }
207
208    //----------------------------------------------------------------------
209    // Constructor that sets the current value and also the invalid value.
210    // The cleanup function will be called on "m_value" as long as it isn't
211    // equal to "m_invalid_value".
212    //----------------------------------------------------------------------
213    CleanUp2 (value_type value, value_type invalid, CallbackType callback, A0 arg) :
214    m_current_value (value),
215    m_invalid_value (invalid),
216    m_callback (callback),
217    m_callback_called (false),
218    m_invalid_value_is_valid (true),
219    m_argument(arg)
220    {
221    }
222
223    //----------------------------------------------------------------------
224    // Automatically cleanup when this object goes out of scope.
225    //----------------------------------------------------------------------
226    ~CleanUp2 ()
227    {
228        clean();
229    }
230
231    //----------------------------------------------------------------------
232    // Access the value stored in this class
233    //----------------------------------------------------------------------
234    value_type get()
235    {
236        return m_current_value;
237    }
238
239    //----------------------------------------------------------------------
240    // Access the value stored in this class
241    //----------------------------------------------------------------------
242    const value_type
243    get() const
244    {
245        return m_current_value;
246    }
247
248    //----------------------------------------------------------------------
249    // Reset the owned value to "value". If a current value is valid and
250    // the cleanup callback hasn't been called, the previous value will
251    // be cleaned up (see void CleanUp::clean()).
252    //----------------------------------------------------------------------
253    void
254    set (const value_type value)
255    {
256        // Cleanup the current value if needed
257        clean ();
258        // Now set the new value and mark our callback as not called
259        m_callback_called = false;
260        m_current_value = value;
261    }
262
263    //----------------------------------------------------------------------
264    // Checks is "m_current_value" is valid. The value is considered valid
265    // no invalid value was supplied during construction of this object or
266    // if an invalid value was supplied and "m_current_value" is not equal
267    // to "m_invalid_value".
268    //
269    // Returns true if "m_current_value" is valid, false otherwise.
270    //----------------------------------------------------------------------
271    bool
272    is_valid() const
273    {
274        if (m_invalid_value_is_valid)
275            return m_current_value != m_invalid_value;
276        return true;
277    }
278
279    //----------------------------------------------------------------------
280    // This function will call the cleanup callback provided in the
281    // constructor one time if the value is considered valid (See is_valid()).
282    // This function sets m_callback_called to true so we don't call the
283    // cleanup callback multiple times on the same value.
284    //----------------------------------------------------------------------
285    void
286    clean()
287    {
288        if (m_callback && !m_callback_called)
289        {
290            m_callback_called = true;
291            if (is_valid())
292                m_callback(m_current_value, m_argument);
293        }
294    }
295
296    //----------------------------------------------------------------------
297    // Cancels the cleanup that would have been called on "m_current_value"
298    // if it was valid. This function can be used to release the value
299    // contained in this object so ownership can be transfered to the caller.
300    //----------------------------------------------------------------------
301    value_type
302    release ()
303    {
304        m_callback_called = true;
305        return m_current_value;
306    }
307
308private:
309    value_type      m_current_value;
310    const   value_type      m_invalid_value;
311    CallbackType    m_callback;
312    bool            m_callback_called;
313    bool            m_invalid_value_is_valid;
314    A0              m_argument;
315
316    // Outlaw default constructor, copy constructor and the assignment operator
317    DISALLOW_COPY_AND_ASSIGN (CleanUp2);
318};
319
320} // namespace lldb_utility
321
322#endif // #ifndef liblldb_CleanUp_h_
323