mirror of
https://github.com/mutouyun/cpp-ipc.git
synced 2025-12-07 01:06:45 +08:00
113 lines
2.7 KiB
C++
Executable File
113 lines
2.7 KiB
C++
Executable File
#pragma once
|
|
|
|
#include <memory> // std::unique_ptr
|
|
#include <utility> // std::forward
|
|
#include <cstddef> // std::size_t
|
|
|
|
#include "libipc/export.h"
|
|
|
|
namespace ipc {
|
|
namespace tls {
|
|
|
|
using key_t = std::size_t;
|
|
using destructor_t = void (*)(void *);
|
|
|
|
struct key_info {
|
|
key_t key_;
|
|
};
|
|
|
|
IPC_EXPORT bool create (key_info * pkey, destructor_t destructor = nullptr);
|
|
IPC_EXPORT void release(key_info const * pkey);
|
|
|
|
IPC_EXPORT bool set(key_info const * pkey, void * ptr);
|
|
IPC_EXPORT void * get(key_info const * pkey);
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
/// Thread-local pointer
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
/**
|
|
* @remarks
|
|
* You need to set the ipc::tls::pointer's storage manually:
|
|
* ```
|
|
* tls::pointer<int> p;
|
|
* if (!p) p = new int(123);
|
|
* ```
|
|
* It would be like an ordinary pointer.
|
|
* Or you could just call create_once to 'new' this pointer automatically.
|
|
* ```
|
|
* tls::pointer<int> p;
|
|
* p.create_once(123);
|
|
* ```
|
|
*/
|
|
|
|
template <typename T>
|
|
class pointer : public key_info {
|
|
|
|
pointer(pointer const &) = delete;
|
|
pointer & operator=(pointer const &) = delete;
|
|
|
|
void destruct() const {
|
|
delete static_cast<T*>(tls::get(this));
|
|
}
|
|
|
|
public:
|
|
using value_type = T;
|
|
|
|
pointer() {
|
|
tls::create(this, [](void* p) {
|
|
delete static_cast<T*>(p);
|
|
});
|
|
}
|
|
|
|
~pointer() {
|
|
destruct();
|
|
tls::release(this);
|
|
}
|
|
|
|
template <typename... P>
|
|
T* create(P&&... params) {
|
|
destruct();
|
|
std::unique_ptr<T> ptr { new T(std::forward<P>(params)...) };
|
|
if (!tls::set(this, ptr.get())) {
|
|
return nullptr;
|
|
}
|
|
return ptr.release();
|
|
}
|
|
|
|
template <typename... P>
|
|
T* create_once(P&&... params) {
|
|
auto p = static_cast<T*>(tls::get(this));
|
|
if (p == nullptr) {
|
|
std::unique_ptr<T> ptr { new T(std::forward<P>(params)...) };
|
|
if (!tls::set(this, ptr.get())) {
|
|
return nullptr;
|
|
}
|
|
p = ptr.release();
|
|
}
|
|
return p;
|
|
}
|
|
|
|
T* operator=(T* p) {
|
|
set(this, p);
|
|
return p;
|
|
}
|
|
|
|
explicit operator T *() const {
|
|
return static_cast<T *>(tls::get(this));
|
|
}
|
|
|
|
explicit operator bool() const {
|
|
return tls::get(this) != nullptr;
|
|
}
|
|
|
|
T & operator* () { return *static_cast<T *>(*this); }
|
|
const T & operator* () const { return *static_cast<T *>(*this); }
|
|
|
|
T * operator->() { return static_cast<T *>(*this); }
|
|
const T * operator->() const { return static_cast<T *>(*this); }
|
|
};
|
|
|
|
} // namespace tls
|
|
} // namespace ipc
|