This commit is contained in:
MaxanRus 2023-07-16 10:03:47 +03:00
commit 46288f0f07
36 changed files with 7578 additions and 0 deletions

121
avl/main.cpp Normal file
View file

@ -0,0 +1,121 @@
#include <bits/stdc++.h>
template<typename T>
class AVLTree {
private:
struct Node {
T content;
Node* left = nullptr;
Node* right = nullptr;
size_t height = 0;
Node(const Node&) = default;
Node(const T& content) : content(content) {}
void Update() {
height = std::min((left ? left->height : 0), (right ? right->height : 0)) + 1;
}
int GetDifference() {
return (left ? left->height : 0) - (right ? right->height : 0);
}
};
Node* root_;
static Node* LeftRotate(Node* v) {
Node* tmp = v->right;
v->right = tmp->left;
tmp->left = v;
v->Update();
tmp->Update();
return tmp;
}
static Node* RightRotate(Node* v) {
Node* tmp = v->left;
v->left = tmp->right;
tmp->right = v;
v->Update();
tmp->Update();
return tmp;
}
static Node* BigLeftRotate(Node* v) {
v->right = RightRotate(v->right);
return LeftRotate(v);
}
static Node* BigRightRotate(Node* v) {
v->left = LeftRotate(v->left);
return RightRotate(v);
}
void stabilization(Node*& v) {
v->Update();
if (v->GetDifference() == -2) {
if (v->right->GetDifference() != 1) {
v = LeftRotate(v);
} else {
v = BigLeftRotate(v);
}
} else if (v->GetDifference() == 2) {
if (v->left->GetDifference() != -1) {
v = RightRotate(v);
} else {
v = BigRightRotate(v);
}
}
}
void insert(Node* v, const T& element) {
if (v->content == element) {
// ТУТ НАДО ЧТО-ТО ИЗМЕНИТЬ, ЕСЛИ ХОТИМ МУЛЬТИМНОЖЕСТВО
return;
} else if (v->content > element) {
if (v->left) {
insert(v->left, element);
stabilization(v);
} else {
v->left = new Node(element);
}
} else if (v->content < element) {
if (v->right) {
insert(v->right, element);
stabilisztion(v);
} else {
v->right = new Node(element);
}
}
}
T eraseMinimum(Node* v) {
if (v->left) {
T tmp = eraseMinimum(v->left);
stabilisztion(v);
return tmp;
} else {
}
}
void erase(Node* v, const T& element) {
if ()
}
public:
void insert(const T& element) {
insert(root_, element);
}
void erase(const T& element) {
erase(root_, element);
}
};
int main() {
AVLTree<int> a;
a.insert(10);
}

638
biginteger/biginteger.h Normal file
View file

@ -0,0 +1,638 @@
#include <algorithm>
#include <complex>
#include <cstring>
#include <iomanip>
#include <sstream>
#include <vector>
namespace FastFourierTransform {
typedef double ld;
typedef std::complex<ld> cld;
typedef std::vector<cld> ComplexPolynom;
const ld PI = acosl(-1);
std::vector<int16_t> Muliplication(const std::vector<int16_t>& a,
const std::vector<int16_t>& b,
std::vector<int16_t>& result);
ComplexPolynom ToComplex(const std::vector<int16_t>& a);
void FastFourierTransform_(ComplexPolynom& a, bool invert);
std::vector<int16_t> Muliplication(const std::vector<int16_t>& a,
const std::vector<int16_t>& b,
std::vector<int16_t>& result) {
ComplexPolynom ca = ToComplex(a);
ComplexPolynom cb = ToComplex(b);
size_t n = std::max(a.size(), b.size());
size_t m = 1;
while (m < n) m <<= 1;
m <<= 1;
ca.resize(m);
cb.resize(m);
FastFourierTransform_(ca, false);
FastFourierTransform_(cb, false);
for (size_t i = 0; i < m; ++i) {
ca[i] *= cb[i];
}
FastFourierTransform_(ca, true);
std::vector<int64_t> v(m);
for (size_t i = 0; i < m; ++i) {
v[i] = ca[i].real() + 0.5;
}
for (size_t i = 0; i < m; ++i) {
v[i + 1] += v[i] / 10000;
v[i] %= 10000;
while (v[i] < 0) v[i] += 10000, v[i + 1] -= 1;
}
result.resize(v.size());
std::copy(v.begin(), v.end(), result.begin());
return result;
}
ComplexPolynom ToComplex(const std::vector<int16_t>& a) {
ComplexPolynom res(a.begin(), a.end());
return res;
}
size_t rev(size_t num, size_t lg_n) {
int res = 0;
for (size_t i = 0; i < lg_n; ++i)
if (num & (1 << i)) res |= 1 << (lg_n - 1 - i);
return res;
}
void FastFourierTransform_(ComplexPolynom& a, bool invert) {
size_t n = a.size();
size_t lg_n = 0;
while ((1u << lg_n) < n) ++lg_n;
for (size_t i = 0; i < n; ++i)
if (i < rev(i, lg_n)) swap(a[i], a[rev(i, lg_n)]);
for (size_t len = 2; len <= n; len <<= 1) {
double ang = 2 * PI / len * (invert ? -1 : 1);
cld wlen(cos(ang), sin(ang));
for (size_t i = 0; i < n; i += len) {
cld w(1);
for (size_t j = 0; j < len / 2; ++j) {
cld u = a[i + j], v = a[i + j + len / 2] * w;
a[i + j] = u + v;
a[i + j + len / 2] = u - v;
w *= wlen;
}
}
}
if (invert)
for (size_t i = 0; i < n; ++i) a[i] /= n;
}
}; // namespace FastFourierTransform
class BigInteger;
BigInteger operator-(const BigInteger& a, const BigInteger& b);
BigInteger operator*(const BigInteger& a, const BigInteger& b);
BigInteger operator/(const BigInteger& a, const BigInteger& b);
BigInteger operator+(const BigInteger& a, const BigInteger& b);
bool operator>(const BigInteger& a, const BigInteger& b);
bool operator<=(const BigInteger& a, const BigInteger& b);
bool operator>=(const BigInteger& a, const BigInteger& b);
bool operator==(const BigInteger& a, const BigInteger& b);
bool operator!=(const BigInteger& a, const BigInteger& b);
BigInteger operator%(const BigInteger& a, const BigInteger& b);
class BigInteger {
public:
BigInteger() {}
BigInteger(int64_t x) {
if (x < 0) {
is_negative_ = true, x *= -1;
}
t_[0] = x % BASE;
x /= BASE;
while (x > 0) {
t_.push_back(x % BASE);
x /= BASE;
}
Normalize();
}
BigInteger(const BigInteger& x) : t_(x.t_), is_negative_(x.is_negative_) {}
void swap(BigInteger& x) {
std::swap(t_, x.t_);
std::swap(is_negative_, x.is_negative_);
}
BigInteger& operator=(const BigInteger& x) {
BigInteger tmp = x;
swap(tmp);
return *this;
}
friend bool operator<(const BigInteger& a, const BigInteger& b) {
if (a.is_negative_ ^ b.is_negative_) {
return a.is_negative_;
}
if (a.t_.size() != b.t_.size()) {
return (a.t_.size() < b.t_.size()) ^ a.is_negative_;
}
for (size_t i = a.t_.size(); i > 0; --i) {
if (a.t_[i - 1] != b.t_[i - 1]) {
return (a.t_[i - 1] < b.t_[i - 1]) ^ a.is_negative_;
}
}
return a.is_negative_;
}
BigInteger& operator++() {
*this += 1;
Normalize();
return *this;
}
BigInteger operator++(int) {
BigInteger tmp = *this;
++(*this);
return tmp;
}
void addingDifferentSigns(const BigInteger& x) {
int16_t carry[2] = {0, 0};
// Вычитаем, если *this < x, то последнее число будет отрицательным и
// потом это пофиксим
for (size_t i = 0; i < x.t_.size() || (carry[i & 1] && i < t_.size());
++i) {
if (i < x.t_.size()) {
t_[i] -= x.t_[i];
}
t_[i] += carry[i & 1];
if (t_[i] < 0 && i + 1 < t_.size()) {
t_[i] += BASE;
carry[(i & 1) ^ 1] = -1;
} else {
carry[(i & 1) ^ 1] = 0;
}
}
// Убераем нули в начале и начинаем фиксить отрицательное число
Normalize();
if (t_.back() < 0) {
t_.pop_back();
for (size_t i = 0; i < t_.size(); ++i) {
t_[i] = BASE - 1 - t_[i];
}
++t_[0];
while (t_.size() > 1 && t_.back() == 0) {
t_.pop_back();
}
is_negative_ ^= true;
}
// Когда мы пофиксили отрицательные числа, у нас в ячейках могли
// образоваться числа >= BASE, фиксим это
carry[0] = 0;
carry[1] = 0;
if (t_[0] >= BASE) {
carry[1] = 1;
t_[0] -= BASE;
}
for (size_t i = 1; i < t_.size() && carry[i & 1]; ++i) {
t_[i] += carry[i & 1];
carry[i & 1] = 0;
if (t_[i] >= BASE) {
carry[(i & 1) ^ 1] = 1;
t_[i] -= BASE;
}
}
// У нас может произойти перенос в ячейку, которой не существует, добавим
// ее)
if (carry[t_.size() & 1]) {
t_.push_back(1);
}
}
BigInteger& operator+=(const BigInteger& x) {
t_.resize(std::max(t_.size(), x.t_.size()) + 1);
// Если числа одинаковых знаков - просто сложение
if (!is_negative_ ^ x.is_negative_) {
int16_t carry[2] = {0, 0};
for (size_t i = 0; i < x.t_.size() || carry[i & 1]; ++i) {
if (i < x.t_.size()) {
t_[i] += x.t_[i];
}
t_[i] += carry[i & 1];
if (t_[i] >= BASE) {
t_[i] -= BASE;
carry[(i & 1) ^ 1] = 1;
} else {
carry[(i & 1) ^ 1] = 0;
}
}
Normalize();
} else {
addingDifferentSigns(x);
}
return *this;
}
BigInteger& operator-=(const BigInteger& x) {
// a - b = -(-a + b)
is_negative_ ^= 1;
*this += x;
is_negative_ ^= 1;
Normalize();
return *this;
}
BigInteger& operator*=(int16_t x) {
// Это умножение на маленькое число, работает за O(n) и используется в
// делении
if (x < 0) {
is_negative_ = !is_negative_;
x *= -1;
}
if (x >= BASE) {
return *this *= BigInteger(x);
}
t_.resize(t_.size() + 3);
int16_t carry[2] = {0, 0};
for (size_t i = 0; i < t_.size(); ++i) {
carry[!(i & 1)] = (int(t_[i]) * x + carry[i & 1]) / BASE;
t_[i] = (int(t_[i]) * x + carry[i & 1]) % BASE;
}
while (t_.size() > 1 && t_.back() == 0) t_.pop_back();
Normalize();
return *this;
}
BigInteger& operator*=(const BigInteger& x) {
// Если число на которое нам надо умножить небольшое, выгоднее умножать за
// квадрат
if (x.t_.size() < 100) {
return SquareMultiplication(x);
}
FastFourierTransform::Muliplication(t_, x.t_, t_);
is_negative_ ^= x.is_negative_;
Normalize();
return *this;
}
// Деление работает за O(N^2), мы вычисляем все значащие биты в делении,
// которых O(n), с помощью бинпоиска(константа, так как log 10000), и
// проверкой в бинпоиске за O(n), потому что используется умножение за O(n), и
// в итоге O(N^2)
BigInteger& operator/=(const BigInteger& x) {
bool is_negative = is_negative_ ^ x.is_negative_;
is_negative_ = false;
std::vector<int16_t> res(t_.size() - std::min(x.t_.size(), t_.size()) + 4);
int16_t d = 1;
if (x < 0) {
d = -1;
}
for (int i = res.size(); i > 0; --i) {
int l = 0, r = BASE - 1, m;
while (l != r) {
m = (l + r + 1) / 2;
if ((x * d * m).MuliplicationDegree10(i - 1) <= *this) {
l = m;
} else {
r = m - 1;
}
}
res[i - 1] = l;
*this -= (x * d * res[i - 1]).MuliplicationDegree10(i - 1);
}
t_ = res;
is_negative_ = is_negative;
Normalize();
return *this;
}
BigInteger& operator%=(const BigInteger& x) {
*this -= (*this / x) * x;
Normalize();
return *this;
}
std::string toString() const {
std::ostringstream string;
if (is_negative_) {
string << "-";
}
string << t_.back();
for (auto it = ++t_.rbegin(); it != t_.rend(); ++it) {
string << std::setw(4) << std::setfill('0') << *it;
}
return string.str();
}
explicit operator bool() const { return t_.size() > 1 || t_[0]; }
friend std::istream& operator>>(std::istream& in, BigInteger& x) {
std::string s;
in >> s;
std::reverse(s.begin(), s.end());
if (s.back() == '-') {
x.is_negative_ = true;
s.pop_back();
} else {
x.is_negative_ = false;
}
while (s.size() % 4) {
s.push_back('0');
}
x.t_.resize(s.size() / 4);
for (size_t i = 0; i < s.size(); i += 4) {
x.t_[i / 4] = s[i] - '0' + 10 * (s[i + 1] - '0') +
100 * (s[i + 2] - '0') + 1000 * (s[i + 3] - '0');
}
x.Normalize();
return in;
}
friend std::ostream& operator<<(std::ostream& out, const BigInteger& x) {
out << x.toString();
return out;
}
BigInteger operator-() {
BigInteger tmp(*this);
tmp.is_negative_ ^= true;
tmp.Normalize();
return tmp;
}
private:
void Normalize() {
while (t_.size() > 1 && t_.back() == 0) {
t_.pop_back();
}
if (t_.size() == 1 && t_[0] == 0) {
is_negative_ = false;
}
}
// Это умножение на 10^degree
BigInteger& MuliplicationDegree10(int degree) {
size_t n = t_.size();
t_.resize(t_.size() + degree);
std::rotate(t_.begin(), t_.begin() + n, t_.end());
Normalize();
return *this;
}
// Это используется, если число на которое мы умножаем не очень большое,
// потому что FFT работает достаточно медленно
BigInteger& SquareMultiplication(const BigInteger& x) {
std::vector<uint64_t> t(t_.size() + x.t_.size() + 1);
for (size_t i = 0; i < t_.size(); ++i) {
for (size_t j = 0; j < x.t_.size(); ++j) {
t[i + j] += static_cast<uint64_t>(t_[i]) * x.t_[j];
}
}
t_.resize(t_.size() + x.t_.size() + 1);
for (size_t i = 0; i < t.size(); ++i) {
t[i + 1] += t[i] / BASE;
t_[i] = t[i] % BASE;
}
while (t_.size() > 1 && t_.back() == 0) t_.pop_back();
is_negative_ ^= x.is_negative_;
Normalize();
return *this;
}
static constexpr uint16_t BASE = 10000;
std::vector<int16_t> t_ = {0};
bool is_negative_ = false;
};
BigInteger operator-(const BigInteger& a, const BigInteger& b) {
return BigInteger(a) -= b;
}
BigInteger operator*(const BigInteger& a, const BigInteger& b) {
return BigInteger(a) *= b;
}
BigInteger operator/(const BigInteger& a, const BigInteger& b) {
BigInteger tmp(a);
tmp /= b;
return tmp;
}
BigInteger operator%(const BigInteger& a, const BigInteger& b) {
BigInteger tmp(a);
tmp %= b;
return tmp;
}
BigInteger operator+(const BigInteger& a, const BigInteger& b) {
return BigInteger(a) += b;
}
bool operator>(const BigInteger& a, const BigInteger& b) { return b < a; }
bool operator<=(const BigInteger& a, const BigInteger& b) { return !(a > b); }
bool operator>=(const BigInteger& a, const BigInteger& b) { return b <= a; }
bool operator==(const BigInteger& a, const BigInteger& b) {
return !(a < b) && !(b < a);
}
bool operator!=(const BigInteger& a, const BigInteger& b) { return !(a == b); }
class Rational;
Rational operator+(const Rational& a, const Rational& b);
Rational operator-(const Rational& a, const Rational& b);
Rational operator*(const Rational& a, const Rational& b);
Rational operator/(const Rational& a, const Rational& b);
bool operator>(const Rational& a, const Rational& b);
bool operator<=(const Rational& a, const Rational& b);
bool operator>=(const Rational& a, const Rational& b);
bool operator==(const Rational& a, const Rational& b);
bool operator!=(const Rational& a, const Rational& b);
class Rational {
public:
Rational() = default;
Rational(const BigInteger& a) { numerator_ = a; }
Rational(int a) { numerator_ = a; }
Rational(const Rational& x)
: numerator_(x.numerator_), denominator_(x.denominator_) {}
void swap(Rational& x) {
std::swap(numerator_, x.numerator_);
std::swap(denominator_, x.denominator_);
}
Rational& operator=(const Rational& x) {
Rational tmp(x);
swap(tmp);
return *this;
}
Rational& operator+=(const Rational& a) {
if (this == &a) {
return *this += Rational(a);
}
numerator_ *= a.denominator_;
numerator_ += a.numerator_ * denominator_;
denominator_ *= a.denominator_;
Normalize();
return *this;
}
Rational& operator-=(const Rational& a) {
if (this == &a) {
return *this -= Rational(a);
}
numerator_ *= a.denominator_;
numerator_ -= a.numerator_ * denominator_;
denominator_ *= a.denominator_;
Normalize();
return *this;
}
Rational& operator*=(const Rational& a) {
numerator_ *= a.numerator_;
denominator_ *= a.denominator_;
Normalize();
return *this;
}
Rational& operator/=(const Rational& a) {
if (this == &a) {
return *this /= Rational(a);
}
numerator_ *= a.denominator_;
denominator_ *= a.numerator_;
Normalize();
return *this;
}
Rational operator-() const {
Rational tmp(*this);
tmp.numerator_ *= -1;
return tmp;
}
bool operator<(const Rational& a) const {
return numerator_ * a.denominator_ < denominator_ * a.numerator_;
}
std::string toString() const {
std::ostringstream str;
str << numerator_;
if (denominator_ != 1) {
str << "/" << denominator_;
}
return str.str();
}
std::string asDecimal(size_t precision) {
BigInteger t = 1;
for (size_t i = 0; i < precision; ++i) {
t *= 10;
}
std::ostringstream str;
BigInteger result = (numerator_ * t) / denominator_;
if (result < 0) {
str << "-", result *= -1;
}
str << result / t << "." << std::setw(precision) << std::setfill('0')
<< result % t;
return str.str();
}
explicit operator double() { return 1.0; }
BigInteger gcd(const BigInteger& a, const BigInteger& b) {
return b ? gcd(b, a % b) : a;
}
void Normalize() {
if (numerator_ == 0) {
denominator_ = 1;
return;
}
BigInteger d = gcd(numerator_, denominator_);
numerator_ /= d;
denominator_ /= d;
if (denominator_ < 0) {
numerator_ *= -1;
denominator_ *= -1;
}
}
BigInteger numerator_ = 0;
BigInteger denominator_ = 1;
};
Rational operator+(const Rational& a, const Rational& b) {
Rational tmp(a);
tmp += b;
return tmp;
}
Rational operator-(const Rational& a, const Rational& b) {
Rational tmp(a);
tmp -= b;
return tmp;
}
Rational operator*(const Rational& a, const Rational& b) {
Rational tmp(a);
tmp *= b;
return tmp;
}
Rational operator/(const Rational& a, const Rational& b) {
Rational tmp(a);
tmp /= b;
return tmp;
}
bool operator>(const Rational& a, const Rational& b) { return b < a; }
bool operator<=(const Rational& a, const Rational& b) {
return a < b || a == b;
}
bool operator>=(const Rational& a, const Rational& b) {
return a > b || a == b;
}
bool operator==(const Rational& a, const Rational& b) {
return !(b < a) && !(a < b);
}
bool operator!=(const Rational& a, const Rational& b) { return !(a == b); }

35
biginteger/main.cpp Normal file
View file

@ -0,0 +1,35 @@
#include "biginteger.h"
int f() {
for () {
for () {
for () {
for () {
for () {
mk
for () {
for () {
for () {
for () {
}
}
}
}
}
}
}
}
}
}
int main() {
BigInteger a = 10, b = 1;
std::cout << a * b << " " << (a /= a) << std::endl;
}

5
biginteger/makefile Normal file
View file

@ -0,0 +1,5 @@
all: main.cpp
g++ -g -Wall -Wextra -std=c++17 -D LOCAL main.cpp -o a
debug: main.cpp
g++ -g -std=c++17 main.cpp -D LOCAL -o a -Wall -Wextra -pedantic -O2 -Wshadow -Wformat=2 -Wfloat-equal -Wconversion -Wlogical-op -Wshift-overflow=2 -Wduplicated-cond -Wcast-qual -Wcast-align -D_GLIBCXX_DEBUG -D_GLIBCXX_DEBUG_PEDANTIC -D_FORTIFY_SOURCE=2 -fsanitize=address -fsanitize=undefined -fno-sanitize-recover -fstack-protector

633
biginteger/save1.h Normal file
View file

