150 lines
4.1 KiB
C++
150 lines
4.1 KiB
C++
#include <atomic>
|
|
#ifndef _POWELLCS440
|
|
#include <cassert>
|
|
#include <iostream>
|
|
|
|
#define todo(msg) \
|
|
std::cerr << msg << std::endl; \
|
|
assert(false);
|
|
|
|
namespace cs440 {
|
|
using counter = std::atomic<std::size_t>;
|
|
template <typename T> class SharedPtr;
|
|
class Key {
|
|
Key() {}
|
|
|
|
public:
|
|
template <typename U> friend class SharedPtr;
|
|
template <typename U> void increment(SharedPtr<U> const &ptr) {
|
|
const_cast<std::atomic<size_t> &>(*ptr.count)++;
|
|
}
|
|
template <typename U> counter *get_counter(SharedPtr<U> const &ptr) {
|
|
return const_cast<std::atomic<size_t> *>(ptr.count);
|
|
}
|
|
template <typename U> U *get_ptr(SharedPtr<U> const &ptr) {
|
|
return const_cast<U *>(ptr.ptr);
|
|
}
|
|
template <typename U> void nullify(SharedPtr<U> &&ptr) {
|
|
ptr.ptr = nullptr;
|
|
ptr.count = nullptr;
|
|
}
|
|
};
|
|
template <typename T> class SharedPtr {
|
|
T *ptr;
|
|
std::atomic<std::size_t> *count;
|
|
|
|
public:
|
|
friend class Key;
|
|
SharedPtr() : ptr{nullptr}, count{new std::atomic<std::size_t>{1}} {}
|
|
template <typename U>
|
|
explicit SharedPtr(U *ptr)
|
|
: ptr{ptr}, count{new std::atomic<std::size_t>{1}} {}
|
|
SharedPtr(const SharedPtr &p) : ptr{p.ptr} {
|
|
Key().increment(p);
|
|
this->count = Key().get_counter(p);
|
|
}
|
|
template <typename U>
|
|
SharedPtr(const SharedPtr<U> &p) : ptr{Key().get_ptr(p)} {
|
|
Key().increment(p);
|
|
this->count = Key().get_counter(p);
|
|
}
|
|
SharedPtr(SharedPtr &&p)
|
|
: count{Key().get_counter(p)}, ptr{Key().get_ptr(p)} {
|
|
Key().nullify(p);
|
|
}
|
|
template <typename U>
|
|
SharedPtr(SharedPtr<U> &&p)
|
|
: count{Key().get_counter(p)}, ptr{Key().get_ptr(p)} {
|
|
Key().nullify(p);
|
|
}
|
|
SharedPtr &operator=(const SharedPtr &ptr) {
|
|
Key().increment(ptr);
|
|
this->count = Key().get_counter(ptr);
|
|
this->ptr = Key().get_ptr(ptr);
|
|
return *this;
|
|
}
|
|
template <typename U> SharedPtr<T> &operator=(const SharedPtr<U> &ptr) {
|
|
Key().increment(ptr);
|
|
this->count = Key().get_counter(ptr);
|
|
this->ptr = Key().get_ptr(ptr);
|
|
return *this;
|
|
}
|
|
SharedPtr &operator=(SharedPtr &&p) {
|
|
this->count = Key().get_counter(ptr);
|
|
this->ptr = Key().get_ptr(ptr);
|
|
Key().nullify(p);
|
|
}
|
|
template <typename U> SharedPtr &operator=(SharedPtr<U> &&p) {
|
|
this->count = Key().get_counter(ptr);
|
|
this->ptr = Key().get_ptr(ptr);
|
|
Key().nullify(p);
|
|
}
|
|
~SharedPtr() {
|
|
if (this->count == nullptr) {
|
|
if (this->ptr != nullptr) {
|
|
delete this->ptr;
|
|
}
|
|
return;
|
|
}
|
|
if (--(*this->count) == 0) {
|
|
delete this->count;
|
|
delete this->ptr;
|
|
}
|
|
}
|
|
void reset() {
|
|
if (this->count != nullptr) {
|
|
if (--(*this->count) == 0) {
|
|
delete this->count;
|
|
delete this->ptr;
|
|
return;
|
|
}
|
|
}
|
|
this->ptr = nullptr;
|
|
this->count = nullptr;
|
|
}
|
|
template <typename U> void reset(U *p) {
|
|
this->reset();
|
|
this->count = new counter{1};
|
|
this->ptr = p;
|
|
}
|
|
T *get() const { return this->ptr; }
|
|
T &operator*() const { return *this->ptr; }
|
|
T *operator->() const { return this->ptr; }
|
|
explicit operator bool() const { return this->ptr != nullptr; }
|
|
template <typename T1, typename T2>
|
|
template <typename U>
|
|
friend SharedPtr<T> static_pointer_cast(const SharedPtr<U> &sp) {
|
|
todo("");
|
|
}
|
|
template <typename U>
|
|
friend SharedPtr<T> dynamic_pointer_cast(const SharedPtr<U> &sp) {
|
|
todo("");
|
|
}
|
|
};
|
|
template <typename T1, typename T2>
|
|
bool operator==(const SharedPtr<T1> &lhs, const SharedPtr<T2> &rhs) {
|
|
return lhs.get() == rhs.get();
|
|
}
|
|
template <typename T>
|
|
bool operator==(const SharedPtr<T> &lhs, std::nullptr_t rhs) {
|
|
|
|
return lhs.get() == rhs;
|
|
}
|
|
template <typename T>
|
|
bool operator==(std::nullptr_t lhs, const SharedPtr<T> &rhs) {
|
|
return lhs == rhs.get();
|
|
}
|
|
template <typename T1, typename T2>
|
|
bool operator!=(const SharedPtr<T1> &lhs, const SharedPtr<T2> &rhs) {
|
|
return !(lhs == rhs);
|
|
}
|
|
template <typename T>
|
|
bool operator!=(const SharedPtr<T> &lhs, std::nullptr_t rhs) {
|
|
return !(lhs == rhs);
|
|
}
|
|
template <typename T>
|
|
bool operator!=(std::nullptr_t lhs, const SharedPtr<T> &rhs) {
|
|
return !(lhs == rhs);
|
|
}
|
|
} // namespace cs440
|
|
#endif
|