#pragma once
#include <memory>
#include "Test.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* x = nullptr) {
if (x != nullptr) {
core = new Core(x);
core->c++;
} else {
core = nullptr;
}
}
SmartPointer(const SmartPointer& oth) {
core = oth.core;
if (core != nullptr) {
core->c++;
}
}
SmartPointer(SmartPointer&& oth) noexcept {
core = oth.core;
oth.core = nullptr;
}
SmartPointer& operator=(const SmartPointer& oth) {
if (core != nullptr) {
if (core->c > 1) {
core->c--;
} else {
delete (core);
}
}
core = oth.core;
if (core != nullptr) {
oth.core->c++;
}
return *this;
}
SmartPointer& operator=(SmartPointer&& oth) {
core = oth.core;
delete oth.core->p;
oth.core = nullptr;
return *this;
}
SmartPointer &operator=(value_type* oth) {
if (core != nullptr) {
if (core->c > 1) {
core->c--;
} else {
delete (core);
}
}
if (oth != nullptr) {
core = new Core(oth);
} else {
core = nullptr;
}
return *this;
}
~SmartPointer() {
if (core != nullptr) {
core = nullptr;
}
}
value_type& operator*() {
if (core == nullptr) {
throw smart_pointer::exception();
}
return *core->p;
}
const value_type& operator*() const {
if (core == nullptr) {
throw smart_pointer::exception();
}
return *core->p;
}
value_type* operator->() const {
if (core != nullptr) {
return core->p;
}
return nullptr;
}
value_type* get() const {
if (core != nullptr) {
return core->p;
}
return nullptr;
}
explicit operator bool() const {
return (core != nullptr);
}
template <typename U, typename AnotherAllocator>
bool operator==(const SmartPointer<U, AnotherAllocator>& oth) const {
if (core != nullptr) {
return (core->p == reinterpret_cast<value_type*>(oth.get()));
} else {
return (oth.get() == nullptr);
}
}
template <typename U, typename AnotherAllocator>
bool operator!=(const SmartPointer<U, AnotherAllocator>& oth) const {
return !(*this == oth);
}
std::size_t count_owners() const {
if (core == nullptr) {
return 0;
}
return core->c;
}
private:
class Core {
public:
explicit Core(value_type* x) : p(x) {}
size_t c = 0;
value_type* p;
};
Core* core;
};
} // namespace smart_pointer