//
// Created by Lenovo on 16.11.2021.
//
#ifndef SMARTPOINTER_HPP
#define SMARTPOINTER_HPP
#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) {
this->core = nullptr;
} else {
this->core = new Core();
core->info = x;
core->cnt = 1;
}
}
SmartPointer(const SmartPointer &x) {
this->core = x.core;
if (x.core != nullptr) {
core->cnt++;
}
}
SmartPointer(SmartPointer &&x) {
this->core = x.core;
x.core = nullptr;
}
SmartPointer &operator=(const SmartPointer &x) {
remove();
this->core = x.core;
if (x.core != nullptr) {
core->cnt++;
}
return *this;
}
SmartPointer &operator=(SmartPointer &&x) {
remove();
this->core = x.core;
x.core = nullptr;
return *this;
}
SmartPointer &operator=(value_type *x) {
remove();
if (x != nullptr) {
this->core = new Core();
core->info = x;
core->cnt = 1;
} else {
this->core = nullptr;
}
return *this;
}
void remove() {
if (core != nullptr) {
core->cnt -= 1;
if (core->cnt == 0) {
delete (core);
}
}
}
~SmartPointer() { remove(); }
value_type &operator*() {
if (core == nullptr) {
throw smart_pointer::exception();
} else {
return *(core->info);
}
}
const value_type &operator*() const {
if (core == nullptr) {
throw smart_pointer::exception();
} else {
return *(core->info);
}
}
value_type *operator->() const {
if (core == nullptr) {
return nullptr;
} else {
return core->info;
}
}
value_type *get() const {
if (core == nullptr) {
return nullptr;
} else {
return core->info;
}
}
operator bool() const { return core != nullptr; }
template<typename U, typename AnotherAllocator>
bool operator==(const SmartPointer<U, AnotherAllocator> &pointer) const {
return static_cast<void *>(this->get()) ==
static_cast<void *>(pointer.get());
}
template<typename U, typename AnotherAllocator>
bool operator!=(const SmartPointer<U, AnotherAllocator> &pointer) const {
return static_cast<void *>(this->get()) !=
static_cast<void *>(pointer.get());
}
std::size_t count_owners() const {
if (core != nullptr) {
return core->cnt;
} else {
return 0;
}
}
private:
class Core {
public:
size_t cnt;
value_type *info;
~Core() {
Allocator allocator;
allocator.deallocate(info, sizeof(value_type));
info = nullptr;
}
};
Core *core;
};
}
#endif