Compare commits
2 Commits
fix-contex
...
gea-devel
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
21823a9066 | ||
|
|
8c8aa2358e |
@@ -29,15 +29,16 @@
|
||||
#include <atomic>
|
||||
#include <functional>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include <boost/serialization/access.hpp>
|
||||
#include <boost/serialization/nvp.hpp>
|
||||
#include <boost/serialization/split_member.hpp>
|
||||
|
||||
namespace uLib {
|
||||
|
||||
/**
|
||||
* @brief Internal control block for shared ownership across polymorphic SmartPointers.
|
||||
* @brief Internal control block for shared ownership across polymorphic
|
||||
* SmartPointers.
|
||||
*/
|
||||
struct ControlBlock {
|
||||
std::atomic<uint32_t> count;
|
||||
@@ -49,19 +50,19 @@ private:
|
||||
friend class boost::serialization::access;
|
||||
template <class Archive>
|
||||
void serialize(Archive &ar, const unsigned int /*version*/) {
|
||||
// ControlBlock identity is tracked by Boost via the cb pointer in ReferenceCounter.
|
||||
// We only save the count value.
|
||||
// ControlBlock identity is tracked by Boost via the cb pointer in
|
||||
// ReferenceCounter. We only save the count value.
|
||||
uint32_t c = count.load();
|
||||
ar &boost::serialization::make_nvp("count", c);
|
||||
if constexpr (Archive::is_loading::value) count.store(c);
|
||||
if constexpr (Archive::is_loading::value)
|
||||
count.store(c);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A smart pointer implementation inspired by std::shared_ptr.
|
||||
*/
|
||||
template <typename T>
|
||||
class SmartPointer {
|
||||
template <typename T> class SmartPointer {
|
||||
public:
|
||||
using element_type = T;
|
||||
|
||||
@@ -100,15 +101,17 @@ public:
|
||||
SmartPointer(std::nullptr_t) noexcept : m_counter(nullptr) {}
|
||||
|
||||
/**
|
||||
* @brief Constructor from raw pointer (Implicit conversion allowed for legacy compatibility).
|
||||
* @brief Constructor from raw pointer (Implicit conversion allowed for legacy
|
||||
* compatibility).
|
||||
*/
|
||||
SmartPointer(T *ptr) : m_counter(nullptr) {
|
||||
if (ptr) m_counter = new ReferenceCounter(ptr);
|
||||
if (ptr)
|
||||
m_counter = new ReferenceCounter(ptr);
|
||||
}
|
||||
|
||||
template <typename D>
|
||||
SmartPointer(T* ptr, D deleter) : m_counter(nullptr) {
|
||||
if (ptr) m_counter = new ReferenceCounter(ptr, deleter);
|
||||
template <typename D> SmartPointer(T *ptr, D deleter) : m_counter(nullptr) {
|
||||
if (ptr)
|
||||
m_counter = new ReferenceCounter(ptr, deleter);
|
||||
}
|
||||
|
||||
SmartPointer(T &ref) : m_counter(new ReferenceCounter(&ref, [](T *) {})) {}
|
||||
@@ -118,26 +121,31 @@ public:
|
||||
}
|
||||
|
||||
SmartPointer(const SmartPointer *other) noexcept : m_counter(nullptr) {
|
||||
if (other) acquire(other->m_counter);
|
||||
if (other)
|
||||
acquire(other->m_counter);
|
||||
}
|
||||
|
||||
template <typename U, typename = std::enable_if_t<std::is_convertible_v<U*, T*>>>
|
||||
template <typename U,
|
||||
typename = std::enable_if_t<std::is_convertible_v<U *, T *>>>
|
||||
SmartPointer(const SmartPointer<U> &other) noexcept : m_counter(nullptr) {
|
||||
if (other.m_counter) {
|
||||
m_counter = new ReferenceCounter();
|
||||
m_counter->ptr = static_cast<T *>(other.m_counter->ptr);
|
||||
m_counter->cb = other.m_counter->cb;
|
||||
if (m_counter->cb) m_counter->cb->count.fetch_add(1, std::memory_order_relaxed);
|
||||
if (m_counter->cb)
|
||||
m_counter->cb->count.fetch_add(1, std::memory_order_relaxed);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
SmartPointer(const SmartPointer<U>& other, T* ptr) noexcept : m_counter(nullptr) {
|
||||
SmartPointer(const SmartPointer<U> &other, T *ptr) noexcept
|
||||
: m_counter(nullptr) {
|
||||
if (other.m_counter) {
|
||||
m_counter = new ReferenceCounter();
|
||||
m_counter->ptr = ptr;
|
||||
m_counter->cb = other.m_counter->cb;
|
||||
if (m_counter->cb) m_counter->cb->count.fetch_add(1, std::memory_order_relaxed);
|
||||
if (m_counter->cb)
|
||||
m_counter->cb->count.fetch_add(1, std::memory_order_relaxed);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -171,7 +179,8 @@ public:
|
||||
|
||||
void reset(T *ptr = nullptr) {
|
||||
release();
|
||||
if (ptr) m_counter = new ReferenceCounter(ptr);
|
||||
if (ptr)
|
||||
m_counter = new ReferenceCounter(ptr);
|
||||
}
|
||||
|
||||
void swap(SmartPointer &other) noexcept {
|
||||
@@ -185,7 +194,9 @@ public:
|
||||
operator T *() const noexcept { return get(); }
|
||||
|
||||
uint32_t use_count() const noexcept {
|
||||
return (m_counter && m_counter->cb) ? m_counter->cb->count.load(std::memory_order_relaxed) : 0;
|
||||
return (m_counter && m_counter->cb)
|
||||
? m_counter->cb->count.load(std::memory_order_relaxed)
|
||||
: 0;
|
||||
}
|
||||
|
||||
bool unique() const noexcept { return use_count() == 1; }
|
||||
@@ -208,24 +219,58 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename U> friend class SmartPointer;
|
||||
friend class boost::serialization::access;
|
||||
|
||||
template <class Archive>
|
||||
void serialize(Archive &ar, const unsigned int /*version*/) {
|
||||
if (Archive::is_loading::value) {
|
||||
release();
|
||||
}
|
||||
ar &boost::serialization::make_nvp("counter", m_counter);
|
||||
if (Archive::is_loading::value && m_counter) {
|
||||
m_counter->count.fetch_add(1, std::memory_order_relaxed);
|
||||
}
|
||||
}
|
||||
|
||||
struct ReferenceCounter {
|
||||
T *ptr;
|
||||
std::atomic<uint32_t> count;
|
||||
std::function<void(T *)> deleter;
|
||||
|
||||
ReferenceCounter(T *p, uint32_t initial_count = 1)
|
||||
: ptr(p), count(initial_count),
|
||||
deleter([](T *ptr_to_del) { delete ptr_to_del; }) {}
|
||||
|
||||
template <typename D>
|
||||
ReferenceCounter(T *p, D d, uint32_t initial_count = 1)
|
||||
: ptr(p), count(initial_count), deleter(d) {}
|
||||
|
||||
ReferenceCounter()
|
||||
: ptr(nullptr), count(0), deleter([](T *p) { delete p; }) {}
|
||||
|
||||
private:
|
||||
friend class boost::serialization::access;
|
||||
template <class Archive>
|
||||
void serialize(Archive &ar, const unsigned int /*version*/) {
|
||||
ar &boost::serialization::make_nvp("ptr", ptr);
|
||||
}
|
||||
};
|
||||
|
||||
ReferenceCounter *m_counter;
|
||||
|
||||
void acquire(ReferenceCounter *c) noexcept {
|
||||
m_counter = c;
|
||||
if (c) {
|
||||
m_counter = new ReferenceCounter();
|
||||
m_counter->ptr = c->ptr;
|
||||
m_counter->cb = c->cb;
|
||||
if (m_counter->cb) m_counter->cb->count.fetch_add(1, std::memory_order_relaxed);
|
||||
c->count.fetch_add(1, std::memory_order_relaxed);
|
||||
}
|
||||
}
|
||||
|
||||
void release() noexcept {
|
||||
if (m_counter) {
|
||||
if (m_counter->cb && m_counter->cb->count.fetch_sub(1, std::memory_order_acq_rel) == 1) {
|
||||
if (m_counter->cb->deleter) m_counter->cb->deleter();
|
||||
if (m_counter->cb &&
|
||||
m_counter->cb->count.fetch_sub(1, std::memory_order_acq_rel) == 1) {
|
||||
if (m_counter->cb->deleter)
|
||||
m_counter->cb->deleter();
|
||||
delete m_counter->cb;
|
||||
}
|
||||
delete m_counter;
|
||||
@@ -234,13 +279,24 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename U> SmartPointer<T> static_pointer_cast(const SmartPointer<U>& r) noexcept { return SmartPointer<T>(r, static_cast<T*>(r.get())); }
|
||||
template <typename T, typename U> SmartPointer<T> dynamic_pointer_cast(const SmartPointer<U>& r) noexcept {
|
||||
if (auto p = dynamic_cast<T*>(r.get())) return SmartPointer<T>(r, p);
|
||||
template <typename T, typename U>
|
||||
SmartPointer<T> static_pointer_cast(const SmartPointer<U> &r) noexcept {
|
||||
return SmartPointer<T>(r, static_cast<T *>(r.get()));
|
||||
}
|
||||
template <typename T, typename U>
|
||||
SmartPointer<T> dynamic_pointer_cast(const SmartPointer<U> &r) noexcept {
|
||||
if (auto p = dynamic_cast<T *>(r.get()))
|
||||
return SmartPointer<T>(r, p);
|
||||
return SmartPointer<T>(nullptr);
|
||||
}
|
||||
template <typename T, typename U> SmartPointer<T> const_pointer_cast(const SmartPointer<U>& r) noexcept { return SmartPointer<T>(r, const_cast<T*>(r.get())); }
|
||||
template <typename T, typename U> SmartPointer<T> reinterpret_pointer_cast(const SmartPointer<U>& r) noexcept { return SmartPointer<T>(r, reinterpret_cast<T*>(r.get())); }
|
||||
template <typename T, typename U>
|
||||
SmartPointer<T> const_pointer_cast(const SmartPointer<U> &r) noexcept {
|
||||
return SmartPointer<T>(r, const_cast<T *>(r.get()));
|
||||
}
|
||||
template <typename T, typename U>
|
||||
SmartPointer<T> reinterpret_pointer_cast(const SmartPointer<U> &r) noexcept {
|
||||
return SmartPointer<T>(r, reinterpret_cast<T *>(r.get()));
|
||||
}
|
||||
|
||||
} // namespace uLib
|
||||
|
||||
|
||||
Reference in New Issue
Block a user