#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: ``` thread_local_ptr p; if (!p) p = new int(123); ``` Just like an ordinary pointer. Or you could just call create: ``` thread_local_ptr 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) { auto ptr = static_cast(*this); if (ptr == nullptr) { return (*this) = new T { std::forward

(params)... }; } 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