#include <memory>
#include "Test.hpp"
#ifndef SMARTPOINTER_HPP
#define SMARTPOINTER_HPP
namespace smart_pointer {
class exception : std::exception {
using base_class = std::exception;
using base_class::base_class;
};
template<
typename T,
typename Allocator
>
class SmartPointer {
ENABLE_CLASS_TESTS;
public:
using value_type = T;
explicit SmartPointer(value_type* p = nullptr) {
if (p == nullptr) {
this->core = nullptr;
} else {
this->core = new Core();
core->p = p;
core->count = 1;
}
}
SmartPointer(const SmartPointer& other) {
this->core = other.core;
if (other.core) core->count++;
}
SmartPointer(SmartPointer&& other) {
this->core = other.core;
other = nullptr;
}
SmartPointer& operator=(const SmartPointer& other) {
if (core != nullptr) {
core->count--;
if (core->count == 0) {
delete (core);
}
}
this->core = other.core;
if (other.core) {
core->count++;
}
return *this;
}
SmartPointer& operator=(SmartPointer&& other) {
if (core != nullptr) {
core->count--;
if (core->count == 0) {
delete (core);
}
}
this->core = other.core;
other.core = nullptr;
return *this;
}
SmartPointer& operator=(value_type* p) {
if (core != nullptr) {
core->count--;
if (core->count == 0) {
delete (core);
}
}
if (p != nullptr) {
this->core = new Core();
core->p = p;
core->count = 1;
} else {
this->core = nullptr;
}
return *this;
}
~SmartPointer() {
if (core != nullptr) {
core->count--;
if (core->count == 0) {
delete (core);
}
}
}
value_type& operator*() {
if (core != nullptr)
return *(core->p);
throw smart_pointer::exception();
}
const value_type& operator*() const {
if (core != nullptr)
return *(core->p);
throw smart_pointer::exception();
}
value_type* operator->() const {
if (core != nullptr)
return core->p;
return nullptr;
}
value_type* get() const {
if (core != nullptr)
return core->p;
return nullptr;
}
operator bool() const {
return core != nullptr;
}
template<typename U, typename AnotherAllocator>
bool operator==(const SmartPointer<U, AnotherAllocator>& other) const {
return (reinterpret_cast<void*>(this->get()) ==
reinterpret_cast<void*>(other.get()));
}
template<typename U, typename AnotherAllocator>
bool operator!=(const SmartPointer<U, AnotherAllocator>& other) const {
return (reinterpret_cast<void*>(this->get()) !=
reinterpret_cast<void*>(other.get()));
}
std::size_t count_owners() const {
if (core == nullptr) return 0;
return core->count;
}
private:
class Core {
public:
value_type* p;
std::size_t count;
~Core() {
Allocator a;
a.deallocate(p, sizeof(value_type));
p = nullptr;
}
};
Core* core;
};
} // namespace smart_pointer
#endif