@ -0,0 +1,633 @@
#include <algorithm>
#include <complex>
#include <cstring>
#include <iomanip>
#include <sstream>
#include <vector>
namespace FastFourierTransform {
typedef double ld;
typedef std::complex<ld> cld;
typedef std::vector<cld> ComplexPolynom;
const ld PI = acosl(-1);
std::vector<int16_t> Muliplication(const std::vector<int16_t>& a, const std::vector<int16_t>& b,
std::vector<int16_t>& result);
ComplexPolynom ToComplex(const std::vector<int16_t>& a);
void FastFourierTransform_(ComplexPolynom& a, bool invert);
std::vector<int16_t> Muliplication(const std::vector<int16_t>& a,
const std::vector<int16_t>& b,
std::vector<int16_t>& result) {
ComplexPolynom ca = ToComplex(a);
ComplexPolynom cb = ToComplex(b);
size_t n = std::max(a.size(), b.size());
size_t m = 1;
while (m < n) m <<= 1;
m <<= 1;
ca.resize(m);
cb.resize(m);
FastFourierTransform_(ca, false);
FastFourierTransform_(cb, false);
for (size_t i = 0; i < m; ++i) {
ca[i] *= cb[i];
}
FastFourierTransform_(ca, true);
std::vector<int64_t> v(m);
for (size_t i = 0; i < m; ++i) {
v[i] = ca[i].real() + 0.5;
}
for (size_t i = 0; i < m; ++i) {
v[i + 1] += v[i] / 10000;
v[i] %= 10000;
while (v[i] < 0) v[i] += 10000, v[i + 1] -= 1;
}
result.resize(v.size());
std::copy(v.begin(), v.end(), result.begin());
return result;
}
ComplexPolynom ToComplex(const std::vector<int16_t>& a) {
ComplexPolynom res(a.begin(), a.end());
return res;
}
size_t rev(size_t num, size_t lg_n) {
int res = 0;
for (size_t i = 0; i < lg_n; ++i)
if (num & (1 << i)) res |= 1 << (lg_n - 1 - i);
return res;
}
void FastFourierTransform_(ComplexPolynom& a, bool invert) {
size_t n = a.size();
size_t lg_n = 0;
while ((1u << lg_n) < n) ++lg_n;
for (size_t i = 0; i < n; ++i)
if (i < rev(i, lg_n)) swap(a[i], a[rev(i, lg_n)]);
for (size_t len = 2; len <= n; len <<= 1) {
double ang = 2 * PI / len * (invert ? -1 : 1);
cld wlen(cos(ang), sin(ang));
for (size_t i = 0; i < n; i += len) {
cld w(1);
for (size_t j = 0; j < len / 2; ++j) {
cld u = a[i + j], v = a[i + j + len / 2] * w;
a[i + j] = u + v;
a[i + j + len / 2] = u - v;
w *= wlen;
}
}
}
if (invert)
for (size_t i = 0; i < n; ++i) a[i] /= n;
}
};
class BigInteger;
BigInteger operator-(const BigInteger& a, const BigInteger& b);
BigInteger operator*(const BigInteger& a, const BigInteger& b);
BigInteger operator/(const BigInteger& a, const BigInteger& b);
BigInteger operator+(const BigInteger& a, const BigInteger& b);
bool operator>(const BigInteger& a, const BigInteger& b);
bool operator<=(const BigInteger& a, const BigInteger& b);
bool operator>=(const BigInteger& a, const BigInteger& b);
bool operator==(const BigInteger& a, const BigInteger& b);
bool operator!=(const BigInteger& a, const BigInteger& b);
BigInteger operator%(const BigInteger& a, const BigInteger& b);
class BigInteger {
public:
BigInteger() {}
BigInteger(int64_t x) {
if (x < 0) {
is_negative_ = true, x *= -1;
}
t_[0] = x % BASE;
x /= BASE;
while (x > 0) {
t_.push_back(x % BASE);
x /= BASE;
}
Normalize();
}
BigInteger(const BigInteger& x) : t_(x.t_), is_negative_(x.is_negative_) {}
void swap(BigInteger& x) {
std::swap(t_, x.t_);
std::swap(is_negative_, x.is_negative_);
}
BigInteger& operator=(const BigInteger& x) {
BigInteger tmp = x;
swap(tmp);
return *this;
}
friend bool operator<(const BigInteger&a, const BigInteger& b) {
if (a.is_negative_ ^ b.is_negative_) {
return a.is_negative_;
}
if (a.t_.size() != b.t_.size()) {
return (a.t_.size() < b.t_.size()) ^ a.is_negative_;
}
for (size_t i = a.t_.size(); i > 0; --i) {
if (a.t_[i - 1] != b.t_[i - 1]) {
return (a.t_[i - 1] < b.t_[i - 1]) ^ a.is_negative_;
}
}
return a.is_negative_;
}
BigInteger& operator++() {
*this += 1;
Normalize();
return *this;
}
BigInteger operator++(int) {
BigInteger tmp = *this;
++(*this);
return tmp;
}
void addingDifferentSigns(const BigInteger& x) {
int16_t carry[2] = {0, 0};
// Вычитаем, если *this < x, то последнее число будет отрицательным и
// потом это пофиксим
for (size_t i = 0; i < x.t_.size() || (carry[i & 1] && i < t_.size());
++i) {
if (i < x.t_.size()) {
t_[i] -= x.t_[i];
}
t_[i] += carry[i & 1];
if (t_[i] < 0 && i + 1 < t_.size()) {
t_[i] += BASE;
carry[(i & 1) ^ 1] = -1;
} else {
carry[(i & 1) ^ 1] = 0;
}
}
// Убераем нули в начале и начинаем фиксить отрицательное число
Normalize();
if (t_.back() < 0) {
t_.pop_back();
for (size_t i = 0; i < t_.size(); ++i) {
t_[i] = BASE - 1 - t_[i];
}
++t_[0];
while (t_.size() > 1 && t_.back() == 0) {
t_.pop_back();
}
is_negative_ ^= true;
}
// Когда мы пофиксили отрицательные числа, у нас в ячейках могли
// образоваться числа >= BASE, фиксим это
carry[0] = 0;
carry[1] = 0;
if (t_[0] >= BASE) {
carry[1] = 1;
t_[0] -= BASE;
}
for (size_t i = 1; i < t_.size() && carry[i & 1]; ++i) {
t_[i] += carry[i & 1];
carry[i & 1] = 0;
if (t_[i] >= BASE) {
carry[(i & 1) ^ 1] = 1;
t_[i] -= BASE;
}
}
// У нас может произойти перенос в ячейку, которой не существует, добавим
// ее)
if (carry[t_.size() & 1]) {
t_.push_back(1);
}
}
BigInteger& operator+=(const BigInteger& x) {
t_.resize(std::max(t_.size(), x.t_.size()) + 1);
// Если числа одинаковых знаков - просто сложение
if (!is_negative_ ^ x.is_negative_) {
int16_t carry[2] = {0, 0};
for (size_t i = 0; i < x.t_.size() || carry[i & 1]; ++i) {
if (i < x.t_.size()) {
t_[i] += x.t_[i];
}
t_[i] += carry[i & 1];
if (t_[i] >= BASE) {
t_[i] -= BASE;
carry[(i & 1) ^ 1] = 1;
} else {
carry[(i & 1) ^ 1] = 0;
}
}
Normalize();
} else {
addingDifferentSigns(x);
}
return *this;
}
BigInteger& operator-=(const BigInteger& x) {
// a - b = -(-a + b)
is_negative_ ^= 1;
*this += x;
is_negative_ ^= 1;
Normalize();
return *this;
}
BigInteger& operator*=(int16_t x) {
// Это умножение на маленькое число, работает за O(n) и используется в
// делении
if (x < 0) {
is_negative_ = !is_negative_;
x *= -1;
}
if (x >= BASE) {
return *this *= BigInteger(x);
}
t_.resize(t_.size() + 3);
int16_t carry[2] = {0, 0};
for (size_t i = 0; i < t_.size(); ++i) {
carry[!(i & 1)] = (int(t_[i]) * x + carry[i & 1]) / BASE;
t_[i] = (int(t_[i]) * x + carry[i & 1]) % BASE;
}
while (t_.size() > 1 && t_.back() == 0) t_.pop_back();
Normalize();
return *this;
}
BigInteger& operator*=(const BigInteger& x) {
// Если число на которое нам надо умножить небольшое, выгоднее умножать за
// квадрат
if (x.t_.size() < 100) {
return SquareMultiplication(x);
}
FastFourierTransform::Muliplication(t_, x.t_, t_);
is_negative_ ^= x.is_negative_;
Normalize();
return *this;
}
// Деление работает за O(N^2), мы вычисляем все значащие биты в делении,
// которых O(n), с помощью бинпоиска(константа, так как log 10000), и
// проверкой в бинпоиске за O(n), потому что используется умножение за O(n), и
// в итоге O(N^2)
BigInteger& operator/=(const BigInteger& x) {
bool is_negative = is_negative_ ^ x.is_negative_;
is_negative_ = false;
std::vector<int16_t> res(t_.size() - std::min(x.t_.size(), t_.size()) + 4);
int16_t d = 1;
if (x < 0) {
d = -1;
}
for (int i = res.size(); i > 0; --i) {
int l = 0, r = BASE - 1, m;
while (l != r) {
m = (l + r + 1) / 2;
if ((x * d * m).MuliplicationDegree10(i - 1) <= *this) {
l = m;
} else {
r = m - 1;
}
}
res[i - 1] = l;
*this -= (x * d * res[i - 1]).MuliplicationDegree10(i - 1);
}
t_ = res;
is_negative_ = is_negative;
Normalize();
return *this;
}
BigInteger& operator%=(const BigInteger& x) {
*this -= (*this / x) * x;
Normalize();
return *this;
}
std::string toString() const {
std::ostringstream string;
if (is_negative_) {
string << "-";
}
string << t_.back();
for (auto it = ++t_.rbegin(); it != t_.rend(); ++it) {
string << std::setw(4) << std::setfill('0') << *it;
}
return string.str();
}
explicit operator bool() const { return t_.size() > 1 || t_[0]; }
friend std::istream& operator>>(std::istream& in, BigInteger& x) {
std::string s;
in >> s;
std::reverse(s.begin(), s.end());
if (s.back() == '-') {
x.is_negative_ = true;
s.pop_back();
} else {
x.is_negative_ = false;
}
while (s.size() % 4) {
s.push_back('0');
}
x.t_.resize(s.size() / 4);
for (size_t i = 0; i < s.size(); i += 4) {
x.t_[i / 4] = s[i] - '0' + 10 * (s[i + 1] - '0') +
100 * (s[i + 2] - '0') + 1000 * (s[i + 3] - '0');
}
x.Normalize();
return in;
}
friend std::ostream& operator<<(std::ostream& out, const BigInteger& x) {
out << x.toString();
return out;
}
BigInteger operator-() {
BigInteger tmp(*this);
tmp.is_negative_ ^= true;
tmp.Normalize();
return tmp;
}
private:
void Normalize() {
while (t_.size() > 1 && t_.back() == 0) {
t_.pop_back();
}
if (t_.size() == 1 && t_[0] == 0) {
is_negative_ = false;
}
}
// Это умножение на 10^degree
BigInteger& MuliplicationDegree10(int degree) {
size_t n = t_.size();
t_.resize(t_.size() + degree);
std::rotate(t_.begin(), t_.begin() + n, t_.end());
Normalize();
return *this;
}
// Это используется, если число на которое мы умножаем не очень большое, потому что
// FFT работает достаточно медленно
BigInteger& SquareMultiplication(const BigInteger& x) {
std::vector<uint64_t> t(t_.size() + x.t_.size() + 1);
for (size_t i = 0; i < t_.size(); ++i) {
for (size_t j = 0; j < x.t_.size(); ++j) {
t[i + j] += static_cast<uint64_t>(t_[i]) * x.t_[j];
}
}
t_.resize(t_.size() + x.t_.size() + 1);
for (size_t i = 0; i < t.size(); ++i) {
t[i + 1] += t[i] / BASE;
t_[i] = t[i] % BASE;
}
while (t_.size() > 1 && t_.back() == 0) t_.pop_back();
is_negative_ ^= x.is_negative_;
Normalize();
return *this;
}
static constexpr uint16_t BASE = 10000;
std::vector<int16_t> t_ = {0};
bool is_negative_ = false;
};
BigInteger operator-(const BigInteger& a, const BigInteger& b) {
return BigInteger(a) -= b;
}
BigInteger operator*(const BigInteger& a, const BigInteger& b) {
return BigInteger(a) *= b;
}
BigInteger operator/(const BigInteger& a, const BigInteger& b) {
BigInteger tmp(a);
tmp /= b;
return tmp;
}
BigInteger operator%(const BigInteger& a, const BigInteger& b) {
BigInteger tmp(a);
tmp %= b;
return tmp;
}
BigInteger operator+(const BigInteger& a, const BigInteger& b) {
return BigInteger(a) += b;
}
bool operator>(const BigInteger& a, const BigInteger& b) { return b < a; }
bool operator<=(const BigInteger& a, const BigInteger& b) { return !(a > b); }
bool operator>=(const BigInteger& a, const BigInteger& b) { return b <= a; }
bool operator==(const BigInteger& a, const BigInteger& b) {
return !(a < b) && !(b < a);
}
bool operator!=(const BigInteger& a, const BigInteger& b) { return !(a == b); }
class Rational;
Rational operator+(const Rational& a, const Rational& b);
Rational operator-(const Rational& a, const Rational& b);
Rational operator*(const Rational& a, const Rational& b);
Rational operator/(const Rational& a, const Rational& b);
bool operator>(const Rational& a, const Rational& b);
bool operator<=(const Rational& a, const Rational& b);
bool operator>=(const Rational& a, const Rational& b);
bool operator==(const Rational& a, const Rational& b);
bool operator!=(const Rational& a, const Rational& b);
class Rational {
public:
Rational() = default;
Rational(const BigInteger& a) { numerator_ = a; }
Rational(int a) { numerator_ = a; }
Rational(const Rational& x)
: numerator_(x.numerator_), denominator_(x.denominator_) {}
void swap(Rational& x) {
std::swap(numerator_, x.numerator_);
std::swap(denominator_, x.denominator_);
}
Rational& operator=(const Rational& x) {
Rational tmp(x);
swap(tmp);
return *this;
}
Rational& operator+=(const Rational& a) {
if (this == &a) {
return *this += Rational(a);
}
numerator_ *= a.denominator_;
numerator_ += a.numerator_ * denominator_;
denominator_ *= a.denominator_;
Normalize();
return *this;
}
Rational& operator-=(const Rational& a) {
if (this == &a) {
return *this -= Rational(a);
}
numerator_ *= a.denominator_;
numerator_ -= a.numerator_ * denominator_;
denominator_ *= a.denominator_;
Normalize();
return *this;
}
Rational& operator*=(const Rational& a) {
numerator_ *= a.numerator_;
denominator_ *= a.denominator_;
Normalize();
return *this;
}
Rational& operator/=(const Rational& a) {
if (this == &a) {
return *this /= Rational(a);
}
numerator_ *= a.denominator_;
denominator_ *= a.numerator_;
Normalize();
return *this;
}
Rational operator-() const {
Rational tmp(*this);
tmp.numerator_ *= -1;
return tmp;
}
bool operator<(const Rational& a) const {
return numerator_ * a.denominator_ < denominator_ * a.numerator_;
}
std::string toString() const {
std::ostringstream str;
str << numerator_;
if (denominator_ != 1) {
str << "/" << denominator_;
}
return str.str();
}
std::string asDecimal(size_t precision) {
BigInteger t = 1;
for (size_t i = 0; i < precision; ++i) {
t *= 10;
}
std::ostringstream str;
BigInteger result = (numerator_ * t) / denominator_;
if (result < 0) {
str << "-", result *= -1;
}
str << result / t << "." << std::setw(precision) << std::setfill('0')
<< result % t;
return str.str();
}
explicit operator double() { return 1.0; }
BigInteger gcd(const BigInteger& a, const BigInteger& b) {
return b ? gcd(b, a % b) : a;
}
void Normalize() {
if (numerator_ == 0) {
denominator_ = 1;
return;
}
BigInteger d = gcd(numerator_, denominator_);
numerator_ /= d;
denominator_ /= d;
if (denominator_ < 0) {
numerator_ *= -1;
denominator_ *= -1;
}
}
BigInteger numerator_ = 0;
BigInteger denominator_ = 1;
};
Rational operator+(const Rational& a, const Rational& b) {
Rational tmp(a);
tmp += b;
return tmp;
}
Rational operator-(const Rational& a, const Rational& b) {
Rational tmp(a);
tmp -= b;
return tmp;
}
Rational operator*(const Rational& a, const Rational& b) {
Rational tmp(a);
tmp *= b;
return tmp;
}
Rational operator/(const Rational& a, const Rational& b) {
Rational tmp(a);
tmp /= b;
return tmp;
}
bool operator>(const Rational& a, const Rational& b) { return b < a; }
bool operator<=(const Rational& a, const Rational& b) { return a < b || a == b; }
bool operator>=(const Rational& a, const Rational& b) { return a > b || a == b; }
bool operator==(const Rational& a, const Rational& b) {
return !(b < a) && !(a < b);
}
bool operator!=(const Rational& a, const Rational& b) { return !(a == b); }

21
biginteger/test.py Normal file
View file

@ -0,0 +1,21 @@
f = open("input.txt", "r")
x = f.read()
for i in x.split('\n'):
t = i.split()
if (len(t) < 3):
break
if (t[0] == '+'):
print(int(t[1]) + int(t[2]))
elif (t[0] == '-'):
print(int(t[1]) - int(t[2]))
elif (t[0] == '%'):
print(int(t[1]) % int(t[2]))
elif (t[0] == '*'):
print(int(t[1]) * int(t[2]))
elif (t[0] == '/'):
x = int(t[1]) // int(t[2])
if (x < 0):
if (int(t[1]) % int(t[2]) != 0):
x += 1
print(x)

32
deque/main.cpp Normal file
View file

@ -0,0 +1,32 @@
#include "deque.h"
#include <iostream>
using namespace std;
int main() {
Deque<int> a;
a.push_back(243);
a.push_back(34);
a.push_back(45);
a.push_back(456);
a.push_front(3240);
cout << endl;
cout << endl;
for (int i = 0; i < a.size(); ++i) {
cout << a[i] << " ";
}
cout << endl << endl;
auto it = a.begin();
it += 3;
a.erase(a.end());
cout << endl;
cout << endl;
for (int i = 0; i < a.size(); ++i) {
cout << a[i] << " ";
}
}

5
deque/makefile Normal file
View file

@ -0,0 +1,5 @@
all: main.cpp
g++ -g -Wall -Wextra -std=c++17 -D LOCAL main.cpp -o a
debug: main.cpp
g++ -g -std=c++17 main.cpp -D LOCAL -o a -Wall -Wextra -pedantic -O2 -Wshadow -Wformat=2 -Wfloat-equal -Wconversion -Wlogical-op -Wshift-overflow=2 -Wduplicated-cond -Wcast-qual -Wcast-align -D_GLIBCXX_DEBUG -D_GLIBCXX_DEBUG_PEDANTIC -D_FORTIFY_SOURCE=2 -fsanitize=address -fsanitize=undefined -fno-sanitize-recover -fstack-protector

14
geometry/main.cpp Normal file
View file

@ -0,0 +1,14 @@
#include <bits/stdc++.h>
#include "geometry.h"
using namespace std;
mt19937 rnd(chrono::steady_clock::now().time_since_epoch().count());
int main() {
Polygon p(Point(0, 0), Point(0, 1), Point(1, 2), Point(2, 0));
Polygon q(Point(0, 0), Point(2, 0), Point(1, 2), Point(0, 1));
cout << p.isCongruentTo(q) << endl;
return 0;
}

2
geometry/makefile Normal file
View file

@ -0,0 +1,2 @@
all:
g++ main.cpp -DLOCAL -Wextra -Wall -o a

9
list/CMakeLists.txt Normal file
View file

@ -0,0 +1,9 @@
cmake_minimum_required(VERSION 3.10)
project("List")
set(SOURCE_FILES main.cpp fastallocator.h)
set(CMAKE_CXX_STANDARD 17)
add_executable(list ${SOURCE_FILES})

308
list/fastallocator.h Normal file
View file

