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