1 //=== DelayedCleanupPool.h - Delayed Clean-up Pool Implementation *- 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 // This file defines a facility to delay calling cleanup methods until specific 11 // points. 12 // 13 //===----------------------------------------------------------------------===// 14 15 #ifndef LLVM_CLANG_BASIC_DELAYEDCLEANUPPOOL_H 16 #define LLVM_CLANG_BASIC_DELAYEDCLEANUPPOOL_H 17 18 #include "clang/Basic/LLVM.h" 19 #include "llvm/ADT/DenseMap.h" 20 #include "llvm/ADT/SmallVector.h" 21 22 namespace clang { 23 24 /// \brief Gathers pairs of pointer-to-object/pointer-to-cleanup-function 25 /// allowing the cleanup functions to get called (with the pointer as parameter) 26 /// at specific points. 27 /// 28 /// The use case is to simplify clean-up of certain resources that, while their 29 /// lifetime is well-known and restricted, cleaning them up manually is easy to 30 /// miss and cause a leak. 31 /// 32 /// The same pointer can be added multiple times; its clean-up function will 33 /// only be called once. 34 class DelayedCleanupPool { 35 public: 36 typedef void (*CleanupFn)(void *ptr); 37 38 /// \brief Adds a pointer and its associated cleanup function to be called 39 /// at a later point. 40 /// 41 /// \returns false if the pointer is already added, true otherwise. 42 bool delayCleanup(void *ptr, CleanupFn fn) { 43 assert(ptr && "Expected valid pointer to object"); 44 assert(fn && "Expected valid pointer to function"); 45 46 CleanupFn &mapFn = Ptrs[ptr]; 47 assert((!mapFn || mapFn == fn) && 48 "Adding a pointer with different cleanup function!"); 49 50 if (!mapFn) { 51 mapFn = fn; 52 Cleanups.push_back(std::make_pair(ptr, fn)); 53 return true; 54 } 55 56 return false; 57 } 58 59 template <typename T> 60 bool delayDelete(T *ptr) { 61 return delayCleanup(ptr, cleanupWithDelete<T>); 62 } 63 64 template <typename T, void (T::*Fn)()> 65 bool delayMemberFunc(T *ptr) { 66 return delayCleanup(ptr, cleanupWithMemberFunc<T, Fn>); 67 } 68 69 void doCleanup() { 70 for (SmallVector<std::pair<void *, CleanupFn>, 8>::reverse_iterator 71 I = Cleanups.rbegin(), E = Cleanups.rend(); I != E; ++I) 72 I->second(I->first); 73 Cleanups.clear(); 74 Ptrs.clear(); 75 } 76 77 ~DelayedCleanupPool() { 78 doCleanup(); 79 } 80 81 private: 82 llvm::DenseMap<void *, CleanupFn> Ptrs; 83 SmallVector<std::pair<void *, CleanupFn>, 8> Cleanups; 84 85 template <typename T> 86 static void cleanupWithDelete(void *ptr) { 87 delete static_cast<T *>(ptr); 88 } 89 90 template <typename T, void (T::*Fn)()> 91 static void cleanupWithMemberFunc(void *ptr) { 92 (static_cast<T *>(ptr)->*Fn)(); 93 } 94 }; 95 96 /// \brief RAII object for triggering a cleanup of a DelayedCleanupPool. 97 class DelayedCleanupPoint { 98 DelayedCleanupPool &Pool; 99 100 public: 101 DelayedCleanupPoint(DelayedCleanupPool &pool) : Pool(pool) { } 102 103 ~DelayedCleanupPoint() { 104 Pool.doCleanup(); 105 } 106 }; 107 108 } // end namespace clang 109 110 #endif 111