iwa/source/object.cpp

133 lines
3.9 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
}
// did you call instance->requestQuit() and then instance->getMainTaskLoop().runUntilDone()?
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
}