• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
15 namespace 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 //----------------------------------------------------------------------
55 template <typename T, typename R = void>
56 class CleanUp
57 {
58 public:
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     //----------------------------------------------------------------------
CleanUp(value_type value,CallbackType callback)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     //----------------------------------------------------------------------
CleanUp(value_type value,value_type invalid,CallbackType callback)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     //----------------------------------------------------------------------
~CleanUp()93     ~CleanUp ()
94     {
95         clean();
96     }
97 
98     //----------------------------------------------------------------------
99     // Access the value stored in this class
100     //----------------------------------------------------------------------
get()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
get()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
set(const value_type value)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
is_valid()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
clean()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
release()169     release ()
170     {
171         m_callback_called = true;
172         return m_current_value;
173     }
174 
175 private:
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 
186 template <typename T, typename R, typename A0>
187 class CleanUp2
188 {
189 public:
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     //----------------------------------------------------------------------
CleanUp2(value_type value,CallbackType callback,A0 arg)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     //----------------------------------------------------------------------
CleanUp2(value_type value,value_type invalid,CallbackType callback,A0 arg)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     //----------------------------------------------------------------------
~CleanUp2()226     ~CleanUp2 ()
227     {
228         clean();
229     }
230 
231     //----------------------------------------------------------------------
232     // Access the value stored in this class
233     //----------------------------------------------------------------------
get()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
get()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
set(const value_type value)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
is_valid()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
clean()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
release()302     release ()
303     {
304         m_callback_called = true;
305         return m_current_value;
306     }
307 
308 private:
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