Home | History | Annotate | Download | only in Basic
      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