#pragma once #include #include #include #include "export.h" namespace ipc { namespace tls { using key_t = std::uint64_t; using destructor_t = void (*)(void*); enum : key_t { invalid_value = (std::numeric_limits::max)() }; IPC_EXPORT key_t create (destructor_t destructor = nullptr); IPC_EXPORT void release(key_t key); IPC_EXPORT bool set(key_t key, void* ptr); IPC_EXPORT void* get(key_t key); //////////////////////////////////////////////////////////////// /// Thread-local pointer //////////////////////////////////////////////////////////////// /* * * * 1. In Windows, if you do not compile thread_local_ptr.cpp, * use thread_local_ptr will cause memory leaks. * * 2. You need to set the thread_local_ptr's storage manually: * ``` * tls::pointer p; * if (!p) p = new int(123); * ``` * Just like an ordinary pointer. Or you could just call create: * ``` * tls::pointer p; * p.create(123); * ``` */ template class pointer { key_t key_; public: using value_type = T; pointer() : key_(tls::create([](void* p) { delete static_cast(p); })) { } ~pointer() { tls::release(key_); } template T* create(P&&... params) { thread_local auto ptr = static_cast(get(key_)); if (ptr == nullptr) { ptr = new T(std::forward

(params)...); if (!set(key_, ptr)) { delete ptr; return nullptr; } } return ptr; } T* operator=(T* ptr) { set(key_, ptr); return ptr; } operator T*() const { return static_cast(get(key_)); } T& operator* () { return *static_cast(*this); } const T& operator* () const { return *static_cast(*this); } T* operator->() { return static_cast(*this); } const T* operator->() const { return static_cast(*this); } }; } // namespace tls } // namespace ipc