#pragma once
#include <memory>
#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 *pointer = nullptr) {
if(pointer) {
this->core = new Core;
this->core->pointer = pointer;
this->core->sum_pointers = 1;
} else {
this->core = nullptr;
}
}
// copy constructor
SmartPointer(const SmartPointer &smart_p) {
if (smart_p.core) {
++(smart_p.core->sum_pointers);
this->core = new Core;
this->core = smart_p.core;
} else {
this->core = nullptr;
}
}
// move constructor
SmartPointer(SmartPointer &&smart_p) noexcept {
if (smart_p.core) {
this->core = smart_p.core;
smart_p.core = nullptr;
} else {
this->core = nullptr;
}
}
// copy assigment
SmartPointer &operator=(const SmartPointer &smart_p) {
if (smart_p.core) {
++(smart_p.core->sum_pointers);
this->core = smart_p.core;
} else {
this->core = nullptr;
}
return *this;
}
// move assigment
SmartPointer &operator=(SmartPointer &&smart_p) noexcept {
if (smart_p.core) {
this->core = new Core;
this->core->pointer = smart_p.core->pointer;
this->core->sum_pointers = smart_p.core->sum_pointers;
} else {
this->core = nullptr;
}
smart_p.core = nullptr;
return *this;
}
//
SmartPointer &operator=(value_type *pointer) {
if (pointer) {
this->core = new Core;
this->core->sum_pointers = 1;
this->core->pointer = pointer;
} else {
this->core = nullptr;
}
return *this;
}
~SmartPointer() = default;
// return reference to the object of class/type T
// if SmartPointer contains nullptr throw `SmartPointer::exception`
value_type &operator*() {
if (!this->core) {
throw smart_pointer::exception();
}
return *this->core->pointer;
}
const value_type &operator*() const {
if (!this->core) {
throw smart_pointer::exception();
}
return *this->core->pointer;
}
// return pointer to the object of class/type T
value_type *operator->() const {
return (this->core) ? this->core->pointer : nullptr;
}
value_type *get() const {
if (this->core) {
return this->core->pointer;
}
return nullptr;
}
// if pointer == nullptr => return false
explicit operator bool() const {
return this->core != nullptr;
}
// if pointers points to the same address or both null => true
template<typename U, typename AnotherAllocator>
bool operator==(const SmartPointer<U, AnotherAllocator> &smart_p) const {
if (!smart_p.get() && !this->get()) {
return true;
}
return static_cast<void*>(smart_p.get()) == static_cast<void*>(this->get());
}
// if pointers points to the same address or both null => false
template<typename U, typename AnotherAllocator>
bool operator!=(const SmartPointer<U, AnotherAllocator> &smart_p) const {
if (!smart_p.get() && !this->get()) {
return false;
}
return static_cast<void*>(smart_p.get()) != static_cast<void*>(this->get());
}
// if smart pointer contains non-nullptr => return count owners
// if smart pointer contains nullptr => return 0
[[nodiscard]] std::size_t count_owners() const {
return (this->core) ? this->core->sum_pointers : 0;
}
private:
class Core {
public:
value_type *pointer;
size_t sum_pointers;
~Core() {
delete pointer;
}
};
Core *core;
};
}