131 lines
3.8 KiB
C++
131 lines
3.8 KiB
C++
|
|
#include "iwa/object.hpp"
|
|
|
|
#if IWA_OBJECTPTR_TRACKING
|
|
#include <iostream>
|
|
#endif
|
|
#include <mutex>
|
|
#include <shared_mutex>
|
|
#include <unordered_map>
|
|
|
|
namespace iwa::impl
|
|
{
|
|
namespace
|
|
{
|
|
std::atomic<object_id_t> gNextObjectId;
|
|
std::unordered_map<object_id_t, BaseObject*> gAllObjects;
|
|
std::shared_mutex gAllObjectMutex;
|
|
std::unordered_map<object_id_t, object_destruction_handler_t> gDestructionHandlers;
|
|
std::shared_mutex gDestructionHandlersMutex;
|
|
|
|
#if IWA_OBJECTPTR_TRACKING
|
|
std::list<ObjectPtrAllocation> gObjectPtrAllocations;
|
|
std::mutex gObjectPtrAllocationsMutex;
|
|
|
|
struct ObjectPtrAllocationsChecker
|
|
{
|
|
~ObjectPtrAllocationsChecker()
|
|
{
|
|
const std::unique_lock lock(gObjectPtrAllocationsMutex);
|
|
if (!gObjectPtrAllocations.empty())
|
|
{
|
|
std::cerr << "ObjectPtrs pending deletion:\n";
|
|
for (const ObjectPtrAllocation& allocation : gObjectPtrAllocations)
|
|
{
|
|
std::cerr << typeid(*allocation.object).name() /* << "@" << allocation.stacktrace */ <<"\n";
|
|
#if IWA_OBJECTPTR_TRACKING > 1
|
|
if (allocation.stacktrace.isSuccess())
|
|
{
|
|
std::cerr << *allocation.stacktrace << "\n";
|
|
}
|
|
#endif
|
|
}
|
|
std::cerr.flush();
|
|
MIJIN_TRAP();
|
|
}
|
|
}
|
|
} gObjectPtrAllocationsChecker;
|
|
#endif // IWA_OBJECTPTR_TRACKING
|
|
}
|
|
|
|
#if IWA_OBJECTPTR_TRACKING
|
|
#if IWA_OBJECTPTR_TRACKING > 1
|
|
objectptr_allocation_handle_t trackObjectPtr(BaseObject* object, mijin::Result<mijin::Stacktrace>&& stacktrace) noexcept
|
|
{
|
|
const std::unique_lock lock(gObjectPtrAllocationsMutex);
|
|
gObjectPtrAllocations.emplace_back(object, std::move(stacktrace));
|
|
return std::prev(gObjectPtrAllocations.end());
|
|
}
|
|
#else
|
|
objectptr_allocation_handle_t trackObjectPtr(BaseObject* object) noexcept
|
|
{
|
|
const std::unique_lock lock(gObjectPtrAllocationsMutex);
|
|
gObjectPtrAllocations.emplace_back(object);
|
|
return std::prev(gObjectPtrAllocations.end());
|
|
}
|
|
#endif
|
|
|
|
void untrackObjectPtr(objectptr_allocation_handle_t handle) noexcept
|
|
{
|
|
const std::unique_lock lock(gObjectPtrAllocationsMutex);
|
|
gObjectPtrAllocations.erase(*handle); // NOLINT(bugprone-unchecked-optional-access)
|
|
}
|
|
#endif // IWA_OBJECTPTR_TRACKING
|
|
|
|
object_id_t nextObjectId() noexcept
|
|
{
|
|
return ++gNextObjectId;
|
|
}
|
|
|
|
void registerObject(BaseObject* object) noexcept
|
|
{
|
|
const std::unique_lock lock(gAllObjectMutex);
|
|
MIJIN_ASSERT(gAllObjects.find(object->getId()) == gAllObjects.end(), "Duplicate object id!");
|
|
gAllObjects.emplace(object->getId(), object);
|
|
}
|
|
|
|
void unregisterObject(BaseObject* object) noexcept
|
|
{
|
|
{
|
|
const std::unique_lock lock(gAllObjectMutex);
|
|
gAllObjects.erase(object->getId());
|
|
}
|
|
|
|
std::unordered_map<object_id_t, object_destruction_handler_t>::iterator itHandler;
|
|
{
|
|
const std::shared_lock readLock(gDestructionHandlersMutex);
|
|
itHandler = gDestructionHandlers.find(object->getId());
|
|
}
|
|
|
|
if (itHandler != gDestructionHandlers.end())
|
|
{
|
|
object_destruction_handler_t handler;
|
|
{
|
|
const std::unique_lock writeLock(gDestructionHandlersMutex);
|
|
handler = std::move(itHandler->second);
|
|
gDestructionHandlers.erase(itHandler);
|
|
}
|
|
handler();
|
|
}
|
|
}
|
|
|
|
ObjectPtr<BaseObject> getRegisteredObject(object_id_t objectId) noexcept
|
|
{
|
|
const std::shared_lock lock(gAllObjectMutex);
|
|
auto it = gAllObjects.find(objectId);
|
|
if (it != gAllObjects.end()) {
|
|
return it->second->getPointer();
|
|
}
|
|
return {};
|
|
}
|
|
} // namespace iwa::impl
|
|
|
|
namespace iwa
|
|
{
|
|
void registerObjectDestructionHandler(const BaseObject& object, object_destruction_handler_t handler) noexcept
|
|
{
|
|
const std::unique_lock writeLock(impl::gDestructionHandlersMutex);
|
|
impl::gDestructionHandlers.emplace(object.getId(), std::move(handler));
|
|
} // namespace iwa
|
|
}
|