@ -0,0 +1,308 @@
#include <memory>
#include <vector>
#include <iterator>
template<size_t chunkSize>
class FixedAllocator {
private:
static const int count_chunks = 16;
static inline std::vector<void*> free;
public:
[[nodiscard]] static void* allocate() {
if (free.empty()) {
char* tmp = new char[chunkSize * count_chunks];
for (int i = 0; i < count_chunks; ++i) free.push_back(reinterpret_cast<void*>(tmp + i * chunkSize));
}
void* tmp = free.back();
free.pop_back();
return tmp;
}
static void deallocate(void* p) {
free.push_back(p);
}
};
template<typename T>
class FastAllocator {
public:
using value_type = T;
FastAllocator() = default;
template<typename U>
FastAllocator(const FastAllocator<U>&) {}
template<typename U>
FastAllocator& operator=(const FastAllocator<U>&) const { return *this; }
[[nodiscard]] T* allocate(size_t n) {
if (n * sizeof(T) > kSizeBigBlock)
return reinterpret_cast<T*>(new char[n * sizeof(T)]);
else {
return reinterpret_cast<T*>(allocate_template_for<sizeof(T), kSizeBigBlock>(sizeof(T) * n));
}
}
void deallocate(T* p, size_t n) {
if (n * sizeof(T) > 48)
delete[] reinterpret_cast<char*>(p);
else
deallocate_template_for<sizeof(T), kSizeBigBlock>(p, n * sizeof(T));
}
private:
static const size_t kSizeBigBlock = 48;
template<size_t x = 1, size_t end = kSizeBigBlock>
[[nodiscard]] void* allocate_template_for(size_t n) {
if (x == n) {
return FixedAllocator<x>::allocate();
} else {
if constexpr (x < end) {
return allocate_template_for<x + 1, end>(n);
}
}
return nullptr;
}
template<size_t x = 1, size_t end = kSizeBigBlock>
void deallocate_template_for(void* ptr, size_t n) {
if (x == n) {
FixedAllocator<x>::deallocate(ptr);
} else {
if constexpr (x < end) {
deallocate_template_for<x + 1, end>(ptr, n);
}
}
}
};
template<class T, class U>
bool operator==(const FastAllocator<T>& a, const FastAllocator<U>& b) {
return &a == &b;
}
template<class T, class U>
bool operator!=(const FastAllocator<T>& a, const FastAllocator<U>& b) {
return !(a == b);
}
template<typename T, typename Allocator=std::allocator<T>>
class List {
private:
class Node;
template<bool is_const>
class base_iterator;
public:
using iterator = base_iterator<false>;
using const_iterator = base_iterator<true>;
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
explicit List(const Allocator& alloc = Allocator()) : alloc_(alloc) {
AllocateEndNode();
}
List(size_t count, const T& value, const Allocator& alloc = Allocator()) : alloc_(alloc) {
AllocateEndNode();
for (size_t i = 0; i < count; ++i) {
Node* tmp = alloc_.allocate(1);
alloc_traits_::construct(alloc_, tmp, value);
Link(end_->l, tmp);
}
size_ = count;
}
List(size_t count, const Allocator& alloc = Allocator()) : alloc_(alloc) {
AllocateEndNode();
for (size_t i = 0; i < count; ++i) {
Node* tmp = alloc_.allocate(1);
alloc_traits_::construct(alloc_, tmp);
Link(end_->l, tmp);
}
size_ = count;
}
List(const List& another) {
alloc_ = alloc_traits_::select_on_container_copy_construction(another.alloc_);
AllocateEndNode();
for (const T& i: another) {
Node* tmp = alloc_.allocate(1);
alloc_traits_::construct(alloc_, tmp, i);
Link(end_->l, tmp);
}
size_ = another.size();
}
List& operator=(const List& another) {
if (this == &another) return *this;
if (alloc_traits_::propagate_on_container_copy_assignment::value && alloc_ != another.alloc_) {
alloc_ = another.alloc_;
}
auto it1 = begin();
auto it2 = another.begin();
for (size_t i = 0; i < std::min(another.size(), size()); ++i) {
*it1 = *it2;
++it1;
++it2;
}
if (another.size() > size()) {
while (size() != another.size()) {
push_back(*it2);
++it2;
}
} else {
while (size() != another.size()) {
pop_back();
}
}
return *this;
}
~List() {
while (end_ != end_->r) {
erase(iterator(end_->r));
}
alloc_.deallocate(end_, 1);
}
Allocator get_allocator() {
return alloc_;
}
void push_back(const T& value) {
insert(end(), value);
}
void push_front(const T& value) {
insert(begin(), value);
}
void pop_back() {
erase(std::prev(end()));
}
void pop_front() {
erase(begin());
}
size_t size() const { return size_; }
iterator begin() { return iterator(end_->r); }
iterator end() { return iterator(end_); }
const_iterator begin() const { return const_iterator(end_->r); }
const_iterator end() const { return const_iterator(end_); }
const_iterator cbegin() const { return const_iterator(end_->r); }
const_iterator cend() const { return const_iterator(end_); }
reverse_iterator rbegin() { return reverse_iterator(end()); }
reverse_iterator rend() { return reverse_iterator(begin()); }
const_reverse_iterator rbegin() const { return const_reverse_iterator(cend()); }
const_reverse_iterator rend() const { return const_reverse_iterator(cbegin()); }
const_reverse_iterator crbegin() const { return const_reverse_iterator(cend()); }
const_reverse_iterator crend() const { return const_reverse_iterator(cbegin()); }
void insert(const_iterator it, const T& value) {
Node* tmp = alloc_.allocate(1);
std::allocator_traits<decltype(alloc_)>::construct(alloc_, tmp, value);
Link(const_cast<Node*>(std::prev(it).it), tmp);
++size_;
}
void erase(const_iterator it) {
Node* tmp = const_cast<Node*>(it.it);
tmp->l->r = tmp->r;
tmp->r->l = tmp->l;
std::allocator_traits<decltype(alloc_)>::destroy(alloc_, tmp);
alloc_.deallocate(tmp, 1);
--size_;
}
private:
void AllocateEndNode() {
end_ = alloc_.allocate(1);
end_->l = end_;
end_->r = end_;
}
void Link(Node* l, Node* x) {
Node* r = l->r;
x->l = l;
x->r = r;
l->r = x;
r->l = x;
}
template<bool is_const>
class base_iterator {
friend List;
std::conditional_t<is_const, const Node*, Node*> it;
using U = std::conditional_t<is_const, const T, T>;
public:
using iterator_category = std::bidirectional_iterator_tag;
using value_type = U;
using pointer = U*;
using reference = U&;
using difference_type = int;
base_iterator() : it(nullptr) {}
base_iterator(Node* v) { it = v; }
base_iterator(const base_iterator&) = default;
operator base_iterator<true>() { return base_iterator<true>(it); }
U& operator*() const { return it->value; }
U* operator->() const { return &it->value; }
base_iterator& operator++()& {
it = it->r;
return *this;
}
base_iterator operator++(int)& {
base_iterator tmp = *this;
it = it->r;
return tmp;
}
base_iterator& operator--()& {
it = it->l;
return *this;
}
base_iterator operator--(int)& {
base_iterator tmp = *this;
it = it->l;
return tmp;
}
friend bool operator==(base_iterator first, base_iterator second) { return first.it == second.it; }
friend bool operator!=(base_iterator first, base_iterator second) { return !(first == second); }
base_iterator& operator=(const base_iterator<false>& another) {
it = another.it;
return *this;
}
};
struct Node {
Node* l = nullptr;
Node* r = nullptr;
T value;
Node() = default;
Node(const T& value) : value(value) {}
Node& operator=(const Node& another) { value = another.value; }
};
typename std::allocator_traits<Allocator>::template rebind_alloc<Node> alloc_;
using alloc_traits_ = std::allocator_traits<decltype(alloc_)>;
Node* end_ = nullptr;
size_t size_ = 0;
};

136
list/main.cpp Normal file
View file

@ -0,0 +1,136 @@
#include <bits/stdc++.h>
#include "fastallocator.h"
using namespace std;
template<size_t number>
struct C1 {
static inline vector<int> v = {0, 0, 0, 0, 0};
C1() {
v[0]++;
}
C1(int) {
v[1]++;
}
C1(const C1&) {
v[2]++;
}
C1& operator=(const C1&) {
v[3]++;
return *this;
}
~C1() {
v[4]++;
}
static void print() {
for (int i: v) {
cout << i << " ";
}
cout << endl;
}
};
void test1() {
{
const int N = 10000;
List<C1<0>> l(N);
list<C1<1>> t(N);
assert(C1<0>::v == C1<1>::v);
List<C1<0>> ll(N, C1<0>(10));
list<C1<1>> tt(N, C1<1>(10));
assert(C1<0>::v == C1<1>::v);
for (size_t i = 0; i < N; ++i) {
l.push_back(C1<0>());
t.push_back(C1<1>());
l.push_front(C1<0>());
t.push_front(C1<1>());
}
assert(C1<0>::v == C1<1>::v);
for (size_t i = 0; i < N; ++i) {
l.insert(l.begin(), C1<0>());
t.insert(t.begin(), C1<1>());
l.insert(next(l.begin()), C1<0>(10));
t.insert(next(t.begin()), C1<1>(10));
l.insert(prev(l.end()), C1<0>());
t.insert(prev(t.end()), C1<1>());
}
assert(C1<0>::v == C1<1>::v);
for (size_t i = 0; i < N / 4; ++i) {
l.pop_back();
t.pop_back();
}
assert(C1<0>::v == C1<1>::v);
for (size_t i = 0; i < N / 8; ++i) {
l.erase(l.begin());
t.erase(t.begin());
}
assert(C1<0>::v == C1<1>::v);
for (size_t i = 0; i < N / 8; ++i) {
l.erase(prev(l.end()));
t.erase(prev(t.end()));
}
assert(C1<0>::v == C1<1>::v);
for (size_t i = 0; i < N / 8; ++i) {
auto a = C1<0>();
l.push_back(a);
auto b = C1<1>();
t.push_back(b);
}
assert(C1<0>::v == C1<1>::v);
for (size_t i = 0; i < N / 8; ++i) {
(*next(l.begin())) = C1<0>();
(*next(t.begin())) = C1<1>();
}
assert(C1<0>::v == C1<1>::v);
C1<0>::print();
C1<1>::print();
List<C1<0>> lll = l;
list<C1<1>> ttt = t;
for (int i = 0; i < 10; ++i) {
l.push_back(10);
t.push_back(10);
}
assert(C1<0>::v == C1<1>::v);
C1<0>::print();
C1<1>::print();
lll = l;
ttt = t;
C1<0>::print();
C1<1>::print();
assert(C1<0>::v == C1<1>::v);
}
assert(C1<0>::v == C1<1>::v);
std::cout << "TEST 1 PASSED" << endl;
}
int main() {
test1();
std::list<char, FastAllocator<char>> x;
x.push_back(10);
}

11
map/CMakeLists.txt Normal file
View file

@ -0,0 +1,11 @@
cmake_minimum_required(VERSION 3.10)
project("List")
set(SOURCE_FILES main.cpp)
set(CMAKE_CXX_COMPILER clang++)
set(CMAKE_CXX_STANDARD 17)
add_executable(map ${SOURCE_FILES})

302
map/fastallocator.h Normal file
View file

@ -0,0 +1,302 @@
#include <memory>
#include <vector>
#include <iterator>
template<size_t chunkSize>
class FixedAllocator {
private:
static const int count_chunks = 16;
static inline std::vector<void*> free;
public:
[[nodiscard]] static void* allocate() {
if (free.empty()) {
char* tmp = static_cast<char*>(malloc(chunkSize * count_chunks));
for (int i = 0; i < count_chunks; ++i) free.push_back(reinterpret_cast<void*>(tmp + i * chunkSize));
}
void* tmp = free.back();
free.pop_back();
return tmp;
}
static void deallocate(void* p) noexcept {
free.push_back(p);
}
};
template<size_t x, size_t end>
[[nodiscard]] void* genius_allocate_fixed_allocator(size_t n) {
if (x == n) {
return FixedAllocator<x>::allocate();
} else {
if constexpr (x < end) {
return genius_allocate_fixed_allocator<x + 1, end>(n);
}
}
return nullptr;
}
template<typename T>
class FastAllocator {
public:
using value_type = T;
FastAllocator() = default;
template<typename U>
FastAllocator(const FastAllocator<U>&) {}
template<typename U>
FastAllocator& operator=(const FastAllocator<U>&) const { return *this; }
[[nodiscard]] T* allocate(size_t n) {
if (n * sizeof(T) > big_block_ || n > 1)
return static_cast<T*>(std::malloc(n * sizeof(T)));
else {
return static_cast<T*>(genius_allocate_fixed_allocator<sizeof(T), big_block_>(sizeof(T) * n));
// return static_cast<T*>(FixedAllocator<sizeof(T)>().allocate());
}
}
void deallocate(T* p, size_t n) noexcept {
if (n * sizeof(T) > 48 || n > 1)
free(p);
else
return FixedAllocator<sizeof(T)>().deallocate(p);
}
private:
static const size_t big_block_ = 48;
};
template<class T, class U>
bool operator==(const FastAllocator<T>& a, const FastAllocator<U>& b) {
return &a == &b;
}
template<class T, class U>
bool operator!=(const FastAllocator<T>& a, const FastAllocator<U>& b) {
return &a != &b;
}
template<typename T, typename Allocator=std::allocator<T>>
class List {
private:
class Node;
template<bool is_const>
class base_iterator;
public:
using iterator = base_iterator<false>;
using const_iterator = base_iterator<true>;
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
explicit List(const Allocator& alloc = Allocator()) : alloc_(alloc) {
AllocateEnd();
}
List(size_t count, const T& value, const Allocator& alloc = Allocator()) : alloc_(alloc) {
AllocateEnd();
for (size_t i = 0; i < count; ++i) {
Node* tmp = alloc_.allocate(1);
alloc_traits_::construct(alloc_, tmp, value);
Link(end_->l, tmp);
}
size_ = count;
}
List(size_t count, const Allocator& alloc = Allocator()) : alloc_(alloc) {
AllocateEnd();
for (size_t i = 0; i < count; ++i) {
Node* tmp = alloc_.allocate(1);
alloc_traits_::construct(alloc_, tmp);
Link(end_->l, tmp);
}
size_ = count;
}
List(const List& another) {
alloc_ = alloc_traits_::select_on_container_copy_construction(another.alloc_);
AllocateEnd();
for (const T& i: another) {
Node* tmp = alloc_.allocate(1);
alloc_traits_::construct(alloc_, tmp, i);
Link(end_->l, tmp);
}
size_ = another.size();
}
List(List&&) = default;
List& operator=(const List& another) {
if (this == &another) return *this;
if (alloc_traits_::propagate_on_container_copy_assignment::value && alloc_ != another.alloc_) {
alloc_ = another.alloc_;
}
auto it1 = begin();
auto it2 = another.begin();
for (size_t i = 0; i < std::min(another.size(), size()); ++i) {
*it1 = *it2;
++it1;
++it2;
}
if (another.size() > size()) {
while (size() != another.size()) {
push_back(*it2);
++it2;
}
} else {
while (size() != another.size()) {
pop_back();
}
}
return *this;
}
List& operator= (List&&) = default;
~List() {
while (end_ != end_->r) {
erase(iterator(end_->r));
}
alloc_.deallocate(end_, 1);
}
Allocator get_allocator() {
return alloc_;
}
void push_back(const T& value) {
insert(end(), value);
}
void push_front(const T& value) {
insert(begin(), value);
}
void pop_back() {
erase(std::prev(end()));
}
void pop_front() {
erase(begin());
}
size_t size() const { return size_; }
iterator begin() { return iterator(end_->r); }
iterator end() { return iterator(end_); }
const_iterator begin() const { return const_iterator(end_->r); }
const_iterator end() const { return const_iterator(end_); }
const_iterator cbegin() const { return const_iterator(end_->r); }
const_iterator cend() const { return const_iterator(end_); }
reverse_iterator rbegin() { return reverse_iterator(end()); }
reverse_iterator rend() { return reverse_iterator(begin()); }
const_reverse_iterator rbegin() const { return const_reverse_iterator(cend()); }
const_reverse_iterator rend() const { return const_reverse_iterator(cbegin()); }
const_reverse_iterator crbegin() const { return const_reverse_iterator(cend()); }
const_reverse_iterator crend() const { return const_reverse_iterator(cbegin()); }
void insert(const_iterator it, const T& value) {
Node* tmp = alloc_.allocate(1);
std::allocator_traits<decltype(alloc_)>::construct(alloc_, tmp, value);
Link(const_cast<Node*>(std::prev(it).it), tmp);
++size_;
}
void erase(const_iterator it) {
Node* tmp = const_cast<Node*>(it.it);
tmp->l->r = tmp->r;
tmp->r->l = tmp->l;
std::allocator_traits<decltype(alloc_)>::destroy(alloc_, tmp);
alloc_.deallocate(tmp, 1);
--size_;
}
private:
void AllocateEnd() {
end_ = alloc_.allocate(1);
end_->l = end_;
end_->r = end_;
}
void Link(Node* l, Node* x) {
Node* r = l->r;
x->l = l;
x->r = r;
l->r = x;
r->l = x;
}
template<bool is_const>
class base_iterator {
friend List;
std::conditional_t<is_const, const Node*, Node*> it;
using U = std::conditional_t<is_const, const T, T>;
public:
using iterator_category = std::bidirectional_iterator_tag;
using value_type = U;
using pointer = U*;
using reference = U&;
using difference_type = int;
base_iterator() : it(nullptr) {}
base_iterator(Node* v) { it = v; }
base_iterator(const base_iterator&) = default;
operator base_iterator<true>() { return base_iterator<true>(it); }
U& operator*() const { return it->value; }
U* operator->() const { return &it->value; }
base_iterator& operator++()& {
it = it->r;
return *this;
}
base_iterator operator++(int)& {
base_iterator tmp = *this;
it = it->r;
return tmp;
}
base_iterator& operator--()& {
it = it->l;
return *this;
}
base_iterator operator--(int)& {
base_iterator tmp = *this;
it = it->l;
return tmp;
}
friend bool operator==(base_iterator first, base_iterator second) { return first.it == second.it; }
friend bool operator!=(base_iterator first, base_iterator second) { return first.it != second.it; }
base_iterator& operator=(const base_iterator<false>& another) {
it = another.it;
return *this;
}
};
struct Node {
Node* l = nullptr;
Node* r = nullptr;
T value;
Node() = default;
Node(const T& value) : value(value) {}
Node& operator=(const Node& another) { value = another.value; }
};
typename std::allocator_traits<Allocator>::template rebind_alloc<Node> alloc_;
using alloc_traits_ = std::allocator_traits<decltype(alloc_)>;
Node* end_ = nullptr;
size_t size_ = 0;
};

385
map/main.cpp Normal file
View file

