| //=== DelayedCleanupPool.h - Delayed Clean-up Pool Implementation *- C++ -*===// |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This file defines a facility to delay calling cleanup methods until specific |
| // points. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef LLVM_CLANG_BASIC_DELAYEDCLEANUPPOOL_H |
| #define LLVM_CLANG_BASIC_DELAYEDCLEANUPPOOL_H |
| |
| #include "clang/Basic/LLVM.h" |
| #include "llvm/ADT/DenseMap.h" |
| #include "llvm/ADT/SmallVector.h" |
| |
| namespace clang { |
| |
| /// \brief Gathers pairs of pointer-to-object/pointer-to-cleanup-function |
| /// allowing the cleanup functions to get called (with the pointer as parameter) |
| /// at specific points. |
| /// |
| /// The use case is to simplify clean-up of certain resources that, while their |
| /// lifetime is well-known and restricted, cleaning them up manually is easy to |
| /// miss and cause a leak. |
| /// |
| /// The same pointer can be added multiple times; its clean-up function will |
| /// only be called once. |
| class DelayedCleanupPool { |
| public: |
| typedef void (*CleanupFn)(void *ptr); |
| |
| /// \brief Adds a pointer and its associated cleanup function to be called |
| /// at a later point. |
| /// |
| /// \returns false if the pointer is already added, true otherwise. |
| bool delayCleanup(void *ptr, CleanupFn fn) { |
| assert(ptr && "Expected valid pointer to object"); |
| assert(fn && "Expected valid pointer to function"); |
| |
| CleanupFn &mapFn = Ptrs[ptr]; |
| assert((!mapFn || mapFn == fn) && |
| "Adding a pointer with different cleanup function!"); |
| |
| if (!mapFn) { |
| mapFn = fn; |
| Cleanups.push_back(std::make_pair(ptr, fn)); |
| return true; |
| } |
| |
| return false; |
| } |
| |
| template <typename T> |
| bool delayDelete(T *ptr) { |
| return delayCleanup(ptr, cleanupWithDelete<T>); |
| } |
| |
| template <typename T, void (T::*Fn)()> |
| bool delayMemberFunc(T *ptr) { |
| return delayCleanup(ptr, cleanupWithMemberFunc<T, Fn>); |
| } |
| |
| void doCleanup() { |
| for (SmallVector<std::pair<void *, CleanupFn>, 8>::reverse_iterator |
| I = Cleanups.rbegin(), E = Cleanups.rend(); I != E; ++I) |
| I->second(I->first); |
| Cleanups.clear(); |
| Ptrs.clear(); |
| } |
| |
| ~DelayedCleanupPool() { |
| doCleanup(); |
| } |
| |
| private: |
| llvm::DenseMap<void *, CleanupFn> Ptrs; |
| SmallVector<std::pair<void *, CleanupFn>, 8> Cleanups; |
| |
| template <typename T> |
| static void cleanupWithDelete(void *ptr) { |
| delete static_cast<T *>(ptr); |
| } |
| |
| template <typename T, void (T::*Fn)()> |
| static void cleanupWithMemberFunc(void *ptr) { |
| (static_cast<T *>(ptr)->*Fn)(); |
| } |
| }; |
| |
| /// \brief RAII object for triggering a cleanup of a DelayedCleanupPool. |
| class DelayedCleanupPoint { |
| DelayedCleanupPool &Pool; |
| |
| public: |
| DelayedCleanupPoint(DelayedCleanupPool &pool) : Pool(pool) { } |
| |
| ~DelayedCleanupPoint() { |
| Pool.doCleanup(); |
| } |
| }; |
| |
| } // end namespace clang |
| |
| #endif |