PkmnLib/src/ScriptResolving/AngelScript/ContextPool.hpp

86 lines
2.3 KiB
C++

#ifndef PKMNLIB_CONTEXTPOOL_HPP
#define PKMNLIB_CONTEXTPOOL_HPP
#include <angelscript.h>
#include <mutex>
#include <thread>
#include "AngelscriptUserdata.hpp"
class ContextPool {
struct CtxThreadedPoolStorage {
std::vector<asIScriptContext*> Pool;
std::mutex Lock;
~CtxThreadedPoolStorage() {
for (auto* ctx : Pool) {
ctx->Release();
}
}
};
std::mutex Lock;
ArbUt::Dictionary<std::thread::id, CtxThreadedPoolStorage*> _pool;
AngelScriptResolver* _resolver;
AngelscriptUserdata* _userData;
CtxThreadedPoolStorage* CreateThreadPool(std::thread::id id) {
std::lock_guard<std::mutex> guard(Lock);
auto tryGet = _pool.TryGet(id);
if (tryGet.has_value()) {
return tryGet->get();
}
auto p = new CtxThreadedPoolStorage();
_pool.Insert(id, p);
return p;
}
CtxThreadedPoolStorage* GetThreadPool() {
auto id = std::this_thread::get_id();
auto tryGet = _pool.TryGet(id);
if (tryGet.has_value()) {
return tryGet->get();
}
return CreateThreadPool(id);
}
public:
ContextPool(AngelScriptResolver* resolver, AngelscriptUserdata* userData)
: _resolver(resolver), _userData(userData) {}
~ContextPool() {
for (const auto& kv : _pool) {
delete kv.second;
}
}
asIScriptContext* RequestContext() {
// Get a context from the pool, or create a new
asIScriptContext* ctx = nullptr;
auto* pool = GetThreadPool();
std::lock_guard<std::mutex> guard(pool->Lock);
if (!pool->Pool.empty()) {
ctx = *pool->Pool.rbegin();
pool->Pool.pop_back();
} else {
ctx = _resolver->GetEngine()->CreateContext();
ctx->SetUserData(_userData);
}
#ifdef ANGELSCRIPT_DEBUGGER
if (_resolver->GetDebugger().HasValue()) {
_resolver->GetDebugger().GetValue()->RegisterContext(ctx);
}
#endif
return ctx;
}
void ReturnContextToPool(asIScriptContext* ctx) {
ctx->Unprepare();
auto* pool = GetThreadPool();
std::lock_guard<std::mutex> guard(pool->Lock);
pool->Pool.push_back(ctx);
}
};
#endif // PKMNLIB_CONTEXTPOOL_HPP