10b57cec5SDimitry Andric //===------------------SharedCluster.h --------------------------*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
95ffd83dbSDimitry Andric #ifndef LLDB_UTILITY_SHAREDCLUSTER_H
105ffd83dbSDimitry Andric #define LLDB_UTILITY_SHAREDCLUSTER_H
110b57cec5SDimitry Andric 
120b57cec5SDimitry Andric #include "lldb/Utility/LLDBAssert.h"
135ffd83dbSDimitry Andric #include "llvm/ADT/STLExtras.h"
14bdd1243dSDimitry Andric #include "llvm/ADT/SmallPtrSet.h"
150b57cec5SDimitry Andric 
165ffd83dbSDimitry Andric #include <memory>
170b57cec5SDimitry Andric #include <mutex>
180b57cec5SDimitry Andric 
190b57cec5SDimitry Andric namespace lldb_private {
200b57cec5SDimitry Andric 
215ffd83dbSDimitry Andric template <class T>
225ffd83dbSDimitry Andric class ClusterManager : public std::enable_shared_from_this<ClusterManager<T>> {
230b57cec5SDimitry Andric public:
Create()245ffd83dbSDimitry Andric   static std::shared_ptr<ClusterManager> Create() {
255ffd83dbSDimitry Andric     return std::shared_ptr<ClusterManager>(new ClusterManager());
260b57cec5SDimitry Andric   }
270b57cec5SDimitry Andric 
~ClusterManager()285ffd83dbSDimitry Andric   ~ClusterManager() {
295ffd83dbSDimitry Andric     for (T *obj : m_objects)
305ffd83dbSDimitry Andric       delete obj;
310b57cec5SDimitry Andric   }
320b57cec5SDimitry Andric 
ManageObject(T * new_object)330b57cec5SDimitry Andric   void ManageObject(T *new_object) {
340b57cec5SDimitry Andric     std::lock_guard<std::mutex> guard(m_mutex);
35bdd1243dSDimitry Andric     auto ret = m_objects.insert(new_object);
36bdd1243dSDimitry Andric     assert(ret.second && "ManageObject called twice for the same object?");
37bdd1243dSDimitry Andric     (void)ret;
380b57cec5SDimitry Andric   }
390b57cec5SDimitry Andric 
GetSharedPointer(T * desired_object)405ffd83dbSDimitry Andric   std::shared_ptr<T> GetSharedPointer(T *desired_object) {
410b57cec5SDimitry Andric     std::lock_guard<std::mutex> guard(m_mutex);
425ffd83dbSDimitry Andric     auto this_sp = this->shared_from_this();
43bdd1243dSDimitry Andric     size_t count =  m_objects.count(desired_object);
44bdd1243dSDimitry Andric     if (count == 0) {
450b57cec5SDimitry Andric       lldbassert(false && "object not found in shared cluster when expected");
460b57cec5SDimitry Andric       desired_object = nullptr;
470b57cec5SDimitry Andric     }
485ffd83dbSDimitry Andric     return {std::move(this_sp), desired_object};
490b57cec5SDimitry Andric   }
500b57cec5SDimitry Andric 
510b57cec5SDimitry Andric private:
ClusterManager()5204eeddc0SDimitry Andric   ClusterManager() : m_objects() {}
53bdd1243dSDimitry Andric   // The cluster manager is used primarily to manage the
54bdd1243dSDimitry Andric   // children of root ValueObjects. So it will always have
55bdd1243dSDimitry Andric   // one element - the root.  Pointers will often have dynamic
56bdd1243dSDimitry Andric   // values, so having 2 entries is pretty common.  It's also
57bdd1243dSDimitry Andric   // pretty common to have small (2,3) structs, so setting the
58bdd1243dSDimitry Andric   // static size to 4 will cover those cases with no allocations
59bdd1243dSDimitry Andric   // w/o wasting too much space.
60bdd1243dSDimitry Andric   llvm::SmallPtrSet<T *, 4> m_objects;
610b57cec5SDimitry Andric   std::mutex m_mutex;
620b57cec5SDimitry Andric };
630b57cec5SDimitry Andric 
640b57cec5SDimitry Andric } // namespace lldb_private
650b57cec5SDimitry Andric 
665ffd83dbSDimitry Andric #endif // LLDB_UTILITY_SHAREDCLUSTER_H
67