cs440-assignment3/SharedPtr.hpp

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