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