feat: add Boost serialization support for SmartPointer and include standard smart pointer headers

This commit is contained in:
AndreaRigoni
2026-04-16 11:30:50 +00:00
parent a3d0a1c28c
commit 8c8aa2358e

View File

@@ -37,7 +37,8 @@
namespace uLib { namespace uLib {
/** /**
* @brief Internal control block for shared ownership across polymorphic SmartPointers. * @brief Internal control block for shared ownership across polymorphic
* SmartPointers.
*/ */
struct ControlBlock { struct ControlBlock {
std::atomic<uint32_t> count; std::atomic<uint32_t> count;
@@ -48,20 +49,20 @@ struct ControlBlock {
private: private:
friend class boost::serialization::access; friend class boost::serialization::access;
template <class Archive> template <class Archive>
void serialize(Archive& ar, const unsigned int /*version*/) { void serialize(Archive &ar, const unsigned int /*version*/) {
// ControlBlock identity is tracked by Boost via the cb pointer in ReferenceCounter. // ControlBlock identity is tracked by Boost via the cb pointer in
// We only save the count value. // ReferenceCounter. We only save the count value.
uint32_t c = count.load(); uint32_t c = count.load();
ar & boost::serialization::make_nvp("count", c); 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. * @brief A smart pointer implementation inspired by std::shared_ptr.
*/ */
template <typename T> template <typename T> class SmartPointer {
class SmartPointer {
public: public:
using element_type = T; using element_type = T;
@@ -70,24 +71,24 @@ public:
* Preserved as a nested template for Boost serialization compatibility. * Preserved as a nested template for Boost serialization compatibility.
*/ */
struct ReferenceCounter { struct ReferenceCounter {
T* ptr; T *ptr;
ControlBlock* cb; ControlBlock *cb;
ReferenceCounter() : ptr(nullptr), cb(nullptr) {} ReferenceCounter() : ptr(nullptr), cb(nullptr) {}
explicit ReferenceCounter(T* p) : ptr(p), cb(new ControlBlock(1)) { explicit ReferenceCounter(T *p) : ptr(p), cb(new ControlBlock(1)) {
cb->deleter = [p]() { delete p; }; cb->deleter = [p]() { delete p; };
} }
template <typename D> template <typename D>
ReferenceCounter(T* p, D d) : ptr(p), cb(new ControlBlock(1)) { ReferenceCounter(T *p, D d) : ptr(p), cb(new ControlBlock(1)) {
cb->deleter = [p, d]() { d(p); }; cb->deleter = [p, d]() { d(p); };
} }
private: private:
friend class boost::serialization::access; friend class boost::serialization::access;
template <class Archive> template <class Archive>
void serialize(Archive& ar, const unsigned int /*version*/) { void serialize(Archive &ar, const unsigned int /*version*/) {
ar & boost::serialization::make_nvp("ptr", ptr); ar &boost::serialization::make_nvp("ptr", ptr);
ar & boost::serialization::make_nvp("cb", cb); ar &boost::serialization::make_nvp("cb", cb);
} }
}; };
@@ -100,54 +101,61 @@ public:
SmartPointer(std::nullptr_t) noexcept : m_counter(nullptr) {} 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) { SmartPointer(T *ptr) : m_counter(nullptr) {
if (ptr) m_counter = new ReferenceCounter(ptr); if (ptr)
m_counter = new ReferenceCounter(ptr);
} }
template <typename D> template <typename D> SmartPointer(T *ptr, D deleter) : m_counter(nullptr) {
SmartPointer(T* ptr, D deleter) : m_counter(nullptr) { if (ptr)
if (ptr) m_counter = new ReferenceCounter(ptr, deleter); m_counter = new ReferenceCounter(ptr, deleter);
} }
SmartPointer(T &ref) : m_counter(new ReferenceCounter(&ref, [](T*){})) { } SmartPointer(T &ref) : m_counter(new ReferenceCounter(&ref, [](T *) {})) {}
SmartPointer(const SmartPointer& other) noexcept : m_counter(nullptr) { SmartPointer(const SmartPointer &other) noexcept : m_counter(nullptr) {
acquire(other.m_counter); acquire(other.m_counter);
} }
SmartPointer(const SmartPointer* other) noexcept : m_counter(nullptr) { 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,
SmartPointer(const SmartPointer<U>& other) noexcept : m_counter(nullptr) { typename = std::enable_if_t<std::is_convertible_v<U *, T *>>>
SmartPointer(const SmartPointer<U> &other) noexcept : m_counter(nullptr) {
if (other.m_counter) { if (other.m_counter) {
m_counter = new ReferenceCounter(); m_counter = new ReferenceCounter();
m_counter->ptr = static_cast<T*>(other.m_counter->ptr); m_counter->ptr = static_cast<T *>(other.m_counter->ptr);
m_counter->cb = other.m_counter->cb; 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> 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) { if (other.m_counter) {
m_counter = new ReferenceCounter(); m_counter = new ReferenceCounter();
m_counter->ptr = ptr; m_counter->ptr = ptr;
m_counter->cb = other.m_counter->cb; 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);
} }
} }
SmartPointer(SmartPointer&& other) noexcept : m_counter(other.m_counter) { SmartPointer(SmartPointer &&other) noexcept : m_counter(other.m_counter) {
other.m_counter = nullptr; other.m_counter = nullptr;
} }
~SmartPointer() { release(); } ~SmartPointer() { release(); }
SmartPointer& operator=(const SmartPointer& other) noexcept { SmartPointer &operator=(const SmartPointer &other) noexcept {
if (this != &other) { if (this != &other) {
release(); release();
acquire(other.m_counter); acquire(other.m_counter);
@@ -155,12 +163,12 @@ public:
return *this; return *this;
} }
SmartPointer& operator=(T* ptr) noexcept { SmartPointer &operator=(T *ptr) noexcept {
reset(ptr); reset(ptr);
return *this; return *this;
} }
SmartPointer& operator=(SmartPointer&& other) noexcept { SmartPointer &operator=(SmartPointer &&other) noexcept {
if (this != &other) { if (this != &other) {
release(); release();
m_counter = other.m_counter; m_counter = other.m_counter;
@@ -169,23 +177,26 @@ public:
return *this; return *this;
} }
void reset(T* ptr = nullptr) { void reset(T *ptr = nullptr) {
release(); release();
if (ptr) m_counter = new ReferenceCounter(ptr); if (ptr)
m_counter = new ReferenceCounter(ptr);
} }
void swap(SmartPointer& other) noexcept { void swap(SmartPointer &other) noexcept {
std::swap(m_counter, other.m_counter); std::swap(m_counter, other.m_counter);
} }
T& operator*() const noexcept { return *(m_counter->ptr); } T &operator*() const noexcept { return *(m_counter->ptr); }
T* operator->() const noexcept { return m_counter->ptr; } T *operator->() const noexcept { return m_counter->ptr; }
T* get() const noexcept { return m_counter ? m_counter->ptr : nullptr; } T *get() const noexcept { return m_counter ? m_counter->ptr : nullptr; }
T* Get() const noexcept { return get(); } T *Get() const noexcept { return get(); }
operator T*() const noexcept { return get(); } operator T *() const noexcept { return get(); }
uint32_t use_count() const noexcept { 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; } bool unique() const noexcept { return use_count() == 1; }
@@ -194,14 +205,14 @@ public:
BOOST_SERIALIZATION_SPLIT_MEMBER() BOOST_SERIALIZATION_SPLIT_MEMBER()
template <class Archive> template <class Archive>
void save(Archive& ar, const unsigned int /*version*/) const { void save(Archive &ar, const unsigned int /*version*/) const {
ar & boost::serialization::make_nvp("counter", m_counter); ar &boost::serialization::make_nvp("counter", m_counter);
} }
template <class Archive> template <class Archive>
void load(Archive& ar, const unsigned int /*version*/) { void load(Archive &ar, const unsigned int /*version*/) {
release(); release();
ar & boost::serialization::make_nvp("counter", m_counter); ar &boost::serialization::make_nvp("counter", m_counter);
if (m_counter && m_counter->cb) { if (m_counter && m_counter->cb) {
m_counter->cb->count.fetch_add(1, std::memory_order_relaxed); m_counter->cb->count.fetch_add(1, std::memory_order_relaxed);
} }
@@ -211,21 +222,24 @@ private:
template <typename U> friend class SmartPointer; template <typename U> friend class SmartPointer;
friend class boost::serialization::access; friend class boost::serialization::access;
ReferenceCounter* m_counter; ReferenceCounter *m_counter;
void acquire(ReferenceCounter* c) noexcept { void acquire(ReferenceCounter *c) noexcept {
if (c) { if (c) {
m_counter = new ReferenceCounter(); m_counter = new ReferenceCounter();
m_counter->ptr = c->ptr; m_counter->ptr = c->ptr;
m_counter->cb = c->cb; m_counter->cb = c->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);
} }
} }
void release() noexcept { void release() noexcept {
if (m_counter) { if (m_counter) {
if (m_counter->cb && m_counter->cb->count.fetch_sub(1, std::memory_order_acq_rel) == 1) { if (m_counter->cb &&
if (m_counter->cb->deleter) m_counter->cb->deleter(); 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->cb;
} }
delete m_counter; delete m_counter;
@@ -234,13 +248,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>
template <typename T, typename U> SmartPointer<T> dynamic_pointer_cast(const SmartPointer<U>& r) noexcept { SmartPointer<T> static_pointer_cast(const SmartPointer<U> &r) noexcept {
if (auto p = dynamic_cast<T*>(r.get())) return SmartPointer<T>(r, p); 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); 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>
template <typename T, typename U> SmartPointer<T> reinterpret_pointer_cast(const SmartPointer<U>& r) noexcept { return SmartPointer<T>(r, reinterpret_cast<T*>(r.get())); } 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 } // namespace uLib