@ -0,0 +1,385 @@
#include <vector>
#include <string>
#include <unordered_map>
#include <iterator>
#include <cassert>
#include "unordered_map.h"
template<typename Key, typename Value, typename Hash = std::hash<Key>, typename Equal = std::equal_to<Key>, typename Alloc = std::allocator<std::pair<Key, Value>>>
using unordered_map = UnorderedMap<Key, Value, Hash, Equal, Alloc>;
//
//using std::unordered_map;
void SimpleTest() {
unordered_map<std::string, int> m;
m["aaaaa"] = 5;
m["bbb"] = 6;
m.at("bbb") = 7;
assert(m.size() == 2);
std::cout << m["aaaaa"] << std::endl;
assert(m["aaaaa"] == 5);
assert(m["bbb"] == 7);
assert(m["ccc"] == 0);
assert(m.size() == 3);
try {
m.at("xxxxxxxx");
assert(false);
} catch (...) {
}
auto it = m.find("dddd");
assert(it == m.end());
it = m.find("bbb");
assert(it->second == 7);
++it->second;
assert(it->second == 8);
for (auto& item : m) {
--item.second;
}
assert(m.at("aaaaa") == 4);
{
auto mm = m;
m = std::move(mm);
}
auto res = m.emplace("abcde", 2);
assert(res.second);
}
void TestIterators() {
unordered_map<double, std::string> m;
std::vector<double> keys = {0.4, 0.3, -8.32, 7.5, 10.0, 0.0};
std::vector<std::string> values = {
"Summer has come and passed",
"The innocent can never last",
"Wake me up when September ends",
"Like my fathers come to pass",
"Seven years has gone so fast",
"Wake me up when September ends",
};
m.reserve(1'000'000);
for (int i = 0; i < 6; ++i) {
m.insert({keys[i], values[i]});
}
auto beg = m.cbegin();
std::string s = beg->second;
auto it = m.begin();
++it;
m.erase(it++);
it = m.begin();
m.erase(++it);
assert(beg->second == s);
assert(m.size() == 4);
unordered_map<double, std::string> mm;
std::vector<std::pair<const double, std::string>> elements = {
{3.0, values[0]},
{5.0, values[1]},
{-10.0, values[2]},
{35.7, values[3]}
};
mm.insert(elements.cbegin(), elements.cend());
s = mm.begin()->second;
m.insert(mm.begin(), mm.end());
assert(mm.size() == 4);
assert(mm.begin()->second == s);
// Test traverse efficiency
m.reserve(1'000'000); // once again, nothing really should happen
assert(m.size() == 8);
// Actions below must be quick (~ 1000 * 8 operations) despite reserving space for 1M elements
for (int i = 0; i < 10000; ++i) {
long long h = 0;
for (auto it = m.cbegin(); it != m.cend(); ++it) {
// just some senseless action
h += int(it->first) + int((it->second)[0]);
}
}
it = m.begin();
++it;
s = it->second;
// I asked to reserve space for 1M elements so actions below adding 100'000 elements mustn't cause reallocation
for (double d = 100.0; d < 10100.0; d += 0.1) {
m.emplace(d, "a");
}
// And my iterator must point to the same object as before
assert(it->second == s);
int dist = std::distance(it, m.end());
int sz = m.size();
m.erase(it, m.end());
assert(sz - dist == m.size());
// Must be also fast
for (double d = 200.0; d < 10200.0; d += 0.35) {
auto it = m.find(d);
if (it != m.end()) m.erase(it);
}
}
// Just a simple SFINAE trick to check CE presence when it's necessary
// Stay tuned, we'll discuss this kind of tricks in our next lectures ;)
template<typename T>
decltype(unordered_map<T, T>().cbegin()->second = 0, int()) TestConstIteratorDoesntAllowModification(T) {
assert(false);
}
template<typename... FakeArgs>
void TestConstIteratorDoesntAllowModification(FakeArgs...) {}
struct VerySpecialType {
int x = 0;
explicit VerySpecialType(int x): x(x) {}
VerySpecialType(const VerySpecialType&) = delete;
VerySpecialType& operator=(const VerySpecialType&) = delete;
VerySpecialType(VerySpecialType&&) = default;
VerySpecialType& operator=(VerySpecialType&&) = default;
};
struct NeitherDefaultNorCopyConstructible {
VerySpecialType x;
NeitherDefaultNorCopyConstructible() = delete;
NeitherDefaultNorCopyConstructible(const NeitherDefaultNorCopyConstructible&) = delete;
NeitherDefaultNorCopyConstructible& operator=(const NeitherDefaultNorCopyConstructible&) = delete;
NeitherDefaultNorCopyConstructible(VerySpecialType&& x): x(std::move(x)) {}
NeitherDefaultNorCopyConstructible(NeitherDefaultNorCopyConstructible&&) = default;
NeitherDefaultNorCopyConstructible& operator=(NeitherDefaultNorCopyConstructible&&) = default;
bool operator==(const NeitherDefaultNorCopyConstructible& other) const {
return x.x == other.x.x;
}
};
namespace std {
template<>
struct hash<NeitherDefaultNorCopyConstructible> {
size_t operator()(const NeitherDefaultNorCopyConstructible& x) const {
return std::hash<int>()(x.x.x);
}
};
}
void TestNoRedundantCopies() {
unordered_map<NeitherDefaultNorCopyConstructible, NeitherDefaultNorCopyConstructible> m;
m.reserve(10);
m.emplace(VerySpecialType(0), VerySpecialType(0));
m.reserve(1'000'000);
std::pair<NeitherDefaultNorCopyConstructible, NeitherDefaultNorCopyConstructible> p{VerySpecialType(1), VerySpecialType(1)};
m.insert(std::move(p));
assert(m.size() == 2);
// this shouldn't compile
// m[VerySpecialType(0)] = VerySpecialType(1);
// but this should
m.at(VerySpecialType(1)) = VerySpecialType(0);
{
auto mm = std::move(m);
m = std::move(mm);
}
m.erase(m.begin());
m.erase(m.begin());
assert(m.size() == 0);
}
template<typename T>
struct MyHash {
size_t operator()(const T& p) const {
return std::hash<int>()(p.second / p.first);
}
};
template<typename T>
struct MyEqual {
bool operator()(const T& x, const T& y) const {
return y.second / y.first == x.second / x.first;
}
};
struct OneMoreStrangeStruct {
int first;
int second;
};
bool operator==(const OneMoreStrangeStruct&, const OneMoreStrangeStruct&) = delete;
void TestCustomHashAndCompare() {
unordered_map<std::pair<int, int>, char, MyHash<std::pair<int, int>>,
MyEqual<std::pair<int, int>>> m;
m.insert({{1, 2}, 0});
m.insert({{2, 4}, 1});
assert(m.size() == 1);
m[{3, 6}] = 3;
assert(m.at({4, 8}) == 3);
unordered_map<OneMoreStrangeStruct, int, MyHash<OneMoreStrangeStruct>, MyEqual<OneMoreStrangeStruct>> mm;
mm[{1, 2}] = 3;
assert(mm.at({5, 10}) == 3);
mm.emplace(OneMoreStrangeStruct{3, 9}, 2);
assert(mm.size() == 2);
mm.reserve(1'000);
mm.erase(mm.begin());
mm.erase(mm.begin());
for (int k = 1; k < 100; ++k) {
for (int i = 1; i < 10; ++i) {
mm.insert({{i, k*i}, 0});
}
}
std::string ans;
std::string myans;
for (auto it = mm.cbegin(); it != mm.cend(); ++it) {
ans += std::to_string(it->second);
myans += '0';
}
assert(ans == myans);
}
// Finally, some tricky fixtures to test custom allocator.
// Done by professional, don't try to repeat
class Chaste {
private:
int x = 0;
Chaste() = default;
Chaste(int x): x(x) {}
// Nobody can construct me except this guy
template<typename T>
friend class TheChosenOne;
public:
Chaste(const Chaste&) = default;
Chaste(Chaste&&) = default;
bool operator==(const Chaste& other) const {
return x == other.x;
}
};
namespace std {
template<>
struct hash<Chaste> {
size_t operator()(const Chaste& x) const {
return std::hash<int>()(reinterpret_cast<const int&>(x));
}
};
}
template<typename T>
struct TheChosenOne: public std::allocator<T> {
TheChosenOne() {}
template<typename U>
TheChosenOne(const TheChosenOne<U>&) {}
template<typename... Args>
void construct(T* p, Args&&... args) const {
new(p) T(std::forward<Args>(args)...);
}
void destroy(T* p) const {
p->~T();
}
template<typename U>
struct rebind {
using other = TheChosenOne<U>;
};
};
template<>
struct TheChosenOne<std::pair<const Chaste, Chaste>>
: public std::allocator<std::pair<const Chaste, Chaste>> {
using PairType = std::pair<const Chaste, Chaste>;
TheChosenOne() {}
template<typename U>
TheChosenOne(const TheChosenOne<U>&) {}
void construct(PairType* p, int a, int b) const {
new(p) PairType(Chaste(a), Chaste(b));
}
void destroy(PairType* p) const {
p->~PairType();
}
template<typename U>
struct rebind {
using other = TheChosenOne<U>;
};
};
void TestCustomAlloc() {
// This container mustn't construct or destroy any objects without using TheChosenOne allocator
unordered_map<Chaste, Chaste, std::hash<Chaste>, std::equal_to<Chaste>,
TheChosenOne<std::pair<const Chaste, Chaste>>> m;
m.emplace(0, 0);
{
auto mm = m;
mm.reserve(1'000);
mm.erase(mm.begin());
}
for (int i = 0; i < 1'000'000; ++i) {
m.emplace(i, i);
}
for (int i = 0; i < 500'000; ++i) {
auto it = m.begin();
++it, ++it;
m.erase(m.begin(), it);
}
}
int main() {
// List<NeitherDefaultNorCopyConstructible> lst;
// NeitherDefaultNorCopyConstructible p = {VerySpecialType(1)};
// lst.insert(lst.end(), std::move(p));
// return 0;
SimpleTest();
TestIterators();
TestConstIteratorDoesntAllowModification(0);
TestNoRedundantCopies();
TestCustomHashAndCompare();
TestCustomAlloc();
}

5
map/makefile Executable file
View file

@ -0,0 +1,5 @@
all: main.cpp
g++ -g -Wall -std=c++17 -D LOCAL main.cpp -o a
debug: main.cpp
g++ -g -std=c++17 main.cpp -D LOCAL -o a -Wall -Wextra -pedantic -O2 -Wshadow -Wformat=2 -Wfloat-equal -Wconversion -Wlogical-op -Wshift-overflow=2 -Wduplicated-cond -Wcast-qual -Wcast-align -D_GLIBCXX_DEBUG -D_GLIBCXX_DEBUG_PEDANTIC -D_FORTIFY_SOURCE=2 -fsanitize=address -fsanitize=undefined -fno-sanitize-recover -fstack-protector

571
map/unordered_map.h Normal file
View file

@ -0,0 +1,571 @@
#include <utility>
#include <list>
#include <vector>
#include <functional>
#include <cassert>
#include <iostream>
#include <memory>
#include <utility>
using std::prev;
template<typename T, typename Allocator=std::allocator<T>>
class List {
private:
class Node;
template<bool is_const>
class base_iterator;
public:
using iterator = base_iterator<false>;
using const_iterator = base_iterator<true>;
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
explicit List(const Allocator& alloc = Allocator()) : allocator_node_(alloc) {
AllocateEnd();
}
List(size_t count, const T& value, const Allocator& alloc = Allocator()) : allocator_node_(alloc) {
AllocateEnd();
for (size_t i = 0; i < count; ++i) {
Node* tmp = allocator_node_.allocate(1);
alloc_traits_::construct(allocator_node_, tmp, value);
Link(end_->l, tmp);
}
size_ = count;
}
List(size_t count, const Allocator& alloc = Allocator()) : allocator_node_(alloc) {
AllocateEnd();
for (size_t i = 0; i < count; ++i) {
Node* tmp = allocator_node_.allocate(1);
alloc_traits_::construct(allocator_node_, tmp);
Link(end_->l, tmp);
}
size_ = count;
}
List(const List& another) {
allocator_node_ = alloc_traits_::select_on_container_copy_construction(another.allocator_node_);
AllocateEnd();
for (const T& i: another) {
Node* tmp = allocator_node_.allocate(1);
alloc_traits_::construct(allocator_node_, tmp, i);
Link(end_->l, tmp);
}
size_ = another.size();
}
List(List&& another) : end_(std::move(another.end_)), size_(std::move(another.size_)) {
another.end_ = nullptr;
}
List& operator=(const List& another) {
if (this == &another) return *this;
if (alloc_traits_::propagate_on_container_copy_assignment::value && allocator_node_ != another.allocator_node_) {
allocator_node_ = another.allocator_node_;
}
auto it1 = begin();
auto it2 = another.begin();
for (size_t i = 0; i < std::min(another.size(), size()); ++i) {
*it1 = *it2;
++it1;
++it2;
}
if (another.size() > size()) {
while (size() != another.size()) {
push_back(*it2);
++it2;
}
} else {
while (size() != another.size()) {
pop_back();
}
}
return *this;
}
List& operator=(List&& another) {
auto tmp(std::move(another));
std::swap(end_, tmp.end_);
std::swap(size_, tmp.size_);
return *this;
}
~List() {
if (end_) {
while (end_ != end_->r) {
erase(iterator(end_->r));
}
allocator_node_.deallocate(end_, 1); // TODO
}
}
Allocator get_allocator() {
return allocator_node_;
}
void push_back(const T& value) {
insert(end(), value);
}
void push_back(T&& value) {
insert(end(), std::move(value));
}
void push_front(const T& value) {
insert(begin(), value);
}
void pop_back() {
erase(std::prev(end()));
}
void pop_front() {
erase(begin());
}
template<class... Args>
iterator emplace_back(Args&&... args) {
Node* tmp = allocator_node_.allocate(1);
tmp->l = nullptr;
tmp->r = nullptr;
Allocator tmp1 = allocator_node_;
std::allocator_traits<Allocator>::construct(tmp1, &tmp->value, std::forward<Args>(args)...);
Link(std::prev(end()).it, tmp);
++size_;
return iterator(tmp);
}
size_t size() const { return size_; }
iterator begin() { return iterator(end_->r); }
iterator end() { return iterator(end_); }
const_iterator begin() const { return const_iterator(end_->r); }
const_iterator end() const { return const_iterator(end_); }
const_iterator cbegin() const { return const_iterator(end_->r); }
const_iterator cend() const { return const_iterator(end_); }
reverse_iterator rbegin() { return reverse_iterator(end()); }
reverse_iterator rend() { return reverse_iterator(begin()); }
const_reverse_iterator rbegin() const { return const_reverse_iterator(cend()); }
const_reverse_iterator rend() const { return const_reverse_iterator(cbegin()); }
const_reverse_iterator crbegin() const { return const_reverse_iterator(cend()); }
const_reverse_iterator crend() const { return const_reverse_iterator(cbegin()); }
iterator insert(const_iterator it, const T& value) {
Node* tmp = allocator_node_.allocate(1);
tmp->l = nullptr;
tmp->r = nullptr;
std::allocator_traits<decltype(allocator_node_)>::construct(allocator_node_, tmp, value);
Link(const_cast<Node*>(std::prev(it).it), tmp);
++size_;
return iterator(tmp);
}
iterator insert(const_iterator it, T&& value) {
Node* tmp = allocator_node_.allocate(1);
tmp->l = nullptr;
tmp->r = nullptr;
alloc_traits_::construct(allocator_node_, tmp, std::move(value));
Link(const_cast<Node*>(std::prev(it).it), tmp);
++size_;
return iterator(tmp);
}
void erase(const_iterator it) {
Node* tmp = const_cast<Node*>(it.it);
tmp->l->r = tmp->r;
tmp->r->l = tmp->l;
std::allocator_traits<decltype(allocator_node_)>::destroy(allocator_node_, tmp);
allocator_node_.deallocate(tmp, 1);
--size_;
}
void relink(iterator a, iterator b) {
Link(a.it, b.it);
}
private:
void AllocateEnd() {
end_ = allocator_node_.allocate(1);
end_->l = end_;
end_->r = end_;
}
void Link(Node* l, Node* x) {
Node* r = l->r;
if (r == x)
return;
auto xl = x->l, xr = x->r;
if (xl)
xl->r = xr;
if (xr)
xr->l = xl;
x->l = l;
x->r = r;
l->r = x;
r->l = x;
}
template<bool is_const>
class base_iterator {
friend List;
std::conditional_t<is_const, const Node*, Node*> it;
using U = std::conditional_t<is_const, const T, T>;
public:
using iterator_category = std::bidirectional_iterator_tag;
using value_type = U;
using pointer = U*;
using reference = U&;
using difference_type = int;
base_iterator() : it(nullptr) {}
base_iterator(Node* v) { it = v; }
base_iterator(const base_iterator&) = default;
operator base_iterator<true>() { return base_iterator<true>(it); }
U& operator*() const { return it->value; }
U* operator->() const { return &it->value; }
base_iterator& operator++()& {
it = it->r;
return *this;
}
base_iterator operator++(int)& {
base_iterator tmp = *this;
it = it->r;
return tmp;
}
base_iterator& operator--()& {
it = it->l;
return *this;
}
base_iterator operator--(int)& {
base_iterator tmp = *this;
it = it->l;
return tmp;
}
friend bool operator==(base_iterator first, base_iterator second) { return first.it == second.it; }
friend bool operator!=(base_iterator first, base_iterator second) { return first.it != second.it; }
base_iterator& operator=(const base_iterator<false>& another) {
it = another.it;
return *this;
}
};
struct Node {
Node* l = nullptr;
Node* r = nullptr;
T value;
Node() = default;
Node(const T& value) : value(value) {}
Node(T&& value) : value(std::move(value)) {}
Node& operator=(const Node& another) { value = another.value; }
};
typename std::allocator_traits<Allocator>::template rebind_alloc<Node> allocator_node_;
using alloc_traits_ = std::allocator_traits<decltype(allocator_node_)>;
Node* end_ = nullptr;
size_t size_ = 0;
};
template<typename Key, typename Value, typename Hash = std::hash<Key>, typename Equal = std::equal_to<Key>, typename Alloc = std::allocator<std::pair<const Key, Value>>>
class UnorderedMap {
private:
using NonConstNodeType = std::pair<Key, Value>;
using ListNonConstNodeType = List<NonConstNodeType, typename std::allocator_traits<Alloc>::template rebind_alloc<std::pair<Key, Value>>>;
struct Node {
std::pair<Key, Value> pair;
size_t hash;
Node() {}
Node(const Node& another) : pair(another.pair), hash(another.hash) {}
Node(Node&& another) : pair(std::move(another.pair)), hash(another.hash) { another.hash = 0; }
Node(Key&& key, Value&& value, const Hash& hash_) : pair(std::make_pair(std::move(key), std::move(value))) {
hash = hash_(key);
}
Node(const Key& key, const Value& value, const Hash& hash_) : pair(std::make_pair(key, value)){
hash = hash_(key);
}
Node(std::pair<Key, Value>&& pair_, const Hash& hash_) : pair(std::move(pair_)) {
hash = hash_(pair.first);
}
Node(const std::pair<Key, Value>& pair_, const Hash& hash_) : pair(pair_) {
hash = hash_(pair.first);
}
};
using NewList = List<Node, typename std::allocator_traits<Alloc>::template rebind_alloc<Node>>;
NewList new_all_pairs;
std::vector<typename NewList::iterator> new_hash_table;
size_t GetBucketIdx(const Key& key) {
return hash_(key) % new_hash_table.size();
}
size_t GetBucketIdx(const Node& node) {
return node.hash % new_hash_table.size();
}
public:
using new_iterator = typename NewList::iterator;
template<bool is_const>
struct base_iterator {
using value_type = std::conditional_t<is_const, const std::pair<const Key, Value>, std::pair<const Key, Value>>;
using iterator_category = std::bidirectional_iterator_tag;
using pointer = value_type*;
using reference = value_type&;
using difference_type = int;
new_iterator it;
base_iterator() {}
base_iterator(const base_iterator&) = default;
base_iterator(const new_iterator& another) : it(another) {}
operator base_iterator<true>() { return base_iterator<true>(it); }
base_iterator& operator=(const base_iterator&) = default;
reference operator*() { return *reinterpret_cast<std::pair<const Key, Value>*>(&it->pair); }
pointer operator->() { return reinterpret_cast<std::pair<const Key, Value>*>(&it->pair); }
base_iterator& operator++()& { ++it; return *this; }
base_iterator operator++(int)& { base_iterator tmp(*this); ++it; return tmp; }
base_iterator& operator--()& { --it; return *this; }
base_iterator operator--(int)& { base_iterator tmp(*this); --it; return tmp; }
bool operator==(const base_iterator& another) { return it == another.it; }
bool operator!=(const base_iterator& another) { return it != another.it; }
};
using iterator = base_iterator<false>;
using const_iterator = base_iterator<true>;
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
using NodeType = std::pair<const Key, Value>;
UnorderedMap() {
new_hash_table.resize(1000, new_all_pairs.end());
}
UnorderedMap(const UnorderedMap& another) : new_all_pairs(another.new_all_pairs), hash_(another.hash_), equal_(another.equal_) {
new_hash_table.resize(another.new_hash_table.size(), new_all_pairs.end());
new_hash_table[GetBucketIdx(*new_all_pairs.begin())] = new_all_pairs.begin();
for (auto it = std::next(new_all_pairs.begin()); it != new_all_pairs.end(); ++it) {
if (GetBucketIdx(*it) != GetBucketIdx(*prev(it)))
new_hash_table[GetBucketIdx(*it)] = it;
}
}
UnorderedMap(UnorderedMap&&) = default;
UnorderedMap& operator=(const UnorderedMap& another) {
this->all_pairs = another.all_pairs;
this->hash_table_ = another.hash_table_;
this->hash_ = another.hash_;
this->equal_ = another.equal_;
this->max_load_factor_ = another.max_load_factor_;
return *this;
}
UnorderedMap& operator=(UnorderedMap&&) = default;
size_t size() const {
return new_all_pairs.size();
}
Value& at(const Key& key) {
auto it = find(key);
if (it == end()) {
throw std::out_of_range("uhaha");
} else {
return it->second;
}
}
Value& operator[](const Key& key) {
return insert(std::make_pair(key, Value())).first->second;
}
template<class... Args>
std::pair<iterator, bool> emplace(Args&&... args) {
if (new_hash_table.size() < new_all_pairs.size())
rehash(new_hash_table.size() * 1.8);
new_all_pairs.emplace_back(std::forward<Args>(args)..., hash_);
auto& node = *std::prev(new_all_pairs.end());
auto& key = node.pair.first;
size_t hash = GetBucketIdx(node);
if (new_hash_table[hash] != new_all_pairs.end()) {
auto i = new_hash_table[hash];
while (i != prev(new_all_pairs.end()) && GetBucketIdx(*i) == hash) {
if (equal_(i->pair.first, key)) break;
++i;
}
if (i != std::prev(new_all_pairs.end()) && equal_(i->pair.first, key)) {
new_all_pairs.pop_back();
return {i, false};
} else {
auto it = std::prev(new_all_pairs.end());
new_all_pairs.relink(std::prev(i), it);
return {it, true};
}
} else {
new_hash_table[hash] = prev(new_all_pairs.end());
return {new_hash_table[hash], true};
}
}
std::pair<iterator, bool> insert(const std::pair<Key, Value>& tmp) {
return emplace(tmp);
}
std::pair<iterator, bool> insert(std::pair<Key, Value>&& tmp) {
return emplace(std::move(tmp));
}
template<class InputIterator>
void insert(InputIterator begin, InputIterator end) {
for (; begin != end; ++begin) {
insert(*begin);
}
}
iterator erase(const Key& key) {
return erase(find(key));
}
iterator erase(iterator it1) {
auto it = it1.it;
size_t hash = GetBucketIdx(*it);
if (new_hash_table[hash] != it) {
auto i = std::next(it);
new_all_pairs.erase(it);
return i;
} else {
if (GetBucketIdx(*std::next(it)) == hash) {
auto i = std::next(it);
new_all_pairs.erase(it);
new_hash_table[hash] = i;
return i;
} else {
auto i = std::next(it);
new_all_pairs.erase(it);
new_hash_table[hash] = new_all_pairs.end();
return i;
}
}
}
iterator erase(iterator begin, iterator end) {
for (; begin != end;) {
begin = erase(begin);
}
return end;
}
const_iterator erase(const_iterator begin, const_iterator end) {
for (; begin != end; ++begin) {
erase(begin);
}
return end;
}
iterator find(const Key& key) {
size_t hash = GetBucketIdx(key);
if (new_hash_table[hash] != new_all_pairs.end()) {
auto i = new_hash_table[hash];
while (i != new_all_pairs.end() && GetBucketIdx(*i) == hash) {
if (equal_(i->pair.first, key)) break;
++i;
}
if (i != new_all_pairs.end() && equal_(i->pair.first, key)) {
return i;
} else {
return end();
}
} else {
return end();
}
}
const_iterator find(const Key& key) const {
return const_cast<UnorderedMap&>(*this).find(key);
}
void rehash(size_t count) {
if (count <= new_hash_table.size())
return;
std::vector<new_iterator> v(count, new_all_pairs.end());
for (auto it = begin_(); it != end_(); ++it) {
auto& i = *it;
size_t hash = hash_(i.pair.first);
if (v[hash % v.size()] != new_all_pairs.end()) {
new_all_pairs.relink(v[hash % v.size()], it);
} else {
v[hash % v.size()] = it;
}
}
std::swap(new_hash_table, v);
}
void reserve(size_t count) {
rehash(count);
}
float load_factor() const {
return static_cast<float>(size()) / new_hash_table.size();
}
float max_load_factor() const {
return max_load_factor_;
}
void max_load_factor(float ml) {
max_load_factor_ = ml;
}
iterator begin() { return new_all_pairs.begin(); }
iterator end() { return new_all_pairs.end(); }
new_iterator begin_() { return new_all_pairs.begin(); }
new_iterator end_() { return new_all_pairs.end(); }
const_iterator begin() const { return const_iterator(const_cast<NewList&>(new_all_pairs).begin()); }
const_iterator end() const { return const_iterator(const_cast<NewList&>(new_all_pairs).end()); }
const_iterator cbegin() const { return const_iterator(const_cast<NewList&>(new_all_pairs).begin()); }
const_iterator cend() const { return const_iterator(const_cast<NewList&>(new_all_pairs).end()); }
reverse_iterator rbegin() { return reverse_iterator(end()); }
reverse_iterator rend() { return reverse_iterator(begin()); }
const_reverse_iterator rbegin() const { return const_reverse_iterator(cend()); }
const_reverse_iterator rend() const { return const_reverse_iterator(cbegin()); }
const_reverse_iterator crbegin() const { return const_reverse_iterator(cend()); }
const_reverse_iterator crend() const { return const_reverse_iterator(cbegin()); }
private:
Hash hash_;
Equal equal_;
float max_load_factor_;
};

49
matrix/main.cpp Normal file
View file

@ -0,0 +1,49 @@
#include <bits/stdc++.h>
#include "matrix.h"
using namespace std;
int main() {
BigInteger d = 1000000;
d *= d;
d /= 132;
cout << d << endl;
Matrix<20, 20, Rational> a;
for (size_t i = 0; i < a.getRow(0).size(); ++i) {
for (size_t j = 0; j < a.getColumn(0).size(); ++j) {
cin >> a[i][j];
}
}
for (size_t i = 0; i < a.getRow(0).size(); ++i) {
for (size_t j = 0; j < a.getColumn(0).size(); ++j) {
cout << setprecision(20) << (double)a[i][j] << " ";
}
cout << endl;
}
cout << "START INVERTED" << endl;
auto s = a.inverted();
cout << "END INVERTED" << endl;
Matrix<20, 20, double> result;
for (size_t i = 0; i < a.getRow(0).size(); ++i) {
for (size_t j = 0; j < a.getColumn(0).size(); ++j) {
cin >> result[i][j];
}
}
for (size_t i = 0; i < s.getRow(0).size(); ++i) {
for (size_t j = 0; j < s.getColumn(0).size(); ++j) {
if (abs((double)s[i][j] - result[i][j]) < 1e-6) continue;
cout << setprecision(8) << (double)s[i][j] << " ";
}
cout << endl;
}
return 0;
}

5
matrix/makefile Executable file
View file

@ -0,0 +1,5 @@
all: main.cpp
g++ -g -Wall -std=c++17 -D LOCAL main.cpp -o a
debug: main.cpp
g++ -g -std=c++17 main.cpp -D LOCAL -o a -Wall -Wextra -pedantic -O2 -Wshadow -Wformat=2 -Wfloat-equal -Wconversion -Wlogical-op -Wshift-overflow=2 -Wduplicated-cond -Wcast-qual -Wcast-align -D_GLIBCXX_DEBUG -D_GLIBCXX_DEBUG_PEDANTIC -D_FORTIFY_SOURCE=2 -fsanitize=address -fsanitize=undefined -fno-sanitize-recover -fstack-protector

1286
matrix/matrix.h Normal file

File diff suppressed because it is too large Load diff

968
matrix/matrix2.h Normal file
View file

@ -0,0 +1,968 @@
#include <iostream>
#include <vector>
#include <cassert>
#include <string>
#include <type_traits>
/*
* TODO: assert and invert
* порядок методов
* проверка на N != M
*/
class BigInteger{
private:
static const int BASE = 10;
bool isPositive; //Zero is positive
std::vector<short> digits;
void normilize();
void popBackZeros();
void fixMinusZero();
void reverseDigits();
void addDigit(short);
friend std::istream& operator>>(std::istream&, BigInteger&);
public:
BigInteger(int);
BigInteger();
BigInteger& operator+=(const BigInteger&);
BigInteger operator+() const;
BigInteger& operator++();
BigInteger operator++(int);
BigInteger& operator-=(const BigInteger&);
BigInteger operator-() const;
BigInteger& operator--();
BigInteger operator--(int);
BigInteger& operator*=(const BigInteger&);
BigInteger& operator/=(const BigInteger&);
BigInteger& operator%=(const BigInteger&);
bool operator<(const BigInteger&) const;
bool operator>(const BigInteger&) const;
bool operator==(const BigInteger&) const;
bool operator!=(const BigInteger&) const;
bool operator<=(const BigInteger&) const;
bool operator>=(const BigInteger&) const;
explicit operator int() const;
explicit operator bool() const;
std::string toString() const;
};
// if something weird in istream => return interpreted, istream is on the first weird symbol
// also interpret number = sign as 0
std::istream& operator>>(std::istream& in, BigInteger& num) {
char c;
bool signDefined = false;
num.isPositive = true;
num.digits.clear();
while(in.get(c)) {
if (c == '-' && !signDefined) {
num.isPositive = false;
signDefined = true;
} else if (c == '+' && !signDefined) {
num.isPositive = true;
signDefined = true;
} else if (c >= '0' && c <= '9') {
num.digits.push_back(c - '0');
signDefined = true;
} else {
if (c != ' ' && c != '\n')
in.putback(c);
break;
}
}
if (num.digits.size() == 0)
num.digits.push_back(0);
num.reverseDigits();
num.normilize();
return in;
}
std::ostream& operator<<(std::ostream& out, const BigInteger& num) {
out << num.toString();
return out;
}
void BigInteger::normilize() {
popBackZeros();
fixMinusZero();
}
void BigInteger::popBackZeros() {
while(digits.size() > 1 && digits.back() == 0) {
digits.pop_back();
}
}
void BigInteger::fixMinusZero() {
isPositive = !isPositive;
if (*this == BigInteger(0))
isPositive = !isPositive;
isPositive = !isPositive;
}
void BigInteger::reverseDigits() {
int size = digits.size();
for (int i = 0; i < size / 2; ++i) {
std::swap(digits[i], digits[size-1-i]);
}
}
void BigInteger::addDigit(short digit) {
reverseDigits();
digits.push_back(digit);
reverseDigits();
}
BigInteger::BigInteger(int value) {
isPositive = (value >= 0);
if (!isPositive)
value = -value;
if (!value) digits.push_back(0);
while (value) {
digits.push_back(value % BASE);
value /= BASE;
}
}
BigInteger::BigInteger() : BigInteger(0) {
}
BigInteger& BigInteger::operator+=(const BigInteger& num) {
if (this == &num) {
return *this += BigInteger(num);
}
if (num.isPositive == isPositive) {
for (unsigned int i = 0; i < std::max(num.digits.size(), digits.size()); ++i) {
short add = (i < num.digits.size() ? num.digits[i] : 0);
if (digits.size() == i)
digits.push_back(0);
if (digits[i] + add >= BASE) {
if (digits.size() == i + 1)
digits.push_back(0);
++digits[i + 1];
} else if (i >= num.digits.size()) {
digits[i] = (digits[i] + add) % BASE;
break;
}
digits[i] = (digits[i] + add) % BASE;
}
} else {
isPositive = !isPositive;
*this -= num;
isPositive = !isPositive;
}
normilize();
return *this;
}
BigInteger operator+(const BigInteger& num1, const BigInteger& num2) {
BigInteger copy = num1;
return copy += num2;
}
BigInteger BigInteger::operator+() const {
return *this;
}
BigInteger& BigInteger::operator++() {
return (*this += 1);
}
BigInteger BigInteger::operator++(int) {
BigInteger copy = *this;
++(*this);
return copy;
}
BigInteger& BigInteger::operator-=(const BigInteger& num) {
if (this == &num) {
return *this -= BigInteger(num);
}
if (num.isPositive == isPositive) {
bool needChange = isPositive ^ (num <= *this);
const BigInteger& a = needChange ? num : *this;
const BigInteger& b = needChange ? *this : num;
bool need = false;
for (unsigned int i = 0; i < a.digits.size(); ++i) {
bool needNext = (a.digits[i] - need - (i < b.digits.size() ? b.digits[i] : 0) < 0);
if(i == digits.size()) digits.push_back(0);
digits[i] = (a.digits[i] - need - (i < b.digits.size() ? b.digits[i] : 0) + BASE) % BASE;
need = needNext;
}
isPositive ^= needChange;
} else {
isPositive = !isPositive;
*this += num;
isPositive = !isPositive;
}
normilize();
return *this;
}
BigInteger operator-(const BigInteger& num1, const BigInteger& num2) {
BigInteger copy = num1;
return copy -= num2;
}
BigInteger BigInteger::operator-() const {
return BigInteger(0) -= *this;
}
BigInteger& BigInteger::operator--() {
return (*this -= 1);
}
BigInteger BigInteger::operator--(int) {
BigInteger copy = *this;
--(*this);
return copy;
}
BigInteger& BigInteger::operator*=(const BigInteger& num) {
BigInteger ans;
ans.digits.resize(digits.size() + num.digits.size());
for(unsigned int i = 0; i < digits.size(); ++i) {
int add = 0;
for (unsigned int j = 0; j <= num.digits.size(); ++j) {
short numDigit = (j == num.digits.size() ? 0 : num.digits[j]);
short addNext = (ans.digits[i + j] + digits[i] * numDigit + add) / BASE;
ans.digits[i + j] = (ans.digits[i + j] + digits[i] * numDigit + add) % BASE;
add = addNext;
}
}
ans.isPositive = !(isPositive ^ num.isPositive);
ans.normilize();
return *this = ans;
}
BigInteger operator*(const BigInteger& num1, const BigInteger& num2) {
BigInteger copy = num1;
return copy *= num2;
}
BigInteger& BigInteger::operator/=(const BigInteger& num) {
if(num == 0)
return *this;
BigInteger ans, val(digits.back());
ans.isPositive = !(isPositive ^ num.isPositive);
int ptr = digits.size();
ptr -= 2;
val.isPositive = num.isPositive;
while (ptr >= 0 && (num.isPositive ? val < num : num < val)) {
val.addDigit(digits[ptr]);
--ptr;
}
val.isPositive = true;
for (; ptr >= -1; --ptr) {
int number = 0;
while (val >= 0) {
num.isPositive ? val -= num : val += num;
++number;
}
num.isPositive ? val += num : val -= num;
--number;
ans.digits.push_back(number);
if(ptr != -1)
val.addDigit(digits[ptr]);
}
ans.reverseDigits();
ans.normilize();
return *this = ans;
}
BigInteger operator/(const BigInteger& num1, const BigInteger& num2) {
BigInteger copy = num1;
return copy /= num2;
}
BigInteger& BigInteger::operator%=(const BigInteger& num) {
if(num == 0)
return *this;
BigInteger copy = (*this) / num;
return *this -= (copy *= num);
}
BigInteger operator%(const BigInteger& num1, const BigInteger& num2) {
BigInteger copy = num1;
return copy %= num2;
}
bool BigInteger::operator<(const BigInteger& num) const {
if (isPositive != num.isPositive)
return num.isPositive;
for (int j = std::max(static_cast<int>(digits.size()), static_cast<int>(num.digits.size())) - 1; j >= 0; --j) {
unsigned int i = static_cast<unsigned int>(j);
if ((i < digits.size() ? digits[i] : 0) < (i < num.digits.size() ? num.digits[i] : 0)) return isPositive;
if ((i < digits.size() ? digits[i] : 0) > (i < num.digits.size() ? num.digits[i] : 0)) return !isPositive;
}
return false;
}
bool BigInteger::operator>(const BigInteger& num) const {
return num < *this;
}
bool BigInteger::operator==(const BigInteger& num) const {
return !(num < *this || *this < num);
}
bool BigInteger::operator!=(const BigInteger& num) const {
return num < *this || *this < num;
}
bool BigInteger::operator<=(const BigInteger& num) const {
return !(num < *this);
}
bool BigInteger::operator>=(const BigInteger& num) const {
return !(*this < num);
}
std::string BigInteger::toString() const {
std::string num = "";
if (!isPositive) num += '-';
for (int i = digits.size() - 1; i >= 0; --i) {
num += ('0' + digits[i]);
}
return num;
}
BigInteger::operator int() const {
int value = 0;
for (int i = digits.size() - 1; i >= 0; --i)
value = value * 10 + digits[i];
if(!isPositive)
value = -value;
return value;
}
BigInteger::operator bool() const {
return int(*this);
}
class Rational{
private:
BigInteger numerator, denominator;
void normilize();
static BigInteger gcd(const BigInteger&, const BigInteger&);
static void reverse(std::string&);
public:
Rational();
Rational(const BigInteger&);
Rational(const BigInteger& numerator, const BigInteger& denominator): numerator(numerator), denominator(denominator) {}
Rational(int);
Rational& operator+=(const Rational&);
Rational operator+() const;
Rational& operator-=(const Rational&);
Rational operator-() const;
Rational& operator*=(const Rational&);
Rational& operator/=(const Rational&);
bool operator<(const Rational&) const;
bool operator>(const Rational&) const;
bool operator==(const Rational&) const;
bool operator!=(const Rational&) const;
bool operator<=(const Rational&) const;
bool operator>=(const Rational&) const;
explicit operator double() const;
std::string asDecimal(size_t) const;
std::string toString() const;
};
BigInteger Rational::gcd(const BigInteger& a, const BigInteger& b) {
if (b == 0)
return a;
return gcd(b, a % b);
}
void Rational::normilize() {
BigInteger _gcd = gcd(numerator, denominator);
numerator /= _gcd;
denominator /= _gcd;
if (denominator < 0) {
numerator *= -1;
denominator *= -1;
}
}
void Rational::reverse(std::string& s) {
for(size_t i = 0; i < s.size()/2; ++i) {
std::swap(s[i], s[s.size() - 1 - i]);
}
}
Rational::Rational() : Rational(0) {
}
Rational::Rational(const BigInteger& val) {
numerator = val;
denominator = 1;
}
Rational::Rational(int val) {
numerator = val;
denominator = 1;
}
Rational& Rational::operator+=(const Rational& frac) {
if (this == &frac)
return *this += Rational(frac);
numerator *= frac.denominator;
numerator += denominator * frac.numerator;
denominator *= frac.denominator;
normilize();
return *this;
}
Rational operator+(const Rational& frac1, const Rational& frac2) {
Rational copy = frac1;
return copy += frac2;
}
Rational Rational::operator+() const {
return *this;
}
Rational& Rational::operator-=(const Rational& frac) {
if (this == &frac)
return *this -= Rational(frac);
numerator *= frac.denominator;
numerator -= denominator * frac.numerator;
denominator *= frac.denominator;
normilize();
return *this;
}
Rational operator-(const Rational& frac1, const Rational& frac2) {
Rational copy = frac1;
return copy -= frac2;
}
Rational Rational::operator-() const {
return Rational(0) -= *this;
}
Rational& Rational::operator*=(const Rational& frac) {
if (this == &frac)
return *this *= Rational(frac);
numerator *= frac.numerator;
denominator *= frac.denominator;
normilize();
return *this;
}
Rational operator*(const Rational& frac1, const Rational& frac2) {
Rational copy = frac1;
return copy *= frac2;
}
Rational& Rational::operator/=(const Rational& frac) {
if (frac.numerator == 0)
return *this;
if (this == &frac)
return *this /= Rational(frac);
numerator *= frac.denominator;
denominator *= frac.numerator;
normilize();
return *this;
}
Rational operator/(const Rational& frac1, const Rational& frac2) {
Rational copy = frac1;
return copy /= frac2;
}
bool Rational::operator<(const Rational& frac) const {
return numerator * frac.denominator < frac.numerator * denominator;
}
bool Rational::operator>(const Rational& frac) const {
return frac < *this;
}
bool Rational::operator==(const Rational& frac) const {
return !(frac < *this || *this < frac);
}
bool Rational::operator!=(const Rational& frac) const {
return frac < *this || *this < frac;
}
bool Rational::operator<=(const Rational& frac) const {
return !(frac < *this);
}
bool Rational::operator>=(const Rational& frac) const {
return !(*this < frac);
}
Rational::operator double() const {
return std::stod(asDecimal(200));
}
std::string Rational::asDecimal(size_t precision = 0u) const {
BigInteger ten = 1;
for (size_t i = 0; i < precision; ++i) {
ten *= 10;
}
BigInteger val = (numerator < 0 ? -1 : 1) * numerator * ten / denominator;
std::string integer = (val / ten).toString();
std::string frac = (val % ten).toString();
reverse(frac);
while(frac.size() < precision) frac += '0';
frac += '.';
reverse(frac);
if(precision == 0u) frac = "";
integer = (numerator < 0 ? "-" : "") + integer;
return integer + frac;
}
std::string Rational::toString() const {
std::string num = numerator.toString();
if (denominator != 1) {
num += "/" + denominator.toString();
}
return num;
}
std::ostream& operator<<(std::ostream& out, const Rational& value) {
out << value.asDecimal(5);
return out;
}
std::istream& operator>>(std::istream& in, Rational& value) {
BigInteger numerator(0), denominator(0);
bool was = false;
char c;
while (in.get(c)) {
if (c == ' ' || c == '\n')
break;
if (c == '/') {
was = true;
} else {
if (!was) {
numerator *= 10;
numerator += (c - '0');
} else {
denominator *= 10;
denominator += (c - '0');
}
}
}
if (!was) {
denominator = BigInteger(1);
}
value = Rational(numerator, denominator);
return in;
}
bool isPrime(int N) {
for (long long i = 2; i * i <= N; ++i) {
if (N % i == 0)
return false;
}
return true;
}
int fastPow(int a, int b, int module) {
if (b == 0)
return 1;
if (b % 2 == 0) {
long long val = fastPow(a, b / 2, module);
return (val * val) % module;
} else {
return (1ll * fastPow(a, b - 1, module) * a) % module;
}
}
int inverseValue(int value, int module) {
return fastPow(value, module - 2, module);
}
template<int N>
class Finite {
public:
Finite<N>(int value = 0): value((value % N + N) % N), isPrimeN(isPrime(N)) {}
Finite<N>& operator+=(const Finite<N>& number) {
value = (value + number.value) % N;
return *this;
}
Finite<N> operator+(const Finite<N>& number) const {
Finite<N> copy = *this;
return copy += number;
}
Finite<N>& operator-=(const Finite<N>& number) {
value = (value - number.value + N) % N;
return *this;
}
Finite<N> operator-(const Finite<N>& number) const {
Finite<N> copy = *this;
return copy -= number;
}
Finite<N> operator-() const {
return Finite<N>(0 - value);
}
Finite<N>& operator*=(const Finite<N>& number) {
value = (1ll * value * number.value) % N;
return *this;
}
Finite<N> operator*(const Finite<N>& number) const {
Finite<N> copy = *this;
return copy *= number;
}
Finite<N>& operator/=(const Finite<N>& number) {
assert(isPrimeN);
value = (1ll * value * inverseValue(number.value, N)) % N;
return *this;
}
Finite<N> operator/(const Finite<N>& number) const {
Finite<N> copy = *this;
return copy /= number;
}
bool operator==(const Finite<N>& number) const {
return value == number.value;
}
bool operator!=(const Finite<N>& number) const {
return value != number.value;
}
Finite<N>& operator++() {
return (*this += 1);
}
Finite<N> operator++(int) {
Finite<N> copy;
++(*this);
return copy;
}
template<int U>
friend std::ostream& operator<<(std::ostream&, const Finite<U>&);
private:
int value;
bool isPrimeN;
};
template<int N>
std::ostream& operator<<(std::ostream& out, const Finite<N>& value){
out << value.value;
return out;
}
template<unsigned M, unsigned N, typename Field = Rational>
class Matrix {
public:
Matrix<M, N, Field>();
template<typename T>
Matrix(std::initializer_list<std::initializer_list<T>> a) {
for (auto i: a) {
table.push_back({});
for (auto j: i) {
table.back().push_back(Field(j));
}
}
}
Matrix<M, N, Field>(std::vector<std::vector<Field>>&);
Matrix<M, N, Field>(std::vector<std::vector<int>>&);
template<unsigned M1, unsigned N1, typename Field1>
bool operator==(const Matrix<M1, N1, Field1>&) const;
template<unsigned M1, unsigned N1, typename Field1>
bool operator!=(const Matrix<M1, N1, Field1>&) const;
Matrix<M, N, Field>& operator+=(const Matrix<M, N, Field>&);
Matrix<M, N, Field> operator+(const Matrix<M, N, Field>&) const;
Matrix<M, N, Field>& operator-=(const Matrix<M, N, Field>&);
Matrix<M, N, Field> operator-(const Matrix<M, N, Field>&) const;
Matrix<M, N, Field> operator*(const Field&) const;
Matrix<M, N, Field>& operator*=(const Matrix<M, N, Field>&);
Field det() const;
Matrix<N, M, Field> transposed() const;
unsigned rank() const;
Field trace() const;
void invert();
Matrix<N, M, Field> inverted() const;
std::vector<Field> getRow(unsigned) const;
std::vector<Field> getColumn(unsigned) const;
std::vector<Field>& operator[](size_t index) {
return table[index];
}
const std::vector<Field>& operator[](size_t index) const {
return table[index];
}
template<unsigned N1, unsigned M1, typename Field1>
friend class Matrix;
private:
std::vector<std::vector<Field>> table;
void swapStrings(unsigned, unsigned);
void divideString(unsigned, const Field);
void subtractStrings(unsigned, unsigned, const Field);
Field makeSimple();
};
template<unsigned int M, unsigned int N, typename Field>
Matrix<M, N, Field>::Matrix() {
if (M != N)
assert(0);
table.resize(M, std::vector<Field>(N));
for (unsigned i = 0; i < N; ++i) {
table[i][i] = Field(1);
}
}
template<unsigned int M, unsigned int N, typename Field>
Matrix<M, N, Field>::Matrix(std::vector<std::vector<Field>>& matrix): table(matrix) {}
template<unsigned int M, unsigned int N, typename Field>
Matrix<M, N, Field>::Matrix(std::vector<std::vector<int>>& matrix) {
table.resize(M, std::vector<Field>(N));
for (unsigned i = 0; i < M; ++i) {
for (unsigned j = 0; j < N; ++j){
table[i][j] = Field(matrix[i][j]);
}
}
}
template<unsigned int M, unsigned int N, typename Field>
template<unsigned int M1, unsigned int N1, typename Field1>
bool Matrix<M, N, Field>::operator==(const Matrix<M1, N1, Field1>& matrix) const {
if (!std::is_same<Matrix<M, N, Field>, Matrix<M1, N1, Field1>>::value)
return false;
for (unsigned i = 0; i < M; ++i) {
for (unsigned j = 0; j < N; ++j) {
if (table[i][j] != matrix[i][j])
return false;
}
}
return true;
}
template<unsigned int M, unsigned int N, typename Field>
template<unsigned int M1, unsigned int N1, typename Field1>
bool Matrix<M, N, Field>::operator!=(const Matrix<M1, N1, Field1>& matrix) const {
return !(*this == matrix);
}
template<unsigned int M, unsigned int N, typename Field>
Matrix<M, N, Field>& Matrix<M, N, Field>::operator+=(const Matrix<M, N, Field>& matrix) {
for (unsigned i = 0; i < M; ++i) {
for (unsigned j = 0; j < N; ++j) {
table[i][j] += matrix[i][j];
}
}
return *this;
}
template<unsigned int M, unsigned int N, typename Field>
Matrix<M, N, Field> Matrix<M, N, Field>::operator+(const Matrix<M, N, Field>& matrix) const {
Matrix<M, N, Field> copy = *this;
return copy += matrix;
}
template<unsigned int M, unsigned int N, typename Field>
Matrix<M, N, Field>& Matrix<M, N, Field>::operator-=(const Matrix<M, N, Field>& matrix) {
for (unsigned i = 0; i < M; ++i) {
for (unsigned j = 0; j < N; ++j) {
table[i][j] -= matrix[i][j];
}
}
return *this;
}
template<unsigned int M, unsigned int N, typename Field>
Matrix<M, N, Field> Matrix<M, N, Field>::operator-(const Matrix<M, N, Field>& matrix) const {
Matrix<M, N, Field> copy = *this;
return copy -= matrix;
}
template<unsigned int M, unsigned int N, typename Field>
Matrix<M, N, Field> Matrix<M, N, Field>::operator*(const Field& multiplier) const {
Matrix<M, N, Field> copy = *this;
for (unsigned i = 0; i < M; ++i) {
for (unsigned j = 0; j < N; ++j) {
copy[i][j] *= multiplier;
}
}
return copy;
}
template<unsigned int M, unsigned int N, typename Field>
Matrix<M, N, Field> operator*(const Field& multiplier, const Matrix<M, N, Field> matrix) {
return matrix * multiplier;
}
template<unsigned int M, unsigned int N, unsigned int K, typename Field>
Matrix<M, K, Field> operator*(const Matrix<M, N, Field>& matrix1, const Matrix<N, K, Field>& matrix2) {
std::vector<std::vector<Field>> resultTable(M, std::vector<Field>(K));
for (unsigned i = 0; i < M; ++i) {
for (unsigned j = 0; j < K; ++j) {
for (unsigned k = 0; k < N; ++k) {
resultTable[i][j] += matrix1[i][k] * matrix2[k][j];
}
}
}
return Matrix<M, K, Field>(resultTable);
}
template<unsigned int M, unsigned int N, typename Field>
Matrix<M, N, Field>& Matrix<M, N, Field>::operator*=(const Matrix<M, N, Field>& matrix) {
if (M != N)
assert(0);
return (*this = (*this) * matrix);
}
template<unsigned int M, unsigned int N, typename Field>
Field Matrix<M, N, Field>::det() const {
if (N != M)
assert(0);
Matrix<M, N, Field> copy = *this;
return copy.makeSimple();
}
template<unsigned int M, unsigned int N, typename Field>
Matrix<N, M, Field> Matrix<M, N, Field>::transposed() const {
std::vector<std::vector<Field>> result(N, std::vector<Field>(M));
for (unsigned i = 0; i < N; ++i) {
for (unsigned j = 0; j < M; ++j) {
result[i][j] = table[j][i];
}
}
return Matrix<N, M, Field>(result);
}
template<unsigned int M, unsigned int N, typename Field>
unsigned Matrix<M, N, Field>::rank() const {
Matrix<M, N, Field> copy = *this;
copy.makeSimple();
unsigned rank = 0;
for (unsigned i = 0; i < M; ++i) {
bool empty = true;
for (unsigned j = 0; j < N; ++j) {
if (copy[i][j] != 0)
empty = false;
}
rank += !empty;
}
return rank;
}
template<unsigned int M, unsigned int N, typename Field>
Field Matrix<M, N, Field>::trace() const {
if (N != M)
assert(0);
Field result(0);
for (unsigned i = 0; i < N; ++i) {
result += table[i][i];
}
return result;
}
template<unsigned int M, unsigned int N, typename Field>
void Matrix<M, N, Field>::invert() {
if (M != N)
assert(0);
if (N > 5){
std::cerr << "was:\n";
for(unsigned i = 0; i < 10; ++i) {
for(unsigned j = 0; j < 20; ++j){
std::cerr << table[i][j] << " ";
}
std::cerr << std::endl;
}
}
std::vector<std::vector<Field>> complexTable(N, std::vector<Field>(2 * N));
for (unsigned i = 0; i < N; ++i) {
for (unsigned j = 0; j < N; ++j) {
complexTable[i][j] = table[i][j];
}
}
for (unsigned i = 0; i < N; ++i)
complexTable[i][i + N] = Field(1);
Matrix<N, 2 * N, Field> complexMatrix(complexTable);
complexMatrix.makeSimple();
std::vector<std::vector<Field>> result(N, std::vector<Field>(N));
for (unsigned i = 0; i < M; ++i) {
for (unsigned j = 0; j < N; ++j) {
result[i][j] = complexMatrix[i][j + N];
}
}
if (N > 100){
std::cerr << "now:\n";
for(unsigned i = 0; i < M; ++i) {
for(unsigned j = 0; j < N; ++j){
std::cerr << result[i][j] << " ";
}
std::cerr << std::endl;
}
}
*this = Matrix<N, M, Field>(result);
}
template<unsigned int M, unsigned int N, typename Field>
Matrix<N, M, Field> Matrix<M, N, Field>::inverted() const {
Matrix<N, M, Field> matrix = *this;
matrix.invert();
return matrix;
}
template<unsigned int M, unsigned int N, typename Field>
std::vector<Field> Matrix<M, N, Field>::getRow(unsigned int index) const {
return table[index];
}
template<unsigned int M, unsigned int N, typename Field>
std::vector<Field> Matrix<M, N, Field>::getColumn(unsigned int index) const {
std::vector<Field> result(M);
for (unsigned i = 0; i < M; ++i) {
result[i] = table[i][index];
}
return result;
}
template<unsigned int M, unsigned int N, typename Field>
void Matrix<M, N, Field>::swapStrings(unsigned index1, unsigned index2) {
std::swap(table[index1], table[index2]);
}
template<unsigned int M, unsigned int N, typename Field>
void Matrix<M, N, Field>::divideString(unsigned index, const Field divisor) {
for (unsigned i = 0; i < N; ++i) {
table[index][i] /= divisor;
}
}
template<unsigned int M, unsigned int N, typename Field>
void Matrix<M, N, Field>::subtractStrings(unsigned indexMinuend, unsigned indexSubtrahend, const Field multiplier) {
for (unsigned i = 0; i < N; ++i) {
table[indexMinuend][i] -= table[indexSubtrahend][i] * multiplier;
}
}
template<unsigned int M, unsigned int N, typename Field>
Field Matrix<M, N, Field>::makeSimple() {
Field determinant(1);
unsigned string = 0;
for (unsigned i = 0; i < N; ++i) {
unsigned found = M + 1;
for (unsigned j = string; j < M; ++j) {
if (table[j][i] != Field(0)) {
found = j;
break;
}
}
if (found == M + 1){
determinant = 0;
continue;
}
swapStrings(string, found);
determinant *= table[string][i];
divideString(string, table[string][i]);
for (unsigned j = 0; j < M; ++j) {
if (j != string)
subtractStrings(j, string, table[j][i]);
}
++string;
}
return determinant;
}
template <unsigned N, typename Field = Rational>
using SquareMatrix = Matrix<N, N, Field>;

2
residue/Makefile Normal file
View file

@ -0,0 +1,2 @@
all:
g++ main.cpp -std=c++14 -Wall -Wextra -o a

9
residue/main.cpp Normal file
View file

@ -0,0 +1,9 @@
#include "residue.h"
using namespace std;
int main() {
Residue<2147483647> a(2147483644);
Residue<2147483647> b(2147483645);
cout << int(a * b) << endl;
}

244
residue/residue.h Normal file
View file

@ -0,0 +1,244 @@
#include <vector>
#include <deque>
#include <iostream>
#include <algorithm>
using namespace std;
template<unsigned N, long long i>
struct is_prime_ {
static const bool value = !(N % i == 0) && is_prime_<N, (i + 1) * (i + 1) <= N ? (N % i == 0 ? 1 : i + 1) : -1>::value;
};
template<unsigned N>
struct is_prime_<N, 1LL> {
static const bool value = false;
};
template<unsigned N>
struct is_prime_<N, -1LL> {
static const bool value = true;
};
template<unsigned N>
struct is_prime {
static const bool value = (is_prime_<N, 2>::value && (N != 1)) || (N == 2);
};
template<unsigned N>
static const bool is_prime_v = is_prime<N>::value;
template<unsigned N, unsigned long long i, bool find_divider>
struct is_power_of_prime_ {
static const bool value = is_power_of_prime_<N % i == 0 ? N / i : (find_divider ? 0 : (i * i >= N ? 1 : N)), N % i == 0 ? i : i + 2, N % i == 0>::value;
};
template<unsigned long long i, bool find_divider>
struct is_power_of_prime_<1, i, find_divider> {
static const bool value = true;
};
template<unsigned long long i, bool find_divider>
struct is_power_of_prime_<0, i, find_divider> {
static const bool value = false;
};
template<unsigned N>
struct is_power_of_prime {
static const bool value = is_power_of_prime_<N, 3, false>::value;
};
template<unsigned N>
struct has_primitive_root {
static const bool value = is_power_of_prime<(N == 4 || N == 2 ? 1 : (N % 4 == 0 ? 0 : (N % 2 == 0 ? N / 2 : N)))>::value;
};
template<unsigned N>
static const bool has_primitive_root_v = has_primitive_root<N>::value;
template<bool T>
void my_static_assert() {
int* a = new int [T ? 1 : -1];
delete[] a;
}
unsigned phi(unsigned n) {
unsigned result = n;
for (int i = 2; i * i <= n; ++i) {
if (n % i == 0) {
while (n % i == 0) {
n /= i;
}
result -= result / i;
}
}
if (n > 1)
result -= result / n;
return result;
}
template<unsigned Modulus>
class Residue {
public:
Residue() = default;
Residue(const Residue<Modulus>& another) = default;
explicit Residue(long long x) : x(x) { Normilize(); }
explicit operator int() const { return x; }
bool operator==(const Residue<Modulus>& another) {
return x == another.x;
}
bool operator!=(const Residue<Modulus>& another) {
return !(*this == another);
}
Residue& operator+=(const Residue<Modulus>& another);
Residue& operator-=(const Residue<Modulus>& another);
Residue& operator*=(const Residue<Modulus>& another);
Residue& operator/=(const Residue<Modulus>& another);
Residue getInverse() const {
cerr << "getInverse " << x << " " << Modulus << endl;
my_static_assert<is_prime_v<Modulus>>();
return Residue(pow(x, Modulus - 2));
}
unsigned order() const {
cerr << "order " << x << " " << Modulus << endl;
unsigned phi = ::phi(Modulus);
unsigned copy_phi = phi;
std::vector<unsigned> first = {1}, second = {phi};
for (unsigned i = 2; i * i <= phi; ++i) {
if (copy_phi % i == 0) {
first.push_back(i);
second.push_back(phi / i);
}
}
std::reverse(second.begin(), second.end());
first.insert(first.end(), second.begin(), second.end());
for (unsigned i: first) {
if (pow(i) == Residue(1)) {
return i;
}
}
return 0;
}
static Residue getPrimitiveRoot() {
cerr << "getPrimitiveRoot " << Modulus << endl;
my_static_assert<has_primitive_root_v<Modulus>>();
if (Modulus == 2) {
return Residue(1);
} else if (Modulus == 4) {
return Residue(3);
}
unsigned phi = ::phi(Modulus);
unsigned copy_phi = phi;
std::vector<unsigned> deviders;
for (unsigned i = 2; i * i <= phi; ++i) {
if (copy_phi % i == 0) {
deviders.push_back(i);
deviders.push_back(phi / i);
while (copy_phi % i == 0) copy_phi /= i;
}
}
if (copy_phi > 1)
deviders.push_back(copy_phi);
for (unsigned res = 2; res < phi; ++res) {
bool ok = pow(res, phi) == 1;
for (unsigned i: deviders) {
ok &= pow(res, i) != 1;
}
if (ok) {
return Residue(res);
}
}
return Residue(phi);
}
Residue<Modulus> pow(unsigned degree) const;
private:
static int pow(int x, unsigned degree);
void Normilize() {
x %= static_cast<long long>(Modulus);
if (x < 0)
x += Modulus;
}
long long x;
};
template<unsigned Modulus>
Residue<Modulus>& Residue<Modulus>::operator+=(const Residue<Modulus>& another) {
x += another.x;
Normilize();
return *this;
}
template<unsigned Modulus>
Residue<Modulus>& Residue<Modulus>::operator-=(const Residue<Modulus>& another) {
x -= another.x;
Normilize();
return *this;
}
template<unsigned Modulus>
Residue<Modulus>& Residue<Modulus>::operator*=(const Residue<Modulus>& another) {
x *= another.x;
Normilize();
return *this;
}
template<unsigned Modulus>
Residue<Modulus>& Residue<Modulus>::operator/=(const Residue<Modulus>& another) {
*this *= another.getInverse();
return *this;
}
template<unsigned Modulus>
Residue<Modulus> operator+(const Residue<Modulus>& a, const Residue<Modulus>& b) {
Residue<Modulus> tmp(a);
tmp += b;
return tmp;
}
template<unsigned Modulus>
Residue<Modulus> operator-(const Residue<Modulus>& a, const Residue<Modulus>& b) {
Residue<Modulus> tmp(a);
tmp -= b;
return tmp;
}
template<unsigned Modulus>
Residue<Modulus> operator*(const Residue<Modulus>& a, const Residue<Modulus>& b) {
Residue<Modulus> tmp(a);
tmp *= b;
return tmp;
}
template<unsigned Modulus>
Residue<Modulus> operator/(const Residue<Modulus>& a, const Residue<Modulus>& b) {
Residue<Modulus> tmp(a);
tmp /= b;
return tmp;
}
template<unsigned Modulus>
Residue<Modulus> Residue<Modulus>::pow(unsigned degree) const {
return Residue(pow(x, degree));
}
template<unsigned Modulus>
int Residue<Modulus>::pow(int x, unsigned degree) {
if (degree == 0) {
return 1;
} else {
long long t = pow(x, degree / 2);
return (((t * t) % static_cast<long long>(Modulus)) * (degree % 2 == 0 ? 1 : x)) % static_cast<long long>(Modulus);
}
}

View file

@ -0,0 +1,11 @@
cmake_minimum_required(VERSION 3.10)
project("List")
set(SOURCE_FILES main.cpp)
set(CMAKE_CXX_COMPILER clang++)
set(CMAKE_CXX_STANDARD 17)
add_executable(map ${SOURCE_FILES})

600
shared_pointer/main.cpp Normal file
View file

@ -0,0 +1,600 @@
#include <set>
#include <iostream>
#include <memory>
#include <vector>
#include <algorithm>
#include <cassert>
#include "smart_pointers.h"
//template<typename T>
//using SharedPtr = std::shared_ptr<T>;
//
//template<typename T>
//using WeakPtr = std::weak_ptr<T>;
//
//#define makeShared std::make_shared
//#define allocateShared std::allocate_shared
//
//template<typename T>
//using EnableSharedFromThis = std::enable_shared_from_this<T>;
struct Base {
virtual ~Base() {}
};
struct Derived: public Base {
static int constructed;
static int destructerd;
Derived() {
++constructed;
}
~Derived() {
++destructerd;
}
};
int Derived::constructed = 0;
int Derived::destructerd = 0;
void test_shared_ptr() {
using std::vector;
auto first_ptr = SharedPtr<vector<int>>(new vector<int>(1'000'000));
auto second_ptr = SharedPtr<vector<int>>(new vector<int>(10));
first_ptr.reset(new vector<int>());
second_ptr.reset();
SharedPtr<vector<int>>().swap(first_ptr);
assert(second_ptr.get() == nullptr);
assert(second_ptr.get() == nullptr);
for (int k = 0; k < 2; ++k) {
vector<SharedPtr<int>> ptrs;
for (int i = 0; i < 100'000; ++i) {
int* p = new int(rand() % 99'999);
ptrs.push_back(SharedPtr<int>(p));
}
std::sort(ptrs.begin(), ptrs.end(), [](auto&& x, auto&& y){return *x < *y;});
for (int i = 0; i + 1 < 100'000; ++i) {
assert(*(ptrs[i]) <= *(ptrs[i+1]));
}
while (!ptrs.empty()) {
ptrs.pop_back();
}
}
// test const
{
const SharedPtr<int> sp(new int(42));
assert(sp.use_count() == 1);
assert(*sp.get() == 42);
assert(*sp == 42);
}
}
struct Node;
struct Next {
SharedPtr<Node> shared;
WeakPtr<Node> weak;
Next(const SharedPtr<Node>& shared): shared(shared) {}
Next(const WeakPtr<Node>& weak): weak(weak) {}
};
struct Node {
static int constructed;
static int destructed;
int value;
Next next;
Node(int value): value(value), next(SharedPtr<Node>()) {
++constructed;
}
Node(int value, const SharedPtr<Node>& next): value(value), next(next) {
++constructed;
}
Node(int value, const WeakPtr<Node>& next): value(value), next(next) {
++constructed;
}
~Node() {
++destructed;
}
};
int Node::constructed = 0;
int Node::destructed = 0;
SharedPtr<Node> getCyclePtr(int cycleSize) {
SharedPtr<Node> head(new Node(0));
SharedPtr<Node> prev(head);
for (int i = 1; i < cycleSize; ++i) {
SharedPtr<Node> current(new Node(i));
prev->next.shared = current;
prev = current;
// std::cout << prev.use_count() << '\n';
}
//prev->next.shared.~SharedPtr<Node>();
//new (&prev->next.weak) WeakPtr<Node>(head);
prev->next.weak = head;
//prev->next.isLast = true;
return head;
}
int allocated = 0;
int deallocated = 0;
int allocate_called = 0;
int deallocate_called = 0;
int new_called = 0;
int delete_called = 0;
void test_weak_ptr() {
auto sp = SharedPtr<int>(new int(23));
WeakPtr<int> weak = sp;
{
auto shared = SharedPtr<int>(new int(42));
weak = shared;
assert(weak.use_count() == 1);
assert(!weak.expired());
}
assert(weak.use_count() == 0);
assert(weak.expired());
weak = sp;
auto wp = weak;
assert(weak.use_count() == 1);
assert(wp.use_count() == 1);
auto wwp = std::move(weak);
//assert(weak.use_count() == 0);
assert(wwp.use_count() == 1);
auto ssp = wwp.lock();
assert(sp.use_count() == 2);
sp = ssp;
ssp = sp;
assert(ssp.use_count() == 2);
sp = std::move(ssp);
assert(sp.use_count() == 1);
ssp.reset(); // nothing should happen
sp.reset();
unsigned int useless_value = 0;
for (int i = 0; i < 100'000; ++i) {
SharedPtr<Node> head = getCyclePtr(8);
SharedPtr<Node> nextHead = head->next.shared;
assert(nextHead.use_count() == 2);
useless_value += 19'937 * i * nextHead.use_count();
head.reset();
assert(nextHead.use_count() == 1);
}
assert(Node::constructed == 800'000);
assert(Node::destructed == 800'000);
// test inheritance
{
SharedPtr<Derived> dsp(new Derived());
SharedPtr<Base> bsp = dsp;
WeakPtr<Derived> wdsp = dsp;
WeakPtr<Base> wbsp = dsp;
WeakPtr<Base> wwbsp = wdsp;
assert(dsp.use_count() == 2);
bsp = std::move(dsp);
assert(bsp.use_count() == 1);
bsp.reset();
assert(wdsp.expired());
assert(wbsp.expired());
assert(wwbsp.expired());
}
assert(Derived::constructed == Derived::destructerd);
// test const
new_called = 0;
delete_called = 0;
{
SharedPtr<int> sp(new int(42));
const WeakPtr<int> wp(sp);
assert(!wp.expired());
auto ssp = wp.lock();
}
assert(new_called == 2);
assert(delete_called == 2);
}
struct NeitherDefaultNorCopyConstructible {
NeitherDefaultNorCopyConstructible() = delete;
NeitherDefaultNorCopyConstructible(const NeitherDefaultNorCopyConstructible&) = delete;
NeitherDefaultNorCopyConstructible& operator=(const NeitherDefaultNorCopyConstructible&) = delete;
NeitherDefaultNorCopyConstructible(NeitherDefaultNorCopyConstructible&&) = default;
NeitherDefaultNorCopyConstructible& operator=(NeitherDefaultNorCopyConstructible&&) = default;
explicit NeitherDefaultNorCopyConstructible(int x): x(x) {}
int x;
};
struct Accountant {
static int constructed;
static int destructed;
Accountant() {
++constructed;
}
Accountant(const Accountant&) {
++constructed;
}
~Accountant() {
++destructed;
}
};
int Accountant::constructed = 0;
int Accountant::destructed = 0;
void* operator new(size_t n) {
++new_called;
auto t = std::malloc(n);
return t;
}
void operator delete(void* ptr) {
++delete_called;
std::free(ptr);
}
struct VerySpecialType {};
void* operator new(size_t n, VerySpecialType) {
return std::malloc(n);
}
void operator delete(void* ptr, VerySpecialType) {
std::free(ptr);
}
template<typename T>
struct MyAllocator {
using value_type = T;
MyAllocator() = default;
template<typename U>
MyAllocator(const MyAllocator<U>&) {}
T* allocate(size_t n) {
++allocate_called;
allocated += n * sizeof(T);;
return (T*) ::operator new(n * sizeof(T), VerySpecialType());
}
void deallocate(T* p, size_t n) {
++deallocate_called;
deallocated += n * sizeof(T);
::operator delete((void*)p, VerySpecialType());
}
};
void test_make_allocate_shared() {
new_called = 0;
delete_called = 0;
{
auto sp = makeShared<NeitherDefaultNorCopyConstructible>(
NeitherDefaultNorCopyConstructible(0));
WeakPtr<NeitherDefaultNorCopyConstructible> wp = sp;
auto ssp = sp;
sp.reset();
assert(!wp.expired());
ssp.reset();
assert(wp.expired());
}
new_called = 0;
delete_called = 0;
{
auto sp = makeShared<Accountant>();
assert(Accountant::constructed == 1);
WeakPtr<Accountant> wp = sp;
auto ssp = sp;
sp.reset();
assert(Accountant::constructed == 1);
assert(Accountant::destructed == 0);
assert(!wp.expired());
ssp.reset();
assert(Accountant::destructed == 1);
Accountant::constructed = 0;
Accountant::destructed = 0;
}
new_called = 0;
delete_called = 0;
{
MyAllocator<NeitherDefaultNorCopyConstructible> alloc;
auto sp = allocateShared<NeitherDefaultNorCopyConstructible>(
alloc, NeitherDefaultNorCopyConstructible(0));
int count = allocated;
assert(allocated > 0);
assert(allocate_called == 1);
WeakPtr<NeitherDefaultNorCopyConstructible> wp = sp;
auto ssp = sp;
sp.reset();
assert(count == allocated);
assert(deallocated == 0);
assert(!wp.expired());
ssp.reset();
assert(count == allocated);
}
assert(allocated == deallocated);
assert(allocate_called == 1);
assert(deallocate_called == 1);
allocated = 0;
deallocated = 0;
allocate_called = 0;
deallocate_called = 0;
{
MyAllocator<Accountant> alloc;
auto sp = allocateShared<Accountant>(alloc);
int count = allocated;
assert(allocated > 0);
assert(allocate_called == 1);
assert(Accountant::constructed == 1);
WeakPtr<Accountant> wp = sp;
auto ssp = sp;
sp.reset();
assert(count == allocated);
assert(deallocated == 0);
assert(Accountant::constructed == 1);
assert(Accountant::destructed == 0);
assert(!wp.expired());
ssp.reset();
assert(count == allocated);
}
assert(allocated == deallocated);
assert(Accountant::constructed == 1);
assert(Accountant::destructed == 1);
assert(allocate_called == 1);
assert(deallocate_called == 1);
assert(new_called == 0);
assert(delete_called == 0);
}
//struct Enabled: public EnableSharedFromThis<Enabled> {
// SharedPtr<Enabled> get_shared() {
// return shared_from_this();
// }
//};
//void test_enable_shared_from_this() {
// {
// Enabled e;
// bool caught = false;
// try {
// e.get_shared();
// } catch (...) {
// caught = true;
// }
// assert(caught);
// }
//
// auto esp = makeShared<Enabled>();
//
// auto& e = *esp;
// auto sp = e.get_shared();
//
// assert(sp.use_count() == 2);
//
// esp.reset();
// assert(sp.use_count() == 1);
//
// sp.reset();
//}
struct A {
static int deleted;
virtual ~A() {
++deleted;
}
};
int A::deleted = 0;
struct A1: public A {
static int deleted;
virtual ~A1() {
++deleted;
}
};
int A1::deleted = 0;
struct A2: public A {
static int deleted;
virtual ~A2() {
++deleted;
}
};
int A2::deleted = 0;
struct A11: public A1 {
static int deleted;
virtual ~A11() {
++deleted;
}
};
int A11::deleted = 0;
struct A12: public A1 {
static int deleted;
virtual ~A12() {
++deleted;
}
};
int A12::deleted = 0;
struct A21: public A2 {
static int deleted;
virtual ~A21() {
++deleted;
}
};
int A21::deleted = 0;
struct A22: public A2 {
static int deleted;
virtual ~A22() {
++deleted;
}
};
int A22::deleted = 0;
int destroy_called;
template<typename T>
struct MyAlloc {
using value_type = T;
MyAlloc() = default;
template<typename U>
MyAlloc(const MyAlloc<U>&) {}
void destroy(T* p) {
++destroy_called;
p->~T();
}
T* allocate(size_t n) {
++allocate_called;
allocated += n * sizeof(T);;
return (T*) ::operator new(n * sizeof(T), VerySpecialType());
}
void deallocate(T* p, size_t n) {
++deallocate_called;
deallocated += n * sizeof(T);
::operator delete((void*)p, VerySpecialType());
}
};
void my_test_inheritance_destroy() {
{
SharedPtr<A22> a22 = allocateShared<A22, MyAlloc<A22>>(MyAlloc<A22>());
SharedPtr<A2> a2 = a22;
SharedPtr<A> a = a2;
assert(a.use_count() == 3);
a22.reset();
a.reset();
a = allocateShared<A21, MyAlloc<A21>>(MyAlloc<A21>());
WeakPtr<A> wa = a;
WeakPtr<A> wwa = wa;
a.reset(new A2());
}
assert(A22::deleted == 1);
assert(A21::deleted == 1);
}
void my_test_custom_deleter();
struct T {
~T() {
std::cout << "~" << std::endl;
}
};
int main() {
using namespace std;
std::allocator<T> all;
SharedPtr<T> p(all.allocate(1));
// p.reset();
// SharedPtr<int> p;
p.reset(new T);
p.reset(new T);
p.reset(new T);
p.reset(new T);
p.reset(new T);
p.reset();
std::cout << "alsdkfj" << endl;
// return 0;
static_assert(!std::is_base_of_v<std::shared_ptr<VerySpecialType>, SharedPtr<VerySpecialType>>,
"don't try to use std smart pointers");
// static_assert(!std::is_base_of_v<WeakPtr<VerySpecialType>, WeakPtr<VerySpecialType>>,
// "don't try to use std smart pointers");
//
test_shared_ptr();
std::cout << "1/5 passed" << std::endl;
test_weak_ptr();
std::cout << "2/5 passed" << std::endl;
test_make_allocate_shared();
std::cout << "3/5 passed" << std::endl;
std::cout << "starting my tests" << std::endl;
my_test_inheritance_destroy();
std::cout << "4/5 passed" << std::endl;
my_test_custom_deleter();
std::cout << "5/5 passed" << std::endl;
std::cout << "now it should work" << std::endl;
// test_enable_shared_from_this();
}
template<typename T>
struct MyDeletor {
static int deleted;
void operator()(T* x) {
::delete x;
++deleted;
}
};
template<typename T>
int MyDeletor<T>::deleted = 0;
void my_test_custom_deleter() {
{
SharedPtr<Accountant> p(new Accountant(), MyDeletor<Accountant>());
SharedPtr<Accountant> pp = std::move(p);
std::cout << pp.use_count() << std::endl;
SharedPtr<Accountant> h = pp;
std::cout << h.use_count() << std::endl;
// p = allocateShared<Accountant, MyAlloc<Accountant>>(MyAlloc<Accountant>());
}
std::cout << delete_called << std::endl;
assert(delete_called == 4);
assert(destroy_called == 3);
destroy_called = 0;
{
auto* smth = new Accountant();
SharedPtr<Accountant> p(smth, MyDeletor<Accountant>(), MyAlloc<Accountant>());
SharedPtr<Accountant> pp = std::move(p);
SharedPtr<Accountant> h = pp;
p = allocateShared<Accountant, MyAlloc<Accountant>>(MyAlloc<Accountant>());
}
assert(delete_called == 5);
assert(destroy_called == 1);
}

5
shared_pointer/makefile Executable file
View file

@ -0,0 +1,5 @@
all: main.cpp
g++ -g -Wall -std=c++17 -D LOCAL main.cpp -o a
debug: main.cpp
g++ -g -std=c++17 main.cpp -D LOCAL -o a -Wall -Wextra -pedantic -O2 -Wshadow -Wformat=2 -Wfloat-equal -Wconversion -Wlogical-op -Wshift-overflow=2 -Wduplicated-cond -Wcast-qual -Wcast-align -D_GLIBCXX_DEBUG -D_GLIBCXX_DEBUG_PEDANTIC -D_FORTIFY_SOURCE=2 -fsanitize=address -fsanitize=undefined -fno-sanitize-recover -fstack-protector

View file

@ -0,0 +1,350 @@
#include <memory>
#include <functional>
struct StandardDelete {
template<typename T>
void operator()(T* ptr) {
delete ptr;
}
};
struct Deleter {
virtual void destroy(void*) = 0;
virtual void deallocate(void*) = 0;
virtual ~Deleter() {}
};
template<class T, class Allocator>
struct ObjectManagerBlock : Deleter {
Allocator allocator_;
ObjectManagerBlock(const Allocator& allocator) : allocator_(allocator) {}
void destroy(void* ptr) override {
using ConstructAllocator = typename std::allocator_traits<Allocator>::template rebind_alloc<T>;
using ConstructAllocatorTraits = typename std::allocator_traits<ConstructAllocator>;
ConstructAllocator construct_allocator = allocator_;
ConstructAllocatorTraits::destroy(construct_allocator, static_cast<T*>(ptr));
}
void deallocate(void* ptr) override {
using MemoryAllocator = typename std::allocator_traits<Allocator>::template rebind_alloc<uint8_t>;
using MemoryAllocatorTraits = typename std::allocator_traits<MemoryAllocator>;
MemoryAllocator memory_allocator = allocator_;
MemoryAllocatorTraits::deallocate(memory_allocator,
reinterpret_cast<uint8_t*>(ptr),
sizeof(T) + 2 * sizeof(size_t) + sizeof(Deleter));
}
};
template<class T, class TDeleter, class Allocator>
struct DeleterWithSpecialDeleter : Deleter {
Allocator allocator_;
TDeleter t_deleter_;
DeleterWithSpecialDeleter(const Allocator& allocator, const TDeleter& t_deleter)
: allocator_(allocator), t_deleter_(t_deleter) {}
void destroy(void* ptr) override {
t_deleter_(reinterpret_cast<T*>(ptr));
}
void deallocate(void* ptr) override {
using MemoryAllocator = typename std::allocator_traits<Allocator>::template rebind_alloc<uint8_t>;
using MemoryAllocatorTraits = typename std::allocator_traits<MemoryAllocator>;
MemoryAllocator memory_allocator = allocator_;
MemoryAllocatorTraits::deallocate(memory_allocator,
reinterpret_cast<uint8_t*>(ptr),
2 * sizeof(size_t) + sizeof(Deleter));
}
};
template<class T>
class WeakPtr;
template<class T>
class SharedPtr {
private:
template<class U>
friend
class SharedPtr;
template<class U>
friend
class WeakPtr;
struct TemplateConstructorTag {};
void decrease_counter() {
if (counter_) {
--*counter_;
if (*counter_ == 0) {
deleter_->destroy(value_);
if (*weak_counter_ == 0) {
if (!is_block_) {
deleter_->deallocate(counter_);
} else {
deleter_->deallocate(value_);
}
}
}
}
}
void increase_counter() {
if (counter_) {
++*counter_;
}
}
void reset_without_decrease() {
value_ = nullptr;
counter_ = nullptr;
weak_counter_ = nullptr;
deleter_ = nullptr;
is_block_ = false;
}
public:
~SharedPtr() {
decrease_counter();
}
SharedPtr() {}
SharedPtr(T* ptr) : SharedPtr(ptr, StandardDelete(), std::allocator<size_t>()) {}
template<class TDeleter, class Allocator = std::allocator<size_t>>
SharedPtr(T* ptr, const TDeleter& deleter, Allocator allocator = Allocator()) : SharedPtr() {
reset<Allocator, TDeleter>(ptr, allocator, deleter);
}
template<class Allocator = std::allocator<size_t>, class TDeleter = StandardDelete>
void reset(T* ptr, Allocator allocator = Allocator(), const TDeleter& t_deleter = TDeleter()) {
decrease_counter();
value_ = ptr;
is_block_ = false;
using MemoryAllocator = typename std::allocator_traits<Allocator>::template rebind_alloc<uint8_t>;
using MemoryAllocatorTraits = typename std::allocator_traits<MemoryAllocator>;
MemoryAllocator memory_allocator = allocator;
auto mem = MemoryAllocatorTraits::allocate(memory_allocator, 2 * sizeof(size_t) + sizeof(Deleter));
counter_ = reinterpret_cast<size_t*>(mem);
*counter_ = 1;
weak_counter_ = reinterpret_cast<size_t*>(mem + sizeof(size_t));
*weak_counter_ = 0;
deleter_ = reinterpret_cast<Deleter*>(mem + 2 * sizeof(size_t));
new(deleter_) DeleterWithSpecialDeleter<T, TDeleter, Allocator>(allocator, t_deleter);
}
void reset() {
decrease_counter();
reset_without_decrease();
}
SharedPtr(SharedPtr&& another) : SharedPtr(std::move(another), TemplateConstructorTag()) {}
template<class U>
SharedPtr(SharedPtr<U>&& another, TemplateConstructorTag = TemplateConstructorTag()) {
value_ = std::move(another.value_);
counter_ = std::move(another.counter_);
weak_counter_ = std::move(another.weak_counter_);
deleter_ = std::move(another.deleter_);
is_block_ = another.is_block_;
another.reset_without_decrease();
}
SharedPtr(const SharedPtr& another) : SharedPtr(another, TemplateConstructorTag()) {}
template<class U>
SharedPtr(const SharedPtr<U>& another, TemplateConstructorTag = TemplateConstructorTag()) {
value_ = another.value_;
counter_ = another.counter_;
weak_counter_ = another.weak_counter_;
deleter_ = another.deleter_;
is_block_ = another.is_block_;
increase_counter();
}
SharedPtr& operator=(const SharedPtr& another) {
return operator=<T>(another);
}
template<class U>
SharedPtr& operator=(const SharedPtr<U>& another) {
SharedPtr tmp(another);
swap(tmp);
return *this;
}
SharedPtr& operator=(SharedPtr&& another) {
return operator=<T>(std::move(another));
}
template<class U>
SharedPtr& operator=(SharedPtr<U>&& another) {
SharedPtr tmp(std::move(another));
swap(tmp);
return *this;
}
size_t use_count() const {
return *counter_;
}
T* operator->() {
return value_;
}
T& operator*() {
return *value_;
}
const T& operator*() const {
return *value_;
}
T* get() {
return value_;
}
const T* get() const {
return value_;
}
void swap(SharedPtr<T>& another) {
std::swap(value_, another.value_);
std::swap(counter_, another.counter_);
std::swap(weak_counter_, another.weak_counter_);
std::swap(deleter_, another.deleter_);
std::swap(is_block_, another.is_block_);
}
private:
template<class U, class... Args>
friend SharedPtr<U> makeShared(Args&& ... args);
template<class U, class Alloc, class... Args>
friend SharedPtr<U> allocateShared(const Alloc& alloc, Args&& ... args);
friend WeakPtr<T>;
T* value_ = nullptr;
size_t* counter_ = nullptr;
size_t* weak_counter_ = nullptr;
Deleter* deleter_ = nullptr;
bool is_block_ = false;
template<class Alloc = std::allocator<size_t>>
SharedPtr(T* ptr, size_t* counter, size_t* weak_counter, Deleter* deleter, const Alloc& alloc) :
value_(ptr), counter_(counter), weak_counter_(weak_counter), deleter_(deleter), is_block_(true) {
increase_counter();
new(deleter) ObjectManagerBlock<T, Alloc>(alloc);
}
SharedPtr(T* ptr, size_t* counter, size_t* weak_counter, Deleter* deleter, bool is_block) :
value_(ptr), counter_(counter), weak_counter_(weak_counter), deleter_(deleter), is_block_(is_block) {
increase_counter();
}
};
template<class T>
class WeakPtr {
template<class U>
friend
class WeakPtr;
struct TemplateConstructorTag {};
public:
~WeakPtr() {
decrease_counter();
}
WeakPtr() {}
WeakPtr(const SharedPtr<T>& another) : WeakPtr(another, TemplateConstructorTag()) {}
template<class U>
WeakPtr(const SharedPtr<U>& another, TemplateConstructorTag = TemplateConstructorTag()) {
value_ = another.value_;
counter_ = another.counter_;
weak_counter_ = another.weak_counter_;
deleter_ = another.deleter_;
is_block_ = another.is_block_;
increase_counter();
}
WeakPtr(const WeakPtr& another) : WeakPtr(another, TemplateConstructorTag()) {}
template<class U>
WeakPtr(const WeakPtr<U>& another, TemplateConstructorTag = TemplateConstructorTag()) {
value_ = another.value_;
counter_ = another.counter_;
weak_counter_ = another.weak_counter_;
deleter_ = another.deleter_;
is_block_ = another.is_block_;
increase_counter();
}
size_t use_count() const {
return *counter_;
}
bool expired() const {
return *counter_ == 0;
}
SharedPtr<T> lock() const {
return SharedPtr<T>(value_, counter_, weak_counter_, deleter_, is_block_);
}
WeakPtr& operator=(const WeakPtr& another) {
WeakPtr tmp(another);
swap(tmp);
return *this;
}
WeakPtr& operator=(WeakPtr&& another) {
WeakPtr tmp(another);
swap(tmp);
return *this;
}
WeakPtr& operator=(const SharedPtr<T>& another) {
WeakPtr tmp(another);
swap(tmp);
return *this;
}
private:
void decrease_counter() {
if (weak_counter_) {
--*weak_counter_;
if (*counter_ == 0 && *weak_counter_ == 0) {
if (!is_block_) {
deleter_->deallocate(counter_);
} else {
deleter_->deallocate(value_);
}
}
}
}
void increase_counter() {
if (weak_counter_) {
++*weak_counter_;
}
}
void swap(WeakPtr& another) {
std::swap(value_, another.value_);
std::swap(counter_, another.counter_);
std::swap(weak_counter_, another.weak_counter_);
std::swap(deleter_, another.deleter_);
}
T* value_ = nullptr;
size_t* counter_ = nullptr;
size_t* weak_counter_ = nullptr;
Deleter* deleter_ = nullptr;
bool is_block_ = false;
};
template<typename T, typename Alloc, typename... Args>
SharedPtr<T> allocateShared(const Alloc& alloc, Args&& ... args) {
using MemoryAllocator = typename std::allocator_traits<Alloc>::template rebind_alloc<uint8_t>;
using MemoryAllocatorTraits = typename std::allocator_traits<MemoryAllocator>;
MemoryAllocator memory_allocator = alloc;
auto ptr = MemoryAllocatorTraits::allocate(memory_allocator, sizeof(T) + 2 * sizeof(size_t) + sizeof(Deleter));
using ConstructAllocator = typename std::allocator_traits<Alloc>::template rebind_alloc<T>;
using ConstructAllocatorTraits = typename std::allocator_traits<ConstructAllocator>;
ConstructAllocator construct_allocator = alloc;
ConstructAllocatorTraits::construct(construct_allocator, (T*) ptr, std::forward<Args>(args)...);
*(size_t*) (ptr + sizeof(T)) = 0;
*(size_t*) (ptr + sizeof(T) + sizeof(size_t)) = 0;
return SharedPtr<T>((T*) ptr, (size_t*) (ptr + sizeof(T)), (size_t*) (ptr + sizeof(T) + sizeof(size_t)),
(Deleter*) (ptr + sizeof(T) + 2 * sizeof(size_t)), alloc);
}
template<class T, typename... Args>
SharedPtr<T> makeShared(Args&& ... args) {
return allocateShared<T>(std::allocator<T>(), std::forward<Args>(args)...);
}

10
string/main.cpp Normal file
View file

@ -0,0 +1,10 @@
#include <iostream>
#include "string.h"
using namespace std;
int main() {
String s = "$$#$##$#$####$#$$$#";
return 0;
}

2
string/makefile Normal file
View file

@ -0,0 +1,2 @@
all:
g++ main.cpp -Wall -Wextra -o a

184
string/string.h Normal file
View file

@ -0,0 +1,184 @@
#include <cstring>
#include <sstream>
class String {
private:
size_t capacity_ = 0;
size_t size_ = 0;
char* t_ = nullptr;
void realloc() {
if (4 * size_ <= capacity_) {
reserve(size_ * 2);
}
}
void realloc(size_t capacity) {
if (capacity > capacity_) {
reserve(capacity * 2);
}
}
public:
~String() { delete[] t_; }
String() = default;
String(char x) {
size_ = 0;
capacity_ = 1;
t_ = new char[capacity_];
t_[size_++] = x;
}
String(const char* t) {
size_ = strlen(t);
capacity_ = size_;
t_ = new char[capacity_];
memcpy(t_, t, size_ * sizeof(char));
}
String(size_t n, char c) : capacity_(n), size_(n), t_(new char[capacity_]) {
memset(t_, c, size_ * sizeof(char));
}
String(const String& s)
: capacity_(s.size_), size_(s.size_), t_(new char[capacity_]) {
memcpy(t_, s.t_, size_ * sizeof(char));
}
void swap(String& s) {
std::swap(capacity_, s.capacity_);
std::swap(size_, s.size_);
std::swap(t_, s.t_);
}
String& operator=(const String& s) {
String copy(s);
swap(copy);
return *this;
}
bool operator==(const String& s) const {
if (size_ != s.size_) return false;
for (size_t i = 0; i < size_; ++i) {
if (t_[i] != s.t_[i]) return false;
}
return true;
}
char& operator[](size_t x) { return t_[x]; }
char operator[](size_t x) const { return t_[x]; }
size_t length() const { return size_; }
char& front() { return t_[0]; }
const char& front() const { return t_[0]; }
char& back() { return t_[size_ - 1]; }
const char& back() const { return t_[size_ - 1]; }
void reserve(size_t capacity) {
char* p = new char[capacity];
capacity_ = capacity;
if (t_) {
size_ = std::min(size_, capacity);
memcpy(p, t_, size_ * sizeof(char));
delete[] t_;
}
t_ = p;
}
void push_back(char x) {
realloc(size_ + 1);
t_[size_++] = x;
}
void pop_back() {
size_--;
realloc();
}
String& operator+=(const String& s) {
realloc(size_ + s.size_);
memcpy(t_ + size_, s.t_, s.size_ * sizeof(char));
size_ += s.size_;
return *this;
}
size_t find(const String& s) const {
for (size_t i = 0; i < size_ - s.size_ + 1; ++i) {
bool is_equal = true;
for (size_t j = 0; j < s.size_; ++j) {
if (t_[i + j] != s.t_[j]) is_equal = false;
}
if (is_equal) {
return i;
}
}
return size_;
}
size_t rfind(const String& s) const {
for (size_t i = size_ - 1; i >= s.size_; --i) {
bool is_equal = true;
for (int j = s.size_; j--;) {
if (t_[i - s.size_ + j + 1] != s.t_[j]) is_equal = false;
}
if (is_equal) {
return i - s.size_ + 1;
}
}
return size_;
}
String substr(size_t i, size_t count) const {
String s;
s.reserve(count);
memcpy(s.t_, t_ + i, count * sizeof(char));
s.size_ = count;
return s;
}
bool empty() { return size_ == 0; }
void clear() {
size_ = 0;
delete[] t_;
t_ = nullptr;
capacity_ = 0;
}
};
String operator+(const String& s, const String& g) {
String res = s;
res += g;
return res;
}
std::istream& operator>>(std::istream& in, String& s) {
s.clear();
char x;
in >> x;
while (!in.eof()) {
if (std::isspace(x)) break;
s.push_back(x);
x = in.get();
}
return in;
}
std::ostream& operator<<(std::ostream& out, const String& s) {
for (size_t i = 0; i < s.length(); ++i) {
out << s[i];
}
return out;
}

13
variant/CMakeLists.txt Normal file
View file

@ -0,0 +1,13 @@
cmake_minimum_required(VERSION 3.10)
#project("Variant")
set(SOURCE_FILES main.cpp)
#set(CMAKE_CXX_FLAGS "-Ofast -Wall -Wextra")
set(CMAKE_CXX_COMPILER g++)
set(CMAKE_CXX_STANDARD 17)
add_executable(map ${SOURCE_FILES})

259
variant/main.cpp Normal file
View file

@ -0,0 +1,259 @@
#include <iostream>
#include <cstring>
#include <cassert>
#include <vector>
#include <variant>
#include "variant.h"
using std::cin;
using std::cout;
using std::endl;
/*
using std::get;
using std::holds_alternative;
template<typename... Types>
using Variant = std::variant<Types...>;
*/
struct A {
A() {
cout << "construct ()" << endl;
}
A(const A&) {
cout << "construct (const A&)" << endl;
}
A(A&& a) {
cout << "A(&&)" << endl;
}
A& operator=(const A&) {
cout << "operator= (const A&)" << endl;
return *this;
}
A& operator=(A&& another) {
cout << "=&&" << endl;
return *this;
}
~A() {
cout << "~A()" << endl;
}
};
void compile_test() {
int x;
{
Variant<int, double> v(1.0);
const Variant<int, double> cv(1.0);
Variant<std::vector<int>> vv;
holds_alternative<double>(v);
get<double>(v);
get<double>(cv);
static_assert(!std::is_assignable_v<decltype(v), std::vector<int>>);
// static_assert(!std::is_assignable_v<decltype(vv), int>);
static_assert(!std::is_assignable_v<Variant < float, int>, double > );
static_assert(!std::is_assignable_v<decltype(get<double>(cv)), double>);
static_assert(std::is_rvalue_reference_v<decltype(get<double>(std::move(v)))>);
static_assert(std::is_lvalue_reference_v<decltype(get<double>(v))>);
}
{
Variant<std::string> v = "abcdefgh";
v = "lakjdflksd";
v = std::string("alksdjfasf");
Variant<std::string> vv("abcdefgh");
assert(get<std::string>(vv).size() == 8);
Variant<std::string, char, std::vector<int>> vvv = "abcdefgh";
Variant<std::string, char, std::vector<int>> vvvv("abcdefgh");
Variant<std::string> vvvvv(std::string("alskdjflaksf"));
Variant<std::string> vvvvvv = std::string("alskdjflaksf");
}
{
// У тебя должен быть
// template<typename T, typename U, typename... Args>
// void emplace(std::initializer_list<U>, Args&&...);
//
// https://en.cppreference.com/w/cpp/utility/variant/emplace
using vec = std::vector<int>;
Variant<vec> v;
vec& a = v.emplace<std::vector<int>>({1, 2, 3});
// Также долежн быть emplace по индексу
vec& b = v.emplace<0>(std::vector<int>(2));
// Также долежн быть emplace по индексу и std::initializer_list :)
vec& c = v.emplace<0>({1, 2, 3});
}
{
Variant<const int> v;
// Пока хз как это решить
// static_assert(!std::is_assignable_v<decltype(v), int>);
// v = 10;
}
{
Variant<const int, std::string, const std::string, double> v = 1;
Variant<int, double> vvv = 1.0f;
std::variant<int, double> vv = 1.0f;
std::cout << std::is_constructible_v<int, float> << std::endl;
}
cout << "compile test passed" << endl;
}
void test1() {
int x;
{
const Variant<A, int> v(10);
std::cout << get<int>(v) << std::endl;
assert(get<int>(v) == 10);
{
int cnt_try = 0;
try {
get<A>(v);
} catch (...) {
cnt_try++;
}
try {
get<0>(v);
} catch (...) {
cnt_try++;
}
assert(cnt_try == 2);
}
}
{
Variant<A, int> v(10);
assert(get<int>(v) == 10);
v = 11;
assert(get<int>(v) == 11);
get<int>(v)++;
assert(get<int>(v) == 12);
}
{
Variant<std::vector<int>> v;
// assert(v.valueless_by_exception());
}
cout << "test1 passed" << endl;
}
void string_test() {
Variant<std::string> v = "abcdefgh";
assert(v.index() == 0);
v = "lakjdflksd";
assert(get<std::string>(v).size() == 10);
assert(v.index() == 0);
v = std::string("a");
assert(get<std::string>(v).size() == 1);
assert(v.index() == 0);
Variant<std::string> vv("ab");
assert(get<std::string>(vv).size() == 2);
assert(vv.index() == 0);
vv = "als";
assert(get<std::string>(vv).size() == 3);
assert(vv.index() == 0);
vv = std::string("alsd");
assert(get<std::string>(vv).size() == 4);
assert(vv.index() == 0);
Variant<std::string, char, std::vector<int>> vvv = "abcdefgh";
assert(vvv.index() == 0);
vvv = "alksjdgasg";
assert(vvv.index() == 0);
vvv = "alskdjglkagj";
assert(vvv.index() == 0);
Variant<std::string, char, std::vector<int>> vvvv("abcdefgh");
assert(vvvv.index() == 0);
vvvv = "asljgs;lgdk";
assert(vvvv.index() == 0);
vvvv = "al;kdja;k";
assert(vvvv.index() == 0);
Variant<std::string> vvvvv(std::string("alskdjflaksf"));
assert(vvvvv.index() == 0);
vvvvv = "a;kjga;g";
assert(vvvvv.index() == 0);
vvvvv = "asdjg;alkjg;alkjg";
assert(vvvvv.index() == 0);
Variant<std::string> vvvvvv = std::string("alskdjflaksf");
assert(vvvvvv.index() == 0);
vvvvvv = "askjga;j";
assert(vvvvvv.index() == 0);
vvvvvv = "a;lkjdg;aldjg";
assert(vvvvvv.index() == 0);
cout << "string test passed" << endl;
}
int testConstr = 0;
int testDestroy = 0;
template<size_t N>
struct TestDelete {
TestDelete() { testConstr++; }
~TestDelete() { ++testDestroy; }
};
int countDelete = 0;
void operator delete[](void* ptr) {
countDelete++;
}
void operator delete(void* ptr) {
countDelete++;
}
void test2() {
countDelete = 0;
{
Variant<TestDelete<0>, TestDelete<1>, TestDelete<2>> v;
}
// assert(testDestroy == 1);
assert(testConstr == 1);
// assert(countDelete == 1);
{
std::variant<TestDelete<0>, TestDelete<1>, TestDelete<2>> v;
v = TestDelete<1>();
v = TestDelete<2>();
}
// assert(testDestroy == 6);
assert(testConstr == 4);
std::cout << countDelete << std::endl;
// assert(countDelete == 2);
std::cout << "test2 passed" << std::endl;
}
void test3() {
using VAR = Variant<std::string, int>;
VAR x = "ddd";
{
VAR v("als");
x = std::move(v);
}
std::cout << get<0>(x) << std::endl;
assert(get<0>(x) == "als");
std::cout << "test3 passed";
}
void test4() {
{
Variant<const int, const double> v = 1.0;
assert(v.index() == 1);
}
{
Variant<const int, const double> v = 1.0f;
assert(v.index() == 1);
}
{
Variant<const int, const double> v = 1;
assert(v.index() == 0);
}
{
Variant<const int, const double> v = 'a';
assert(v.index() == 0);
}
}
int main() {
compile_test();
test1();
string_test();
test2();
test3();
test4();
// std::variant<int, int, double> v;
// get<int>(v) = 10;
}

5
variant/makefile Executable file
View file

@ -0,0 +1,5 @@
all: main.cpp
g++ -g -Wall -std=c++17 -D LOCAL main.cpp -o a
debug: main.cpp
g++ -g -std=c++17 main.cpp -D LOCAL -o a -Wall -Wextra -pedantic -O2 -Wshadow -Wformat=2 -Wfloat-equal -Wconversion -Wlogical-op -Wshift-overflow=2 -Wduplicated-cond -Wcast-qual -Wcast-align -D_GLIBCXX_DEBUG -D_GLIBCXX_DEBUG_PEDANTIC -D_FORTIFY_SOURCE=2 -fsanitize=address -fsanitize=undefined -fno-sanitize-recover -fstack-protector

343
variant/variant.h Normal file
View file

@ -0,0 +1,343 @@
#include <cstring>
template <typename T, typename ...Types>
struct get_index_by_type {
static const size_t value = -1;
};
template <typename T, typename Head, typename ...Tail>
struct get_index_by_type<T, Head, Tail...> {
static const size_t value = std::is_same_v<T, Head> ? 0 : get_index_by_type<T, Tail...>::value + 1;
};
template<typename T, typename ...Tail>
static const size_t get_index_by_type_v = get_index_by_type<T, Tail...>::value;
template<typename T, typename... Types>
struct t_is_on_of_types {
static const bool value = false;
};
template<typename T, typename Head, typename... Tail>
struct t_is_on_of_types<T, Head, Tail...> {
static const bool value = std::is_same_v<T, Head> || t_is_on_of_types<T, Tail...>::value;
};
template<typename T, typename... Types>
static const bool t_is_on_of_types_v = t_is_on_of_types<T, Types...>::value;
template<size_t N, typename... Types>
struct get_type_by_index {};
template<typename T, typename... Types>
struct get_type_by_index<0, T, Types...> {
using value = T;
};
template<size_t N, typename T, typename... Types>
struct get_type_by_index<N, T, Types...> {
using value = typename get_type_by_index<N - 1, Types...>::value;
};
template<typename T, typename... Types>
struct count_types_in_package {};
template<typename T, typename Head, typename... Tail>
struct count_types_in_package<T, Head, Tail...> {
static const size_t value = std::is_same_v<T, Head> + count_types_in_package<T, Tail...>::value;
};
template<typename T>
struct count_types_in_package<T> {
static const size_t value = 0;
};
template<size_t N, typename... Types>
using get_type_by_index_v = typename get_type_by_index<N, Types...>::value;
template<typename... Types>
struct get_max_size {
static const size_t value = 0;
};
template<typename Head, typename... Tail>
struct get_max_size<Head, Tail...> {
static const size_t value = std::max(sizeof(Head), get_max_size<Tail...>::value);
};
template<typename... Types>
static const size_t get_max_size_v = get_max_size<Types...>::value;
template <typename ...Types>
class Variant;
template<typename T, typename... Types>
struct VariantAlternative;
template<typename T, typename... Types>
struct VariantAlternative {
public:
VariantAlternative() {}
VariantAlternative(const VariantAlternative&) {}
VariantAlternative(const T& value) {
auto* me = std::launder(static_cast<Variant<Types...>*>(this));
me->index_ = get_index_by_type_v<T, Types...>;
new(me->object_) T(value);
}
VariantAlternative(T&& value) {
auto* me = std::launder(static_cast<Variant<Types...>*>(this));
me->index_ = get_index_by_type_v<T, Types...>;
new(me->object_) T(std::move(value));
}
VariantAlternative& operator=(const T& value) {
auto* me = std::launder(static_cast<Variant<Types...>*>(this));
me->destroy();
me->index_ = get_index_by_type_v<T, Types...>;
new(me->object_) T(value);
return *this;
}
VariantAlternative& operator=(T&& value) {
auto* me = static_cast<Variant<Types...>*>(this);
me->destroy();
me->index_ = get_index_by_type_v<T, Types...>;
new(me->object_) T(std::move(value));
return *this;
}
template<typename K, typename U = T, std::enable_if_t<!std::is_convertible_v<U, K> && std::is_constructible_v<U, K>, bool> = true>
VariantAlternative(const K& value) {
auto* me = std::launder(static_cast<Variant<Types...>*>(this));
me->index_ = get_index_by_type_v<T, Types...>;
me->index_ = get_index_by_type_v<T, Types...>;
new(me->object_) T(value);
}
template<typename K, typename U = T, std::enable_if_t<!std::is_convertible_v<U, K> && std::is_constructible_v<U, K>, bool> = true>
VariantAlternative(K&& value) {
auto* me = std::launder(static_cast<Variant<Types...>*>(this));
me->index_ = get_index_by_type_v<T, Types...>;
me->index_ = get_index_by_type_v<T, Types...>;
new(me->object_) T(std::forward<K>(value));
}
template<typename K, typename U = T, std::enable_if_t<!std::is_convertible_v<U, K> && std::is_assignable_v<U, K>, bool> = true>
VariantAlternative& operator=(const K& value) {
auto* me = static_cast<Variant<Types...>*>(this);
me->destroy();
me->index_ = get_index_by_type_v<T, Types...>;
new(me->object_) T(value);
return *this;
}
template<typename K, typename U = T, std::enable_if_t<!std::is_convertible_v<U, K> && std::is_assignable_v<U, K>, bool> = true>
VariantAlternative& operator=(K&& value) {
auto* me = static_cast<Variant<Types...>*>(this);
me->destroy();
me->index_ = get_index_by_type_v<T, Types...>;
new(me->object_) T(std::forward<K>(value));
return *this;
}
~VariantAlternative() {
auto* me = static_cast<Variant<Types...>*>(this);
if (get_index_by_type_v<T, Types...> == me->index_) {
me->destroy();
}
}
};
template<typename T, typename... TTypes>
bool holds_alternative(const Variant<TTypes...>& another) {
return another.template holds_alternative<T>();
}
template<typename T, typename... TTypes>
const T& get(const Variant<TTypes...>& another) {
static_assert(t_is_on_of_types_v<T, TTypes...>);
static_assert(count_types_in_package<T, TTypes...>::value == 1);
if (another.template holds_alternative<T>()) {
return *reinterpret_cast<T*>(std::launder(const_cast<Variant<TTypes...>&>(another).object_));
} else {
throw std::bad_cast();
}
}
template<typename T, typename... TTypes>
T& get(Variant<TTypes...>& another) {
return const_cast<T&>(get<T>(const_cast<const Variant<TTypes...>&>(another)));
}
template<typename T, typename... TTypes>
T&& get(Variant<TTypes...>&& another) {
return std::move(const_cast<T>(get<T>(const_cast<const Variant<TTypes...>&>(another))));
}
template<size_t N, typename... TTypes>
const get_type_by_index_v<N, TTypes...>& get(const Variant<TTypes...>& another) {
return get<get_type_by_index_v<N, TTypes...>>(another);
}
template<size_t N, typename... TTypes>
get_type_by_index_v<N, TTypes...>& get(Variant<TTypes...>& another) {
using R = get_type_by_index_v<N, TTypes...>;
return const_cast<R&>(get<R>(const_cast<const Variant<TTypes...>&>(another)));
}
template<size_t N, typename... TTypes>
get_type_by_index_v<N, TTypes...>&& get(Variant<TTypes...>&& another) {
using R = get_type_by_index_v<N, TTypes...>;
return std::move(const_cast<R>(get<R>(const_cast<const Variant<TTypes...>&>(another))));
}
template <typename ...Types>
class Variant : public VariantAlternative<Types, Types...>... {
template<typename TT, typename... TTypes>
friend class VariantAlternative;
private:
static const size_t size_variant = get_max_size_v<Types...>;
alignas(Types...) int8_t object_[size_variant];
size_t index_;
template<class T>
bool holds_alternative() const {
if (get_index_by_type_v<T, Types...> == -1)
throw std::bad_cast();
else
return get_index_by_type_v<T, Types...> == index_;
}
template<size_t N = 0>
void destroy() {
if (index_ == N) {
index_ = -1;
using R = get_type_by_index_v<N, Types...>;
reinterpret_cast<R*>(object_)->~R();
} else {
if constexpr (N + 1 < sizeof...(Types)) {
destroy<N + 1>();
}
}
}
template<size_t N = 0>
void copy_constructor(const Variant& another) {
if (another.index_ == N) {
using R = get_type_by_index_v<N, Types...>;
new(object_) R(*reinterpret_cast<R const*>(std::launder(another.object_)));
index_ = another.index_;
} else {
if constexpr (N + 1 < sizeof...(Types)) {
copy_constructor<N + 1>(another);
}
}
}
template<size_t N = 0>
void move_constructor(Variant&& another) {
if (this == &another) return;
if (another.index_ == N) {
using R = get_type_by_index_v<N, Types...>;
new(object_) R(std::move(*reinterpret_cast<R*>(std::launder(another.object_))));
index_ = another.index_;
} else {
if constexpr (N + 1 < sizeof...(Types)) {
move_constructor<N + 1>(std::move(another));
}
}
}
template<size_t N = 0, size_t M = 0>
void swap(Variant& another) {
if (index_ == N && another.index_ == M) {
using R = get_type_by_index_v<N, Types...>;
using S = get_type_by_index_v<M, Types...>;
S tmp(std::move(*reinterpret_cast<S*>(another.object_)));
new(another.object_) R(std::move(*reinterpret_cast<R*>(object_)));
new(object_) S(std::move(tmp));
std::swap(index_, another.index_);
} else if (index_ != N) {
if constexpr(N + 1 < sizeof...(Types))
swap<N + 1, M>(another);
} else {
if constexpr(M + 1 < sizeof...(Types))
swap<N, M + 1>(another);
}
}
public:
using VariantAlternative<Types, Types...>::operator=...;
using VariantAlternative<Types, Types...>::VariantAlternative...;
Variant() : index_(0) {
new(object_) get_type_by_index_v<0, Types...>();
}
Variant(Variant&& another) {
move_constructor(std::move(another));
}
Variant(const Variant& another) : Variant() {
copy_constructor(another);
}
Variant& operator=(const Variant& another) {
Variant tmp(another);
swap(tmp);
return *this;
}
Variant& operator=(Variant&& another) noexcept {
if (&another == this) return *this;
Variant tmp(std::move(another));
swap(tmp);
return *this;
}
template<typename T, typename... Args>
T& emplace(Args&&... args) {
destroy();
index_ = get_index_by_type_v<T, Types...>;
new(object_) T(std::forward<Args...>(args)...);
return *reinterpret_cast<T*>(object_);
}
template<size_t I, typename... Args>
get_type_by_index_v<I, Types...>& emplace(Args&&... args) {
using T = get_type_by_index_v<I, Types...>;
destroy();
index_ = get_index_by_type_v<T, Types...>;
new(object_) T(std::forward<Args...>(args)...);
return *reinterpret_cast<T*>(object_);
}
template<typename T, typename U, typename... Args>
T& emplace(std::initializer_list<U> il, Args&&... args) {
destroy();
index_ = get_index_by_type_v<T, Types...>;
new(object_) T(il, std::forward<Args...>(args)...);
return *reinterpret_cast<T*>(object_);
}
template<size_t I, typename U, typename... Args>
get_type_by_index_v<I, Types...>& emplace(std::initializer_list<U> il, Args&&... args) {
using T = get_type_by_index_v<I, Types...>;
destroy();
index_ = get_index_by_type_v<T, Types...>;
new(object_) T(il, std::forward<Args...>(args)...);
return *reinterpret_cast<T*>(object_);
}
size_t index() const {
return index_;
}
bool valueless_by_exception() const {
return index_ == -1;
}
template<typename T, typename... TTypes>
friend bool holds_alternative(const Variant<TTypes...>& another);
template<typename T, typename... TTypes>
friend const T& get(const Variant<TTypes...>& another);
template<typename T, typename... TTypes>
friend T& get(Variant<TTypes...>& another);
template<typename T, typename... TTypes>
friend T&& get(Variant<TTypes...>&& another);
template<size_t N, typename... TTypes>
friend const get_type_by_index_v<N, TTypes...>& get(const Variant<TTypes...>& another);
template<size_t N, typename... TTypes>
friend get_type_by_index_v<N, TTypes...>& get(Variant<TTypes...>& another);
template<size_t N, typename... TTypes>
friend get_type_by_index_v<N, TTypes...>&& get(Variant<TTypes...>&& another);
};