#pragma once
#include<string>
#include<iostream>
#include<fstream>
#include<vector>
#include<iomanip>
#include<sstream>
#include<cmath>
#include <cstdio>
#include <algorithm>
#include <stack>
#include <functional>
#include <set>
#include <queue>
#include <memory>
#include <map>
#include <cassert>
#include <utility>
using std::exchange;
using std::move;
using std::size_t;
#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) :
core((x == nullptr ? nullptr : new Core(x))) {
}
SmartPointer(const SmartPointer& oth) :
core(oth.core != nullptr ? oth.core : nullptr) {
if (core != nullptr) {
this->core->c++;
}
}
SmartPointer(SmartPointer&& oth) :
core(exchange(oth.core, nullptr)) { }
SmartPointer& operator=(const SmartPointer& oth) {
this->~SmartPointer();
this->core = oth.core;
if (this->core != nullptr) {
this->core->c++;
}
return *this;
}
SmartPointer& operator=(SmartPointer&& oth) {
this->~SmartPointer();
this->core = move(oth.core);
oth.core = nullptr;
return *this;
}
SmartPointer& operator=(value_type* p) {
this->~SmartPointer();
if (p == nullptr) {
this->core = nullptr;
} else {
this->core = new Core(p);
}
return *this;
}
~SmartPointer() {
if (this->core != nullptr) {
if (this->core->c <= 1) {
delete this->core;
} else {
this->core->c--;
}
}
}
value_type& operator*() {
if (this->core == nullptr || this->core->p == nullptr) {
throw smart_pointer::exception();
} else {
return *(this->core->p);
}
}
const value_type& operator*() const {
if (this->core == nullptr || this->core->p == nullptr) {
throw smart_pointer::exception();
}
return *(this->core->p);
}
value_type* operator->() const {
return this->get();
}
value_type* get() const {
if (this->core == nullptr) {
return nullptr;
} else {
return this->core->p;
}
}
operator bool() const {
if (this->core == nullptr || this->core->p == nullptr) {
return false;
} else {
return true;
}
}
decltype(auto) getCore() const {
return static_cast<void*>(this->core);
}
template<typename U, typename AnotherAllocator>
bool operator==(const SmartPointer<U, AnotherAllocator>& oth)
const {
return this->getCore() == oth.getCore();
}
template<typename U, typename AnotherAllocator>
bool operator!=(const SmartPointer<U, AnotherAllocator>& oth) const {
return !(SmartPointer::operator==(oth));
}
size_t count_owners() const {
if (this->core == nullptr) {
return 0;
} else {
return this->core->c;
}
}
private:
class Core {
public:
explicit Core(value_type* x) : p(x), c(1) {}
~Core() {
if (p != nullptr) {
delete p;
}
}
size_t c = 0;
value_type* p;
};
Core* core;
};
}; // namespace smart_pointer