#include #ifndef _POWELLCS440 #include #include #define todo(msg) \ std::cerr << msg << std::endl; \ assert(false); namespace cs440 { using counter = std::atomic; class Control { counter count; virtual void destroy() = 0; public: Control() : count{1} {}; void decrement() { count--; if (count == 0) { this->destroy(); } } void increment() { count++; } virtual ~Control() = default; }; template class ControlImpl : public Control { T *val; void destroy() override { // std::cerr << this << '\t' << val << std::endl; // delete val; // delete this; } public: ControlImpl(T *v) : Control{}, val{v} {} ~ControlImpl() = default; }; template class SharedPtr { T *raw; Control *underlying; public: template friend class SharedPtr; // typename U meaning a type which inherits from T SharedPtr() : raw{nullptr}, underlying{nullptr} {} template explicit SharedPtr(U *p) { this->raw = p; this->underlying = new ControlImpl(p); } SharedPtr(const SharedPtr &p) : raw{p.raw}, underlying{p.underlying} { if (this->underlying != nullptr) { this->underlying->increment(); } } template SharedPtr(const SharedPtr &p) : raw{p.raw}, underlying{p.underlying} { if (this->underlying != nullptr) { this->underlying->increment(); } } SharedPtr(SharedPtr &&p) : raw{p.raw}, underlying{p.underlying} { p.raw = nullptr; p.underlying = nullptr; }; template SharedPtr(SharedPtr &&p) : raw{p.raw}, underlying{p.underlying} { p.raw = nullptr; p.underlying = nullptr; } // needs to handle self assignment SharedPtr &operator=(const SharedPtr &rhs) { if (this->underlying == rhs.underlying) { return *this; } this->raw = rhs.raw; if (this->underlying != nullptr) { this->underlying->decrement(); } this->underlying = rhs.underlying; if (this->underlying != nullptr) { this->underlying->increment(); } return *this; } template SharedPtr &operator=(const SharedPtr &rhs) { if (this->underlying == rhs.underlying) { return *this; } this->raw = rhs.raw; if (this->underlying != nullptr) { this->underlying->decrement(); } this->underlying = rhs.underlying; if (this->underlying != nullptr) { this->underlying->increment(); } return *this; } SharedPtr &operator=(SharedPtr &&rhs) { if (this == &rhs) { return *this; } this->raw = rhs.raw; if (this->underlying != nullptr) { this->underlying->decrement(); } this->underlying = rhs.underlying; rhs.raw = nullptr; rhs.underlying = nullptr; } template SharedPtr &operator=(SharedPtr &&rhs) { if (this == &rhs) { return *this; } this->raw = rhs.raw; if (this->underlying != nullptr) { this->underlying->decrement(); } this->underlying = rhs.underlying; rhs.raw = nullptr; rhs.underlying = nullptr; } ~SharedPtr() { if (this->underlying != nullptr) { this->underlying->decrement(); } } void reset() { this->raw = nullptr; if (this->underlying != nullptr) { this->underlying->decrement(); } this->underlying = nullptr; } template void reset(U *p) { this->raw = p; if (this->underlying != nullptr) { this->underlying->decrement(); } this->underlying = new ControlImpl(p); } T *get() const { return this->raw; } T &operator*() const { return *this->get(); } T *operator->() const { return this->get(); } explicit operator bool() const { return this->raw; } template friend bool operator==(const SharedPtr &lhs, const SharedPtr &rhs) { return lhs.raw == rhs.raw; } friend bool operator==(const SharedPtr &lhs, std::nullptr_t) { return lhs.raw == nullptr; } friend bool operator==(std::nullptr_t, const SharedPtr &rhs) { return nullptr == rhs.raw; } // template // friend bool operator!=(const SharedPtr &lhs, const SharedPtr &rhs) // { // return lhs.raw != rhs.raw; // } // friend bool operator!=(const SharedPtr &lhs, std::nullptr_t) { // return lhs.raw != nullptr; // } // friend bool operator!=(std::nullptr_t, const SharedPtr &rhs) { // return nullptr != rhs.raw; // } template friend SharedPtr static_pointer_cast(const SharedPtr &sp) { SharedPtr ret{}; ret.raw = static_cast(sp.raw); ret.underlying = sp.underlying; } template friend SharedPtr dynamic_pointer_cast(const SharedPtr &sp) { SharedPtr ret{}; ret.raw = dynamic_cast(sp.raw); ret.underlying = sp.underlying; } }; } // namespace cs440 #endif