1254721Semaste//===-- CleanUp.h -----------------------------------------------*- C++ -*-===//
2254721Semaste//
3254721Semaste//                     The LLVM Compiler Infrastructure
4254721Semaste//
5254721Semaste// This file is distributed under the University of Illinois Open Source
6254721Semaste// License. See LICENSE.TXT for details.
7254721Semaste//
8254721Semaste//===----------------------------------------------------------------------===//
9254721Semaste
10254721Semaste#ifndef liblldb_CleanUp_h_
11254721Semaste#define liblldb_CleanUp_h_
12254721Semaste
13254721Semaste#include "lldb/lldb-public.h"
14254721Semaste
15254721Semastenamespace lldb_utility {
16254721Semaste
17254721Semaste//----------------------------------------------------------------------
18254721Semaste// Templated class that guarantees that a cleanup callback function will
19254721Semaste// be called. The cleanup function will be called once under the
20254721Semaste// following conditions:
21254721Semaste// - when the object goes out of scope
22254721Semaste// - when the user explicitly calls clean.
23254721Semaste// - the current value will be cleaned up when a new value is set using
24254721Semaste//   set(T value) as long as the current value hasn't already been cleaned.
25254721Semaste//
26254721Semaste// This class is designed to be used with simple types for type T (like
27254721Semaste// file descriptors, opaque handles, pointers, etc). If more complex
28254721Semaste// type T objects are desired, we need to probably specialize this class
29254721Semaste// to take "const T&" for all input T parameters. Yet if a type T is
30254721Semaste// complex already it might be better to build the cleanup funcionality
31254721Semaste// into T.
32254721Semaste//
33254721Semaste// The cleanup function must take one argument that is of type T.
34254721Semaste// The calback function return type is R. The return value is currently
35254721Semaste// needed for "CallbackType". If there is an easy way to get around the
36254721Semaste// need for the return value we can change this class.
37254721Semaste//
38254721Semaste// The two template parameters are:
39254721Semaste//    T - The variable type of value that will be stored and used as the
40254721Semaste//      sole argument for the cleanup callback.
41254721Semaste//    R - The return type for the cleanup function.
42254721Semaste//
43254721Semaste// EXAMPLES
44254721Semaste//  // Use with file handles that get opened where you want to close
45254721Semaste//  // them. Below we use "int open(const char *path, int oflag, ...)"
46254721Semaste//  // which returns an integer file descriptor. -1 is the invalid file
47254721Semaste//  // descriptor so to make an object that will call "int close(int fd)"
48254721Semaste//  // automatically we can use:
49254721Semaste//
50254721Semaste//  CleanUp <int, int> fd(open("/tmp/a.txt", O_RDONLY, 0), -1, close);
51254721Semaste//
52254721Semaste//  // malloc/free example
53254721Semaste//  CleanUp <void *, void> malloced_bytes(malloc(32), NULL, free);
54254721Semaste//----------------------------------------------------------------------
55254721Semastetemplate <typename T, typename R = void>
56254721Semasteclass CleanUp
57254721Semaste{
58254721Semastepublic:
59254721Semaste    typedef T value_type;
60254721Semaste    typedef R (*CallbackType)(value_type);
61254721Semaste
62254721Semaste    //----------------------------------------------------------------------
63254721Semaste    // Constructor that sets the current value only. No values are
64254721Semaste    // considered to be invalid and the cleanup function will be called
65254721Semaste    // regardless of the value of m_current_value.
66254721Semaste    //----------------------------------------------------------------------
67254721Semaste    CleanUp (value_type value, CallbackType callback) :
68254721Semaste        m_current_value (value),
69254721Semaste        m_invalid_value (),
70254721Semaste        m_callback (callback),
71254721Semaste        m_callback_called (false),
72254721Semaste        m_invalid_value_is_valid (false)
73254721Semaste    {
74254721Semaste    }
75254721Semaste
76254721Semaste    //----------------------------------------------------------------------
77254721Semaste    // Constructor that sets the current value and also the invalid value.
78254721Semaste    // The cleanup function will be called on "m_value" as long as it isn't
79254721Semaste    // equal to "m_invalid_value".
80254721Semaste    //----------------------------------------------------------------------
81254721Semaste    CleanUp (value_type value, value_type invalid, CallbackType callback) :
82254721Semaste        m_current_value (value),
83254721Semaste        m_invalid_value (invalid),
84254721Semaste        m_callback (callback),
85254721Semaste        m_callback_called (false),
86254721Semaste        m_invalid_value_is_valid (true)
87254721Semaste    {
88254721Semaste    }
89254721Semaste
90254721Semaste    //----------------------------------------------------------------------
91254721Semaste    // Automatically cleanup when this object goes out of scope.
92254721Semaste    //----------------------------------------------------------------------
93254721Semaste    ~CleanUp ()
94254721Semaste    {
95254721Semaste        clean();
96254721Semaste    }
97254721Semaste
98254721Semaste    //----------------------------------------------------------------------
99254721Semaste    // Access the value stored in this class
100254721Semaste    //----------------------------------------------------------------------
101254721Semaste    value_type get()
102254721Semaste    {
103254721Semaste        return m_current_value;
104254721Semaste    }
105254721Semaste
106254721Semaste    //----------------------------------------------------------------------
107254721Semaste    // Access the value stored in this class
108254721Semaste    //----------------------------------------------------------------------
109254721Semaste    const value_type
110254721Semaste    get() const
111254721Semaste    {
112254721Semaste        return m_current_value;
113254721Semaste    }
114254721Semaste
115254721Semaste    //----------------------------------------------------------------------
116254721Semaste    // Reset the owned value to "value". If a current value is valid and
117254721Semaste    // the cleanup callback hasn't been called, the previous value will
118254721Semaste    // be cleaned up (see void CleanUp::clean()).
119254721Semaste    //----------------------------------------------------------------------
120254721Semaste    void
121254721Semaste    set (const value_type value)
122254721Semaste    {
123254721Semaste        // Cleanup the current value if needed
124254721Semaste        clean ();
125254721Semaste        // Now set the new value and mark our callback as not called
126254721Semaste        m_callback_called = false;
127254721Semaste        m_current_value = value;
128254721Semaste    }
129254721Semaste
130254721Semaste    //----------------------------------------------------------------------
131254721Semaste    // Checks is "m_current_value" is valid. The value is considered valid
132254721Semaste    // no invalid value was supplied during construction of this object or
133254721Semaste    // if an invalid value was supplied and "m_current_value" is not equal
134254721Semaste    // to "m_invalid_value".
135254721Semaste    //
136254721Semaste    // Returns true if "m_current_value" is valid, false otherwise.
137254721Semaste    //----------------------------------------------------------------------
138254721Semaste    bool
139254721Semaste    is_valid() const
140254721Semaste    {
141254721Semaste        if (m_invalid_value_is_valid)
142254721Semaste            return m_current_value != m_invalid_value;
143254721Semaste        return true;
144254721Semaste    }
145254721Semaste
146254721Semaste    //----------------------------------------------------------------------
147254721Semaste    // This function will call the cleanup callback provided in the
148254721Semaste    // constructor one time if the value is considered valid (See is_valid()).
149254721Semaste    // This function sets m_callback_called to true so we don't call the
150254721Semaste    // cleanup callback multiple times on the same value.
151254721Semaste    //----------------------------------------------------------------------
152254721Semaste    void
153254721Semaste    clean()
154254721Semaste    {
155254721Semaste        if (m_callback && !m_callback_called)
156254721Semaste        {
157254721Semaste            m_callback_called = true;
158254721Semaste            if (is_valid())
159254721Semaste                m_callback(m_current_value);
160254721Semaste        }
161254721Semaste    }
162254721Semaste
163254721Semaste    //----------------------------------------------------------------------
164254721Semaste    // Cancels the cleanup that would have been called on "m_current_value"
165254721Semaste    // if it was valid. This function can be used to release the value
166254721Semaste    // contained in this object so ownership can be transfered to the caller.
167254721Semaste    //----------------------------------------------------------------------
168254721Semaste    value_type
169254721Semaste    release ()
170254721Semaste    {
171254721Semaste        m_callback_called = true;
172254721Semaste        return m_current_value;
173254721Semaste    }
174254721Semaste
175254721Semasteprivate:
176254721Semaste            value_type      m_current_value;
177254721Semaste    const   value_type      m_invalid_value;
178254721Semaste            CallbackType    m_callback;
179254721Semaste            bool            m_callback_called;
180254721Semaste            bool            m_invalid_value_is_valid;
181254721Semaste
182254721Semaste    // Outlaw default constructor, copy constructor and the assignment operator
183254721Semaste    DISALLOW_COPY_AND_ASSIGN (CleanUp);
184254721Semaste};
185254721Semaste
186254721Semastetemplate <typename T, typename R, typename A0>
187254721Semasteclass CleanUp2
188254721Semaste{
189254721Semastepublic:
190254721Semaste    typedef T value_type;
191254721Semaste    typedef R (*CallbackType)(value_type, A0);
192254721Semaste
193254721Semaste    //----------------------------------------------------------------------
194254721Semaste    // Constructor that sets the current value only. No values are
195254721Semaste    // considered to be invalid and the cleanup function will be called
196254721Semaste    // regardless of the value of m_current_value.
197254721Semaste    //----------------------------------------------------------------------
198254721Semaste    CleanUp2 (value_type value, CallbackType callback, A0 arg) :
199254721Semaste    m_current_value (value),
200254721Semaste    m_invalid_value (),
201254721Semaste    m_callback (callback),
202254721Semaste    m_callback_called (false),
203254721Semaste    m_invalid_value_is_valid (false),
204254721Semaste    m_argument(arg)
205254721Semaste    {
206254721Semaste    }
207254721Semaste
208254721Semaste    //----------------------------------------------------------------------
209254721Semaste    // Constructor that sets the current value and also the invalid value.
210254721Semaste    // The cleanup function will be called on "m_value" as long as it isn't
211254721Semaste    // equal to "m_invalid_value".
212254721Semaste    //----------------------------------------------------------------------
213254721Semaste    CleanUp2 (value_type value, value_type invalid, CallbackType callback, A0 arg) :
214254721Semaste    m_current_value (value),
215254721Semaste    m_invalid_value (invalid),
216254721Semaste    m_callback (callback),
217254721Semaste    m_callback_called (false),
218254721Semaste    m_invalid_value_is_valid (true),
219254721Semaste    m_argument(arg)
220254721Semaste    {
221254721Semaste    }
222254721Semaste
223254721Semaste    //----------------------------------------------------------------------
224254721Semaste    // Automatically cleanup when this object goes out of scope.
225254721Semaste    //----------------------------------------------------------------------
226254721Semaste    ~CleanUp2 ()
227254721Semaste    {
228254721Semaste        clean();
229254721Semaste    }
230254721Semaste
231254721Semaste    //----------------------------------------------------------------------
232254721Semaste    // Access the value stored in this class
233254721Semaste    //----------------------------------------------------------------------
234254721Semaste    value_type get()
235254721Semaste    {
236254721Semaste        return m_current_value;
237254721Semaste    }
238254721Semaste
239254721Semaste    //----------------------------------------------------------------------
240254721Semaste    // Access the value stored in this class
241254721Semaste    //----------------------------------------------------------------------
242254721Semaste    const value_type
243254721Semaste    get() const
244254721Semaste    {
245254721Semaste        return m_current_value;
246254721Semaste    }
247254721Semaste
248254721Semaste    //----------------------------------------------------------------------
249254721Semaste    // Reset the owned value to "value". If a current value is valid and
250254721Semaste    // the cleanup callback hasn't been called, the previous value will
251254721Semaste    // be cleaned up (see void CleanUp::clean()).
252254721Semaste    //----------------------------------------------------------------------
253254721Semaste    void
254254721Semaste    set (const value_type value)
255254721Semaste    {
256254721Semaste        // Cleanup the current value if needed
257254721Semaste        clean ();
258254721Semaste        // Now set the new value and mark our callback as not called
259254721Semaste        m_callback_called = false;
260254721Semaste        m_current_value = value;
261254721Semaste    }
262254721Semaste
263254721Semaste    //----------------------------------------------------------------------
264254721Semaste    // Checks is "m_current_value" is valid. The value is considered valid
265254721Semaste    // no invalid value was supplied during construction of this object or
266254721Semaste    // if an invalid value was supplied and "m_current_value" is not equal
267254721Semaste    // to "m_invalid_value".
268254721Semaste    //
269254721Semaste    // Returns true if "m_current_value" is valid, false otherwise.
270254721Semaste    //----------------------------------------------------------------------
271254721Semaste    bool
272254721Semaste    is_valid() const
273254721Semaste    {
274254721Semaste        if (m_invalid_value_is_valid)
275254721Semaste            return m_current_value != m_invalid_value;
276254721Semaste        return true;
277254721Semaste    }
278254721Semaste
279254721Semaste    //----------------------------------------------------------------------
280254721Semaste    // This function will call the cleanup callback provided in the
281254721Semaste    // constructor one time if the value is considered valid (See is_valid()).
282254721Semaste    // This function sets m_callback_called to true so we don't call the
283254721Semaste    // cleanup callback multiple times on the same value.
284254721Semaste    //----------------------------------------------------------------------
285254721Semaste    void
286254721Semaste    clean()
287254721Semaste    {
288254721Semaste        if (m_callback && !m_callback_called)
289254721Semaste        {
290254721Semaste            m_callback_called = true;
291254721Semaste            if (is_valid())
292254721Semaste                m_callback(m_current_value, m_argument);
293254721Semaste        }
294254721Semaste    }
295254721Semaste
296254721Semaste    //----------------------------------------------------------------------
297254721Semaste    // Cancels the cleanup that would have been called on "m_current_value"
298254721Semaste    // if it was valid. This function can be used to release the value
299254721Semaste    // contained in this object so ownership can be transfered to the caller.
300254721Semaste    //----------------------------------------------------------------------
301254721Semaste    value_type
302254721Semaste    release ()
303254721Semaste    {
304254721Semaste        m_callback_called = true;
305254721Semaste        return m_current_value;
306254721Semaste    }
307254721Semaste
308254721Semasteprivate:
309254721Semaste    value_type      m_current_value;
310254721Semaste    const   value_type      m_invalid_value;
311254721Semaste    CallbackType    m_callback;
312254721Semaste    bool            m_callback_called;
313254721Semaste    bool            m_invalid_value_is_valid;
314254721Semaste    A0              m_argument;
315254721Semaste
316254721Semaste    // Outlaw default constructor, copy constructor and the assignment operator
317254721Semaste    DISALLOW_COPY_AND_ASSIGN (CleanUp2);
318254721Semaste};
319254721Semaste
320254721Semaste} // namespace lldb_utility
321254721Semaste
322254721Semaste#endif // #ifndef liblldb_CleanUp_h_
323