AnyPS5/core/shader/recompiler/ThreadOwned.hpp

60 lines
1.5 KiB
C++

#ifndef CORE_SHADER_RECOMPILER_THREADOWNED_HPP
#define CORE_SHADER_RECOMPILER_THREADOWNED_HPP
#include <memory>
#include <pthread.h>
#include <stdexcept>
#include <vector>
namespace ShaderRecompiler {
namespace ThreadOwnedDetail {
struct Owned {
void* object;
void (*destroy)(void*);
};
inline void DestroyAll(void* value) {
auto* owned = static_cast<std::vector<Owned>*>(value);
for (auto it = owned->rbegin(); it != owned->rend(); ++it) it->destroy(it->object);
delete owned;
}
inline pthread_key_t Key() {
static const pthread_key_t key = [] {
pthread_key_t created{};
if (pthread_key_create(&created, DestroyAll) != 0) throw std::runtime_error("ThreadOwned: pthread_key_create failed");
return created;
}();
return key;
}
inline void DestroyAtThreadExit(void* object, void (*destroy)(void*)) {
auto* owned = static_cast<std::vector<Owned>*>(pthread_getspecific(Key()));
if (owned == nullptr) {
owned = new std::vector<Owned>();
if (pthread_setspecific(Key(), owned) != 0) {
delete owned;
throw std::runtime_error("ThreadOwned: pthread_setspecific failed");
}
}
owned->push_back({object, destroy});
}
}
template<typename T>
T& ThreadOwned(T*& slot) {
if (slot == nullptr) {
auto object = std::make_unique<T>();
ThreadOwnedDetail::DestroyAtThreadExit(object.get(), [](void* value) { delete static_cast<T*>(value); });
slot = object.release();
}
return *slot;
}
}
#endif