#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 *val = nullptr):
core(val == nullptr ? nullptr :new Core(val, 1)) {}
SmartPointer(const SmartPointer &val) {
core = val.core;
if (core != nullptr)
core->ptr_count++;
}
SmartPointer(SmartPointer &&val) {
core = val.core;
val.core = nullptr;
}
SmartPointer &operator=(const SmartPointer &val) {
if (core != nullptr) {
core->ptr_count--;
if (core->ptr_count == 0) {
delete core->ptr;
delete core;
}
}
core = val.core;
if (core != nullptr)
core->ptr_count++;
return *this;
}
SmartPointer &operator=(SmartPointer &&val) {
if (core != nullptr) {
core->ptr_count--;
if (core->ptr_count == 0) {
delete core->ptr;
delete core;
}
}
core = val.core;
val.core = nullptr;
return *this;
}
SmartPointer &operator=(value_type *val) {
if (core != nullptr) {
core->ptr_count--;
if (core->ptr_count == 0) {
delete core->ptr;
delete core;
}
}
if (val == nullptr) {
core = nullptr;
return *this;
}
core = new Core(val, 1);
return *this;
}
~SmartPointer() {
if (core != nullptr) {
core->ptr_count--;
if (core->ptr_count == 0) {
delete core->ptr;
delete core;
}
}
}
value_type &operator*() {
if (core == nullptr || core->ptr == nullptr)
throw smart_pointer::exception();
return *(core->ptr);
}
const value_type &operator*() const {
if (core == nullptr || core->ptr == nullptr)
throw smart_pointer::exception();
return *(core->ptr);
}
value_type *operator->() const {
if (core != nullptr)
return core->ptr;
return nullptr;
}
value_type *get() const {
if (core != nullptr)
return core->ptr;
return nullptr;
}
operator bool() const {
if (core == nullptr)
return false;
return core->ptr != nullptr;
}
template<typename U, typename AnotherAllocator>
bool operator==(const SmartPointer<U, AnotherAllocator> &val) const {
bool exp1, exp2;
exp1 = get() == nullptr && val.get() == nullptr;
exp2 = static_cast<void*>(get()) == static_cast<void*>(val.get());
return exp1 || exp2;
}
template<typename U, typename AnotherAllocator>
bool operator!=(const SmartPointer<U, AnotherAllocator> &val) const {
bool exp1, exp2;
exp1 = get() == nullptr && val.get() == nullptr;
exp2 = static_cast<void*>(get()) == static_cast<void*>(val.get());
return !(exp1 || exp2);
}
std::size_t count_owners() const {
if (core != nullptr)
return core->ptr_count;
return 0;
}
private:
class Core {
public:
Core(value_type *val, size_t count) : ptr(val), ptr_count(count) {}
value_type *ptr;
size_t ptr_count;
};
Core *core;
};
} // namespace smart_pointer