#pragma once
#include <memory>
#include <typeinfo>
#include "Test.hpp"
namespace smart_pointer {
// `exception` class definition
class exception : std::exception {
using base_class = std::exception;
using base_class::base_class;
};
// `SmartPointer` class declaration
template<
typename T,
typename Allocator
>
class SmartPointer {
// don't remove this macro
ENABLE_CLASS_TESTS;
public:
using value_type = T;
explicit SmartPointer(value_type* ptr = nullptr) {
if (ptr != nullptr) {
this->core = new Core(ptr);
} else {
core = nullptr;
}
}
// copy constructor
SmartPointer(const SmartPointer& otherPointer) {
// changeOwners(-1);
this->core = otherPointer.core;
changeOwners(1);
}
// move constructor
SmartPointer(SmartPointer&& oldPointer) {
this->core = oldPointer.core;
oldPointer.changeOwners(-1);
oldPointer.core = nullptr;
}
// copy assigment
SmartPointer& operator=(const SmartPointer& otherPointer) {
changeOwners(-1);
this->core = otherPointer.core;
changeOwners(1);
return *this;
}
// move assigment
SmartPointer& operator=(SmartPointer&& oldPointer) {
changeOwners(-1);
this->core = oldPointer.core;
oldPointer.core = nullptr;
return *this;
}
//
SmartPointer& operator=(value_type* ptr) {
if (ptr != nullptr) {
changeOwners(-1);
this->core = new Core(ptr);
} else {
this->core = nullptr;
}
return *this;
}
~SmartPointer() {
if (this->core != nullptr) {
if (this->core->count_owners == 1) {
delete core;
} else {
this->core->count_owners -= 1;
}
} else {
delete core;
}
}
// return reference to the object of class/type T
// if SmartPointer contains nullptr throw `SmartPointer::exception`
value_type& operator*() {
if (this->core == nullptr) {
throw exception("dfs");
} else {
return *(this->core->ptr);
}
}
value_type& operator*() const {
if (this->core== nullptr) {
throw exception("fgr");
} else {
return *(this->core->ptr);
}
}
// return pointer to the object of class/type T
value_type* operator->() const {
if (core == nullptr) return nullptr;
return this->core->ptr;
}
value_type* get() const {
if (core == nullptr) return nullptr;
return this->core->ptr;
}
// if pointer == nullptr => return false
operator bool() const {
if (this->core == nullptr) {
return false;
} else {
return true;
}
}
// if pointers points to the same address or both null => true
template<typename U, typename AnotherAllocator>
bool operator==(const SmartPointer<U,
AnotherAllocator>& otherPointer) const {
return (int64_t)(this->core) ==
(int64_t)(otherPointer.core);
return false;
}
// if pointers points to the same address or both null => false
template<typename U, typename AnotherAllocator>
bool operator!=(const SmartPointer<U,
AnotherAllocator>& otherPointer) const {
return (int64_t)(this->core) !=
(int64_t)(otherPointer.core);
}
// if smart pointer contains non-nullptr => return count owners
// if smart pointer contains nullptr => return 0
std::size_t count_owners() const {
if (this->core == nullptr) return 0;
return this->core->count_owners;
}
class Core {
public:
T* ptr;
int64_t count_owners;
explicit Core(T* ptr) {
this->ptr = ptr;
if (ptr != nullptr) {
count_owners = 1;
} else {
count_owners = 0;
}
}
bool operator==(const Core& other_core) {
if (typeid(ptr) != typeid(other_core.ptr)) return false;
return this->ptr == other_core.ptr;
}
bool operator!=(const Core& other_core) {
if (typeid(ptr) == typeid(other_core.ptr)) {
return this->ptr != other_core.ptr;
}
return true;
}
};
Core* core;
private:
void changeOwners(int value = 1) {
if (this->core != nullptr) {
if (this->core->ptr != nullptr) {
this->core->count_owners += value;
}
}
}
};
} // namespace smart_pointer