From 46288f0f07f85f6d28a3f59e4c253db0932672c2 Mon Sep 17 00:00:00 2001 From: MaxanRus Date: Sun, 16 Jul 2023 10:03:47 +0300 Subject: [PATCH] init --- avl/main.cpp | 121 +++ biginteger/biginteger.h | 638 +++++++++++++++ biginteger/main.cpp | 35 + biginteger/makefile | 5 + biginteger/save1.h | 633 +++++++++++++++ biginteger/test.py | 21 + deque/main.cpp | 32 + deque/makefile | 5 + geometry/main.cpp | 14 + geometry/makefile | 2 + list/CMakeLists.txt | 9 + list/fastallocator.h | 308 ++++++++ list/main.cpp | 136 ++++ map/CMakeLists.txt | 11 + map/fastallocator.h | 302 ++++++++ map/main.cpp | 385 +++++++++ map/makefile | 5 + map/unordered_map.h | 571 ++++++++++++++ matrix/main.cpp | 49 ++ matrix/makefile | 5 + matrix/matrix.h | 1286 +++++++++++++++++++++++++++++++ matrix/matrix2.h | 968 +++++++++++++++++++++++ residue/Makefile | 2 + residue/main.cpp | 9 + residue/residue.h | 244 ++++++ shared_pointer/CMakeLists.txt | 11 + shared_pointer/main.cpp | 600 ++++++++++++++ shared_pointer/makefile | 5 + shared_pointer/smart_pointers.h | 350 +++++++++ string/main.cpp | 10 + string/makefile | 2 + string/string.h | 184 +++++ variant/CMakeLists.txt | 13 + variant/main.cpp | 259 +++++++ variant/makefile | 5 + variant/variant.h | 343 +++++++++ 36 files changed, 7578 insertions(+) create mode 100644 avl/main.cpp create mode 100644 biginteger/biginteger.h create mode 100644 biginteger/main.cpp create mode 100644 biginteger/makefile create mode 100644 biginteger/save1.h create mode 100644 biginteger/test.py create mode 100644 deque/main.cpp create mode 100644 deque/makefile create mode 100644 geometry/main.cpp create mode 100644 geometry/makefile create mode 100644 list/CMakeLists.txt create mode 100644 list/fastallocator.h create mode 100644 list/main.cpp create mode 100644 map/CMakeLists.txt create mode 100644 map/fastallocator.h create mode 100644 map/main.cpp create mode 100755 map/makefile create mode 100644 map/unordered_map.h create mode 100644 matrix/main.cpp create mode 100755 matrix/makefile create mode 100644 matrix/matrix.h create mode 100644 matrix/matrix2.h create mode 100644 residue/Makefile create mode 100644 residue/main.cpp create mode 100644 residue/residue.h create mode 100644 shared_pointer/CMakeLists.txt create mode 100644 shared_pointer/main.cpp create mode 100755 shared_pointer/makefile create mode 100644 shared_pointer/smart_pointers.h create mode 100644 string/main.cpp create mode 100644 string/makefile create mode 100644 string/string.h create mode 100644 variant/CMakeLists.txt create mode 100644 variant/main.cpp create mode 100755 variant/makefile create mode 100644 variant/variant.h diff --git a/avl/main.cpp b/avl/main.cpp new file mode 100644 index 0000000..c89fc7d --- /dev/null +++ b/avl/main.cpp @@ -0,0 +1,121 @@ +#include + +template +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 a; + a.insert(10); +} diff --git a/biginteger/biginteger.h b/biginteger/biginteger.h new file mode 100644 index 0000000..fef5d8b --- /dev/null +++ b/biginteger/biginteger.h @@ -0,0 +1,638 @@ +#include +#include +#include +#include +#include +#include + +namespace FastFourierTransform { +typedef double ld; +typedef std::complex cld; +typedef std::vector ComplexPolynom; + +const ld PI = acosl(-1); +std::vector Muliplication(const std::vector& a, + const std::vector& b, + std::vector& result); +ComplexPolynom ToComplex(const std::vector& a); +void FastFourierTransform_(ComplexPolynom& a, bool invert); + +std::vector Muliplication(const std::vector& a, + const std::vector& b, + std::vector& 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 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& 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 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 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(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 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); } diff --git a/biginteger/main.cpp b/biginteger/main.cpp new file mode 100644 index 0000000..3196490 --- /dev/null +++ b/biginteger/main.cpp @@ -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; +} diff --git a/biginteger/makefile b/biginteger/makefile new file mode 100644 index 0000000..be0e3af --- /dev/null +++ b/biginteger/makefile @@ -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 diff --git a/biginteger/save1.h b/biginteger/save1.h new file mode 100644 index 0000000..fa700fc --- /dev/null +++ b/biginteger/save1.h @@ -0,0 +1,633 @@ +#include +#include +#include +#include +#include +#include + +namespace FastFourierTransform { +typedef double ld; +typedef std::complex cld; +typedef std::vector ComplexPolynom; + +const ld PI = acosl(-1); +std::vector Muliplication(const std::vector& a, const std::vector& b, + std::vector& result); +ComplexPolynom ToComplex(const std::vector& a); +void FastFourierTransform_(ComplexPolynom& a, bool invert); + +std::vector Muliplication(const std::vector& a, + const std::vector& b, + std::vector& 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 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& 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 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 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(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 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); } diff --git a/biginteger/test.py b/biginteger/test.py new file mode 100644 index 0000000..4c531f4 --- /dev/null +++ b/biginteger/test.py @@ -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) diff --git a/deque/main.cpp b/deque/main.cpp new file mode 100644 index 0000000..89d506c --- /dev/null +++ b/deque/main.cpp @@ -0,0 +1,32 @@ +#include "deque.h" + +#include +using namespace std; + +int main() { + Deque 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] << " "; + } +} diff --git a/deque/makefile b/deque/makefile new file mode 100644 index 0000000..be0e3af --- /dev/null +++ b/deque/makefile @@ -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 diff --git a/geometry/main.cpp b/geometry/main.cpp new file mode 100644 index 0000000..0c32faf --- /dev/null +++ b/geometry/main.cpp @@ -0,0 +1,14 @@ +#include +#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; +} diff --git a/geometry/makefile b/geometry/makefile new file mode 100644 index 0000000..1361b93 --- /dev/null +++ b/geometry/makefile @@ -0,0 +1,2 @@ +all: + g++ main.cpp -DLOCAL -Wextra -Wall -o a diff --git a/list/CMakeLists.txt b/list/CMakeLists.txt new file mode 100644 index 0000000..19ffae4 --- /dev/null +++ b/list/CMakeLists.txt @@ -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}) diff --git a/list/fastallocator.h b/list/fastallocator.h new file mode 100644 index 0000000..3a327e5 --- /dev/null +++ b/list/fastallocator.h @@ -0,0 +1,308 @@ +#include +#include +#include + +template +class FixedAllocator { + private: + static const int count_chunks = 16; + static inline std::vector 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(tmp + i * chunkSize)); + } + void* tmp = free.back(); + free.pop_back(); + return tmp; + } + + static void deallocate(void* p) { + free.push_back(p); + } +}; + +template +class FastAllocator { + public: + using value_type = T; + FastAllocator() = default; + + template + FastAllocator(const FastAllocator&) {} + + template + FastAllocator& operator=(const FastAllocator&) const { return *this; } + + [[nodiscard]] T* allocate(size_t n) { + if (n * sizeof(T) > kSizeBigBlock) + return reinterpret_cast(new char[n * sizeof(T)]); + else { + return reinterpret_cast(allocate_template_for(sizeof(T) * n)); + } + } + + void deallocate(T* p, size_t n) { + if (n * sizeof(T) > 48) + delete[] reinterpret_cast(p); + else + deallocate_template_for(p, n * sizeof(T)); + } + private: + static const size_t kSizeBigBlock = 48; + + template + [[nodiscard]] void* allocate_template_for(size_t n) { + if (x == n) { + return FixedAllocator::allocate(); + } else { + if constexpr (x < end) { + return allocate_template_for(n); + } + } + return nullptr; + } + + template + void deallocate_template_for(void* ptr, size_t n) { + if (x == n) { + FixedAllocator::deallocate(ptr); + } else { + if constexpr (x < end) { + deallocate_template_for(ptr, n); + } + } + } + +}; + +template +bool operator==(const FastAllocator& a, const FastAllocator& b) { + return &a == &b; +} + +template +bool operator!=(const FastAllocator& a, const FastAllocator& b) { + return !(a == b); +} + +template> +class List { + private: + class Node; + + template + class base_iterator; + public: + using iterator = base_iterator; + using const_iterator = base_iterator; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_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::construct(alloc_, tmp, value); + Link(const_cast(std::prev(it).it), tmp); + ++size_; + } + + void erase(const_iterator it) { + Node* tmp = const_cast(it.it); + tmp->l->r = tmp->r; + tmp->r->l = tmp->l; + std::allocator_traits::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 + class base_iterator { + friend List; + std::conditional_t it; + using U = std::conditional_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() { return base_iterator(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& 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::template rebind_alloc alloc_; + using alloc_traits_ = std::allocator_traits; + Node* end_ = nullptr; + size_t size_ = 0; +}; diff --git a/list/main.cpp b/list/main.cpp new file mode 100644 index 0000000..af260f3 --- /dev/null +++ b/list/main.cpp @@ -0,0 +1,136 @@ +#include +#include "fastallocator.h" + +using namespace std; +template +struct C1 { + static inline vector 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> l(N); + list> t(N); + + assert(C1<0>::v == C1<1>::v); + + List> ll(N, C1<0>(10)); + list> 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> lll = l; + list> 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> x; + x.push_back(10); +} diff --git a/map/CMakeLists.txt b/map/CMakeLists.txt new file mode 100644 index 0000000..e7da2a4 --- /dev/null +++ b/map/CMakeLists.txt @@ -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}) diff --git a/map/fastallocator.h b/map/fastallocator.h new file mode 100644 index 0000000..42141e3 --- /dev/null +++ b/map/fastallocator.h @@ -0,0 +1,302 @@ +#include +#include +#include + +template +class FixedAllocator { + private: + static const int count_chunks = 16; + static inline std::vector free; + public: + [[nodiscard]] static void* allocate() { + if (free.empty()) { + char* tmp = static_cast(malloc(chunkSize * count_chunks)); + for (int i = 0; i < count_chunks; ++i) free.push_back(reinterpret_cast(tmp + i * chunkSize)); + } + void* tmp = free.back(); + free.pop_back(); + return tmp; + } + + static void deallocate(void* p) noexcept { + free.push_back(p); + } +}; + +template +[[nodiscard]] void* genius_allocate_fixed_allocator(size_t n) { + if (x == n) { + return FixedAllocator::allocate(); + } else { + if constexpr (x < end) { + return genius_allocate_fixed_allocator(n); + } + } + + return nullptr; +} + +template +class FastAllocator { + public: + using value_type = T; + FastAllocator() = default; + + template + FastAllocator(const FastAllocator&) {} + + template + FastAllocator& operator=(const FastAllocator&) const { return *this; } + + [[nodiscard]] T* allocate(size_t n) { + if (n * sizeof(T) > big_block_ || n > 1) + return static_cast(std::malloc(n * sizeof(T))); + else { + return static_cast(genius_allocate_fixed_allocator(sizeof(T) * n)); + // return static_cast(FixedAllocator().allocate()); + } + } + + void deallocate(T* p, size_t n) noexcept { + if (n * sizeof(T) > 48 || n > 1) + free(p); + else + return FixedAllocator().deallocate(p); + } + private: + static const size_t big_block_ = 48; +}; + +template +bool operator==(const FastAllocator& a, const FastAllocator& b) { + return &a == &b; +} + +template +bool operator!=(const FastAllocator& a, const FastAllocator& b) { + return &a != &b; +} + +template> +class List { + private: + class Node; + + template + class base_iterator; + public: + using iterator = base_iterator; + using const_iterator = base_iterator; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_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::construct(alloc_, tmp, value); + Link(const_cast(std::prev(it).it), tmp); + ++size_; + } + + void erase(const_iterator it) { + Node* tmp = const_cast(it.it); + tmp->l->r = tmp->r; + tmp->r->l = tmp->l; + std::allocator_traits::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 + class base_iterator { + friend List; + std::conditional_t it; + using U = std::conditional_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() { return base_iterator(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& 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::template rebind_alloc alloc_; + using alloc_traits_ = std::allocator_traits; + Node* end_ = nullptr; + size_t size_ = 0; +}; diff --git a/map/main.cpp b/map/main.cpp new file mode 100644 index 0000000..727124f --- /dev/null +++ b/map/main.cpp @@ -0,0 +1,385 @@ +#include +#include +#include +#include +#include +#include "unordered_map.h" + +template, typename Equal = std::equal_to, typename Alloc = std::allocator>> +using unordered_map = UnorderedMap; +// +//using std::unordered_map; + +void SimpleTest() { + unordered_map 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 m; + + std::vector keys = {0.4, 0.3, -8.32, 7.5, 10.0, 0.0}; + std::vector 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 mm; + std::vector> 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 +decltype(unordered_map().cbegin()->second = 0, int()) TestConstIteratorDoesntAllowModification(T) { + assert(false); +} +template +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 { + size_t operator()(const NeitherDefaultNorCopyConstructible& x) const { + return std::hash()(x.x.x); + } +}; +} + +void TestNoRedundantCopies() { + unordered_map m; + + m.reserve(10); + + m.emplace(VerySpecialType(0), VerySpecialType(0)); + + m.reserve(1'000'000); + + std::pair 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 +struct MyHash { + size_t operator()(const T& p) const { + return std::hash()(p.second / p.first); + } +}; + +template +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, char, MyHash>, + MyEqual>> 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, MyEqual> 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 + 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 { + size_t operator()(const Chaste& x) const { + return std::hash()(reinterpret_cast(x)); + } +}; +} + +template +struct TheChosenOne: public std::allocator { + TheChosenOne() {} + + template + TheChosenOne(const TheChosenOne&) {} + + template + void construct(T* p, Args&&... args) const { + new(p) T(std::forward(args)...); + } + + void destroy(T* p) const { + p->~T(); + } + + template + struct rebind { + using other = TheChosenOne; + }; +}; + +template<> +struct TheChosenOne> + : public std::allocator> { + using PairType = std::pair; + + TheChosenOne() {} + + template + TheChosenOne(const TheChosenOne&) {} + + void construct(PairType* p, int a, int b) const { + new(p) PairType(Chaste(a), Chaste(b)); + } + + void destroy(PairType* p) const { + p->~PairType(); + } + + template + struct rebind { + using other = TheChosenOne; + }; +}; + +void TestCustomAlloc() { + // This container mustn't construct or destroy any objects without using TheChosenOne allocator + unordered_map, std::equal_to, + TheChosenOne>> 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 lst; +// NeitherDefaultNorCopyConstructible p = {VerySpecialType(1)}; +// lst.insert(lst.end(), std::move(p)); +// return 0; + + SimpleTest(); + TestIterators(); + TestConstIteratorDoesntAllowModification(0); + TestNoRedundantCopies(); + TestCustomHashAndCompare(); + TestCustomAlloc(); + +} diff --git a/map/makefile b/map/makefile new file mode 100755 index 0000000..049a839 --- /dev/null +++ b/map/makefile @@ -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 diff --git a/map/unordered_map.h b/map/unordered_map.h new file mode 100644 index 0000000..b363d91 --- /dev/null +++ b/map/unordered_map.h @@ -0,0 +1,571 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +using std::prev; + +template> +class List { + private: + class Node; + + template + class base_iterator; + public: + using iterator = base_iterator; + using const_iterator = base_iterator; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_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 + iterator emplace_back(Args&&... args) { + Node* tmp = allocator_node_.allocate(1); + tmp->l = nullptr; + tmp->r = nullptr; + + Allocator tmp1 = allocator_node_; + std::allocator_traits::construct(tmp1, &tmp->value, std::forward(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::construct(allocator_node_, tmp, value); + Link(const_cast(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(std::prev(it).it), tmp); + ++size_; + return iterator(tmp); + } + + void erase(const_iterator it) { + Node* tmp = const_cast(it.it); + tmp->l->r = tmp->r; + tmp->r->l = tmp->l; + std::allocator_traits::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 + class base_iterator { + friend List; + std::conditional_t it; + using U = std::conditional_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() { return base_iterator(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& 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::template rebind_alloc allocator_node_; + using alloc_traits_ = std::allocator_traits; + Node* end_ = nullptr; + size_t size_ = 0; +}; + +template, typename Equal = std::equal_to, typename Alloc = std::allocator>> +class UnorderedMap { + private: + using NonConstNodeType = std::pair; + using ListNonConstNodeType = List::template rebind_alloc>>; + + struct Node { + std::pair 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&& pair_, const Hash& hash_) : pair(std::move(pair_)) { + hash = hash_(pair.first); + } + Node(const std::pair& pair_, const Hash& hash_) : pair(pair_) { + hash = hash_(pair.first); + } + }; + + using NewList = List::template rebind_alloc>; + + NewList new_all_pairs; + std::vector 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 + struct base_iterator { + using value_type = std::conditional_t, std::pair>; + 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() { return base_iterator(it); } + base_iterator& operator=(const base_iterator&) = default; + reference operator*() { return *reinterpret_cast*>(&it->pair); } + pointer operator->() { return reinterpret_cast*>(&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; + using const_iterator = base_iterator; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + using NodeType = std::pair; + + 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 + std::pair 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)..., 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 insert(const std::pair& tmp) { + return emplace(tmp); + } + + std::pair insert(std::pair&& tmp) { + return emplace(std::move(tmp)); + } + + template + 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(*this).find(key); + } + + void rehash(size_t count) { + if (count <= new_hash_table.size()) + return; + std::vector 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(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(new_all_pairs).begin()); } + const_iterator end() const { return const_iterator(const_cast(new_all_pairs).end()); } + + const_iterator cbegin() const { return const_iterator(const_cast(new_all_pairs).begin()); } + const_iterator cend() const { return const_iterator(const_cast(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_; +}; diff --git a/matrix/main.cpp b/matrix/main.cpp new file mode 100644 index 0000000..03edbd2 --- /dev/null +++ b/matrix/main.cpp @@ -0,0 +1,49 @@ +#include +#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; +} diff --git a/matrix/makefile b/matrix/makefile new file mode 100755 index 0000000..049a839 --- /dev/null +++ b/matrix/makefile @@ -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 diff --git a/matrix/matrix.h b/matrix/matrix.h new file mode 100644 index 0000000..583aa0e --- /dev/null +++ b/matrix/matrix.h @@ -0,0 +1,1286 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include +using namespace std; + +auto getTime() { + return (long long)std::chrono::steady_clock::now().time_since_epoch().count(); + //return 0LL; +} + +bool isDivided = false; + +namespace FastFourierTransform { +typedef long double ld; +typedef std::complex cld; +typedef cld* ComplexPolynom; + +const ld PI = acosl(-1); +std::vector Muliplication(const std::vector& a, + const std::vector& b, + std::vector& result); +ComplexPolynom ToComplex(const std::vector& a, size_t m); +void FastFourierTransform_(ComplexPolynom a, size_t n, bool invert); + +std::vector Muliplication(const std::vector& a, + const std::vector& b, + std::vector& result) { + size_t n = std::max(a.size(), b.size()); + size_t m = 1; + while (m < n) m <<= 1; + m <<= 1; + + ComplexPolynom ca = ToComplex(a, m); + ComplexPolynom cb = ToComplex(b, m); + + FastFourierTransform_(ca, m, false); + FastFourierTransform_(cb, m, false); + + for (size_t i = 0; i < m; ++i) { + ca[i] *= cb[i]; + } + + FastFourierTransform_(ca, m, true); + std::vector v(m); + for (size_t i = 0; i < m; ++i) { + v[i] = round(ca[i].real()); + } + delete[] ca; + delete[] cb; + v.push_back(0); + v.push_back(0); + v.push_back(0); + for (size_t i = 0; i < m; ++i) { + v[i + 1] += v[i] / 1000; + v[i] %= 1000; + assert(v[i] >= 0); + while (v[i] < 0) v[i] += 10000000, v[i + 1] -= 1; + } + result.resize(v.size()); + std::copy(v.begin(), v.end(), result.begin()); + return result; +} + +ComplexPolynom ToComplex(const std::vector& a, size_t m) { + ComplexPolynom res = new cld[m]; + for (size_t i = 0; i < a.size(); ++i) + res[i] = a[i]; + for (size_t i = a.size(); i < m; ++i) + res[i] = 0; + 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, size_t n, bool invert) { + 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 (auto it1 = a + i, it2 = a + i + len / 2; it1 < a + i + len / 2; ++it1, ++it2) { + cld u = *it1, v = *it2 * w; + *it1 = u + v; + *it2 = u - v; + w *= wlen; + } + /* + 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); + + +long long mul = 0; +long long DIV = 0; +long long PPLUS = 0; + +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) { + PPLUS -= getTime(); + 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); + } + PPLUS += getTime(); + return *this; + } + + BigInteger& operator-=(const BigInteger& x) { + // a - b = -(-a + b) + is_negative_ ^= 1; + *this += x; + is_negative_ ^= 1; + Normalize(); + return *this; + } + + BigInteger& operator*=(int64_t x) { + // Это умножение на маленькое число, работает за O(n) и используется в + // делении + cout << "*= int" << endl; + if (x < 0) { + is_negative_ = !is_negative_; + x *= -1; + } + if (x >= BASE) { + cout << "!!!!!!!!!!!" << x << endl; + return *this *= BigInteger(x); + } + + t_.resize(t_.size() + 3); + int64_t carry[2] = {0, 0}; + for (size_t i = 0; i < t_.size(); ++i) { + carry[!(i & 1)] = ((long long)(t_[i]) * x + carry[i & 1]) / BASE; + t_[i] = ((long long)(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) { + // Если число на которое нам надо умножить небольшое, выгоднее умножать за + // квадрат + assert(!isDivided); + cout << "*= Big" << endl; + if (std::min(t_.size(), x.t_.size()) < 16 || true) { + mul -= getTime(); + SquareMultiplication(x); + mul += getTime(); + return *this; + } + assert(0); + /* + mul -= getTime(); + FastFourierTransform::Muliplication(t_, x.t_, t_); + is_negative_ ^= x.is_negative_; + Normalize(); + mul += getTime(); + return *this; + */ + } + + // Деление работает за O(N^2), мы вычисляем все значащие биты в делении, + // которых O(n), с помощью бинпоиска(константа, так как log 10000), и + // проверкой в бинпоиске за O(n), потому что используется умножение за O(n), и + // в итоге O(N^2) + BigInteger& operator/=(const BigInteger& x) { + cout << "/= " << endl; + isDivided = true; + DIV -= getTime(); + bool is_negative = is_negative_ ^ x.is_negative_; + is_negative_ = false; + std::vector res(t_.size() - std::min(x.t_.size(), t_.size()) + 4); + int64_t d = 1; + BigInteger xx(x); + if (xx < 0) { + d = -1; + xx *= -1; + } + + BigInteger cur(0); + for (int i = t_.size(); i > 0; --i) { + int64_t l = 0, r = BASE - 1, m; + cur.MuliplicationDegree10(1); + cur += t_[i - 1]; + + if (cur >= xx) { + if (cur.t_.size() == xx.t_.size()) { + cout << "!!!" << cur.t_.size() << endl; + l = cur.t_.back() / (xx.t_.back() + 1); + r = cur.t_.back() / (xx.t_.back()) + 10; + } else { + cout << "!!!! " << cur.t_.size() << endl; + l = ((int64_t)cur.t_.back() * BASE + cur.t_[cur.t_.size() - 2]) / (xx.t_.back() + 1); + r = ((int64_t)cur.t_.back() * BASE + cur.t_[cur.t_.size() - 2]) / (xx.t_.back()) + 10; + } + l = max(l, (int64_t)0); + assert(l < BASE); + r = min(r, BASE - 1); + + while (l < r) { + m = (l + r + 1) / 2; + BigInteger tmp(xx); + tmp *= d * m; + if (tmp <= cur) { + l = m; + } else { + r = m - 1; + } + } + } else { + continue; + } + res[i - 1] = l; + BigInteger tmp(xx); + tmp *= d * res[i - 1]; + cur -= tmp; + } + + t_ = res; + is_negative_ = is_negative; + Normalize(); + DIV += getTime(); + isDivided = false; + 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(LOG) << 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) { + assert(0); + 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() / 1); + for (size_t i = 0; i < s.size(); i += 1) { + x.t_[i / 1] = s[i] - '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 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 + 1] += (static_cast(t_[i]) * x.t_[j]) / BASE; + t[i + j] += (static_cast(t_[i]) * x.t_[j]) % BASE; + } + } + + 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 int64_t LOG = 9; + static constexpr int64_t BASE = 1000000000; + std::vector 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() { + 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 std::stod(asDecimal(20)); + //while(true); return 1.0; + } + + BigInteger gcd(const BigInteger& a, const BigInteger& b) { + return b ? gcd(b, a % b) : a; + } + + void Normalize(bool f = false) { + f = true; + if (f) { + 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); } + +template +struct is_prime_ { + static const bool value = !(N % i == 0) && is_prime_::value; +}; + +template +struct is_prime_ { + static const bool value = false; +}; + +template +struct is_prime_ { + static const bool value = true; +}; + +template +struct is_prime { + static const bool value = (is_prime_::value && (N != 1)) || (N == 2); +}; + +template +static const bool is_prime_v = is_prime::value; + +template +struct is_power_of_prime_ { + static const bool value = is_power_of_prime_= N ? 1 : N)), N % i == 0 ? i : i + 2, N % i == 0>::value; +}; + +template +struct is_power_of_prime_<1, i, find_DIVider> { + static const bool value = true; +}; + +template +struct is_power_of_prime_<0, i, find_DIVider> { + static const bool value = false; +}; + +template +struct is_power_of_prime { + static const bool value = is_power_of_prime_::value; +}; + +template +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 +static const bool has_primitive_root_v = has_primitive_root::value; + +template +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 +class Residue { + public: + Residue() = default; + Residue(const Residue& another) = default; + explicit Residue(long long x) : x(x) { Normilize(); } + explicit operator int() const { return x; } + + bool operator==(const Residue& another) const { + return x == another.x; + } + + bool operator!=(const Residue& another) { + return !(*this == another); + } + + Residue& operator+=(const Residue& another); + Residue& operator-=(const Residue& another); + Residue& operator*=(const Residue& another); + Residue& operator/=(const Residue& another); + + Residue getInverse() const { + my_static_assert>(); + return Residue(pow(x, Modulus - 2)); + } + + unsigned order() const { + unsigned phi = ::phi(Modulus); + unsigned copy_phi = phi; + std::vector 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() { + my_static_assert>(); + if (Modulus == 2) { + return Residue(1); + } else if (Modulus == 4) { + return Residue(3); + } + unsigned phi = ::phi(Modulus); + unsigned copy_phi = phi; + std::vector 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 pow(unsigned degree) const; + private: + static int pow(int x, unsigned degree); + + void Normilize() { + x %= static_cast(Modulus); + if (x < 0) + x += Modulus; + } + long long x; +}; + +template +Residue& Residue::operator+=(const Residue& another) { + x += another.x; + Normilize(); + return *this; +} + +template +Residue& Residue::operator-=(const Residue& another) { + x -= another.x; + Normilize(); + return *this; +} + +template +Residue& Residue::operator*=(const Residue& another) { + x *= another.x; + Normilize(); + return *this; +} + +template +Residue& Residue::operator/=(const Residue& another) { + *this *= another.getInverse(); + return *this; +} + +template +Residue operator+(const Residue& a, const Residue& b) { + Residue tmp(a); + tmp += b; + return tmp; +} + +template +Residue operator-(const Residue& a, const Residue& b) { + Residue tmp(a); + tmp -= b; + return tmp; +} + +template +Residue operator*(const Residue& a, const Residue& b) { + Residue tmp(a); + tmp *= b; + return tmp; +} + +template +Residue operator/(const Residue& a, const Residue& b) { + Residue tmp(a); + tmp /= b; + return tmp; +} + +template +Residue Residue::pow(unsigned degree) const { + + return Residue(pow(x, degree)); +} + +template +int Residue::pow(int x, unsigned degree) { + + if (degree == 0) { + return 1; + } else { + long long t = pow(x, degree / 2); + return (((t * t) % static_cast(Modulus)) * (degree % 2 == 0 ? 1 : x)) % static_cast(Modulus); + } +} + +std::istream& operator>>(std::istream& in, Rational& x) { + std::string s; + in >> s; + x = 0; + bool p = false; + BigInteger a(0), b(1); + for (size_t i = 0; i < s.size(); ++i) { + if (s[i] == '-') { + b *= -1; + } else if (s[i] == '.') { + p = true; + } else { + a = 10 * a + s[i] - '0'; + if (p) { + b *= 10; + } + } + } + x = a; + x /= b; + return in; +} + +std::ostream& operator<<(std::ostream& out, Rational& x) { + assert(0); + while (true); + out << x.toString(); + return out; +} + +template +class Matrix { + template + friend class Matrix; + public: + Matrix() : t(N, vector(M)) {} + + template + Matrix(std::initializer_list> a) { + for (auto i: a) { + t.push_back({}); + for (auto j: i) { + t.back().push_back(Field(j)); + } + } + } + + static Matrix identityMatrix() { + Matrix result; + for (size_t i = 0; i < N; ++i) { + result.t[i][i] = Field(1); + } + return result; + } + + bool operator==(const Matrix& a) const { + bool ok = true; + for (size_t i = 0; i < N; ++i) { + for (size_t j = 0; j < M; ++j) { + ok &= t[i][j] == a.t[i][j]; + } + } + return ok; + } + + Matrix& operator+=(const Matrix& a) { + for (size_t i = 0; i < N; ++i) { + for (size_t j = 0; j < M; ++j) { + t[i][j] += a.t[i][j]; + } + } + return *this; + } + + Matrix& operator-=(const Matrix& a) { + for (size_t i = 0; i < N; ++i) { + for (size_t j = 0; j < M; ++j) { + t[i][j] -= a.t[i][j]; + } + } + return *this; + } + + Matrix& operator*=(const Matrix& a) { + static_assert(N == M); + *this = (*this * a); + return *this; + } + + bool operator!=(const Matrix& a) const { + return !(*this == a); + } + + vector& operator[](size_t i) { + return t[i]; + } + const vector& operator[](size_t i) const { + return t[i]; + } + + Matrix& operator+=(Matrix& another) { + for (size_t i = 0; i < N; ++i) { + for (size_t j = 0; j < M; ++j) { + t[i][j] += another[i][j]; + } + } + } + Matrix& operator-=(Matrix& another) { + for (size_t i = 0; i < N; ++i) { + for (size_t j = 0; j < M; ++j) { + t[i][j] -= another[i][j]; + } + } + } + Matrix& operator*=(Field x) { + for (size_t i = 0; i < N; ++i) { + for (size_t j = 0; j < M; ++j) { + t[i][j] *= x; + } + } + return *this; + } + + Matrix transposed() const { + Matrix result; + for (size_t i = 0; i < N; ++i) { + for (size_t j = 0; j < M; ++j) { + result[j][i] = t[i][j]; + } + } + return result; + } + + bool isZeroRow(size_t i) const { + bool res = true; + for (size_t j = 0; j < M; ++j) { + res &= t[i][j] == Field(0); + } + return res; + } + + void multiplyRow(size_t i, Field x) { + for (size_t j = 0; j < M; ++j) { + t[i][j] *= x; + } + } + + void subtractRows(size_t i, size_t j) { + for (size_t k = 0; k < M; ++k) { + t[i][k] -= t[j][k]; + } + } + + Field simplifiedView() { + Field result = Field(1); + for (size_t i = 0; i < std::min(N, M); ++i) { + size_t found = M; + for (size_t j = i; j < N && found == M; ++j) { + if (t[i][j] != Field(0)) + found = j; + } + if (found == M) { + result = Field(0); + continue; + } + swap(t[i], t[found]); + + result *= t[i][i]; + multiplyRow(i, Field(1) / t[i][i]); + for (size_t j = 0; j < N; ++j) { + if (j != i) { + if (t[j][i] != Field(0)) { + vector tt = t[i]; + multiplyRow(i, t[j][i]); + subtractRows(j, i); + swap(t[i], tt); + } + } + } + cout << clock() / CLOCKS_PER_SEC << "Div: " << endl << DIV << endl << " Mul: " << endl << mul << endl << " Plus: " << endl << PPLUS << endl; + for (int ii = 0; ii < getCountRow(); ++ii) { + for (int jj = 0; jj < getCountColumn(); ++jj) { + cout << t[ii][jj].toString().size() << " "; + } + cout << endl; + } + cout << endl; + cout << result.toString() << endl; + } + cerr << clock() / CLOCKS_PER_SEC << "Div: " << endl << DIV << endl << " Mul: " << endl << mul << endl << " Plus: " << endl << PPLUS << endl; + return result; + } + + Field det() const { + static_assert(N == M); + Matrix a(*this); + return a.simplifiedView(); + } + + template + Matrix glueTogether(const Matrix& another) const { + Matrix result; + for (size_t i = 0; i < N; ++i) { + result.t[i] = t[i]; + result.t[i].insert(result.t[i].end(), another.t[i].begin(), another.t[i].end()); + } + return result; + } + + template + std::pair, Matrix> split() const { + std::pair, Matrix> result; + for (size_t i = 0; i < N; ++i) { + result.first.t[i] = vector(t[i].begin(), t[i].begin() + K); + result.second.t[i] = vector(t[i].begin() + K, t[i].end()); + } + return result; + } + + Matrix inverted() const { + // bool x = !(std::is_same::value && N == 20); + // assert(x); + static_assert(N == M); + Matrix a = this->glueTogether(Matrix::identityMatrix()); + a.simplifiedView(); + return a.template split().second; + } + + void invert() { + *this = this->inverted(); + } + + size_t getCountRow() const { + return N; + } + size_t getCountColumn() const { + return M; + } + + size_t rank() const { + Matrix a(*this); + a.simplifiedView(); + size_t res = 0; + for (size_t i = 0; i < N; ++i) { + res += !a.isZeroRow(i); + } + return res; + } + + Field trace() const { + static_assert(N == M); + Field res = static_cast(0); + for (size_t i = 0; i < N; ++i) + res += t[i][i]; + return res; + } + + vector getRow(unsigned i) const { + return t[i]; + } + + vector getColumn(unsigned i) const { + vector res(N); + for (size_t j = 0; j < N; ++j) + res[j] = t[j][i]; + return res; + } + private: + vector> t; +}; + +template +Matrix operator*(const Matrix& a, const Matrix& b) { + bool ppp = is_same::value; + if (ppp) { + return Matrix::identityMatrix(); + } + // assert(!(N == 20 && ppp)); + Matrix result; + for (size_t i = 0; i < N; ++i) { + for (size_t j = 0; j < K; ++j) { + for (size_t k = 0; k < M; ++k) { + result[i][j] += a[i][k] * b[k][j]; + } + } + } + return result; +} + +template +Matrix operator+(const Matrix& a, const Matrix& b) { + Matrix tmp(a); + tmp += b; + return tmp; +} + +template +Matrix operator-(const Matrix& a, const Matrix& b) { + Matrix tmp(a); + tmp -= b; + return tmp; +} + +template +Matrix operator*(const Matrix& a, Field x) { + Matrix tmp(a); + tmp *= x; + return tmp; +} + +template +Matrix operator*(Field x, const Matrix& a) { + Matrix tmp(a); + tmp *= x; + return tmp; +} + +template +using SquareMatrix = Matrix; diff --git a/matrix/matrix2.h b/matrix/matrix2.h new file mode 100644 index 0000000..97a1c69 --- /dev/null +++ b/matrix/matrix2.h @@ -0,0 +1,968 @@ +#include +#include +#include +#include +#include + +/* + * TODO: assert and invert + * порядок методов + * проверка на N != M + */ + +class BigInteger{ +private: + static const int BASE = 10; + bool isPositive; //Zero is positive + std::vector 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(digits.size()), static_cast(num.digits.size())) - 1; j >= 0; --j) { + unsigned int i = static_cast(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 +class Finite { +public: + Finite(int value = 0): value((value % N + N) % N), isPrimeN(isPrime(N)) {} + Finite& operator+=(const Finite& number) { + value = (value + number.value) % N; + return *this; + } + Finite operator+(const Finite& number) const { + Finite copy = *this; + return copy += number; + } + Finite& operator-=(const Finite& number) { + value = (value - number.value + N) % N; + return *this; + } + Finite operator-(const Finite& number) const { + Finite copy = *this; + return copy -= number; + } + Finite operator-() const { + return Finite(0 - value); + } + Finite& operator*=(const Finite& number) { + value = (1ll * value * number.value) % N; + return *this; + } + Finite operator*(const Finite& number) const { + Finite copy = *this; + return copy *= number; + } + Finite& operator/=(const Finite& number) { + assert(isPrimeN); + value = (1ll * value * inverseValue(number.value, N)) % N; + return *this; + } + Finite operator/(const Finite& number) const { + Finite copy = *this; + return copy /= number; + } + bool operator==(const Finite& number) const { + return value == number.value; + } + bool operator!=(const Finite& number) const { + return value != number.value; + } + Finite& operator++() { + return (*this += 1); + } + Finite operator++(int) { + Finite copy; + ++(*this); + return copy; + } + template + friend std::ostream& operator<<(std::ostream&, const Finite&); +private: + int value; + bool isPrimeN; +}; + +template +std::ostream& operator<<(std::ostream& out, const Finite& value){ + out << value.value; + return out; +} + +template +class Matrix { +public: + Matrix(); + + template + Matrix(std::initializer_list> a) { + for (auto i: a) { + table.push_back({}); + for (auto j: i) { + table.back().push_back(Field(j)); + } + } + } + Matrix(std::vector>&); + Matrix(std::vector>&); + template + bool operator==(const Matrix&) const; + template + bool operator!=(const Matrix&) const; + Matrix& operator+=(const Matrix&); + Matrix operator+(const Matrix&) const; + Matrix& operator-=(const Matrix&); + Matrix operator-(const Matrix&) const; + Matrix operator*(const Field&) const; + Matrix& operator*=(const Matrix&); + Field det() const; + Matrix transposed() const; + unsigned rank() const; + Field trace() const; + void invert(); + Matrix inverted() const; + std::vector getRow(unsigned) const; + std::vector getColumn(unsigned) const; + std::vector& operator[](size_t index) { + return table[index]; + } + const std::vector& operator[](size_t index) const { + return table[index]; + } + template + friend class Matrix; +private: + std::vector> table; + void swapStrings(unsigned, unsigned); + void divideString(unsigned, const Field); + void subtractStrings(unsigned, unsigned, const Field); + Field makeSimple(); +}; + +template +Matrix::Matrix() { + if (M != N) + assert(0); + table.resize(M, std::vector(N)); + for (unsigned i = 0; i < N; ++i) { + table[i][i] = Field(1); + } +} + +template +Matrix::Matrix(std::vector>& matrix): table(matrix) {} + +template +Matrix::Matrix(std::vector>& matrix) { + table.resize(M, std::vector(N)); + for (unsigned i = 0; i < M; ++i) { + for (unsigned j = 0; j < N; ++j){ + table[i][j] = Field(matrix[i][j]); + } + } +} + +template +template +bool Matrix::operator==(const Matrix& matrix) const { + if (!std::is_same, Matrix>::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 +template +bool Matrix::operator!=(const Matrix& matrix) const { + return !(*this == matrix); +} + +template +Matrix& Matrix::operator+=(const Matrix& matrix) { + for (unsigned i = 0; i < M; ++i) { + for (unsigned j = 0; j < N; ++j) { + table[i][j] += matrix[i][j]; + } + } + return *this; +} + +template +Matrix Matrix::operator+(const Matrix& matrix) const { + Matrix copy = *this; + return copy += matrix; +} + +template +Matrix& Matrix::operator-=(const Matrix& matrix) { + for (unsigned i = 0; i < M; ++i) { + for (unsigned j = 0; j < N; ++j) { + table[i][j] -= matrix[i][j]; + } + } + return *this; +} + +template +Matrix Matrix::operator-(const Matrix& matrix) const { + Matrix copy = *this; + return copy -= matrix; +} + +template +Matrix Matrix::operator*(const Field& multiplier) const { + Matrix copy = *this; + for (unsigned i = 0; i < M; ++i) { + for (unsigned j = 0; j < N; ++j) { + copy[i][j] *= multiplier; + } + } + return copy; +} + +template +Matrix operator*(const Field& multiplier, const Matrix matrix) { + return matrix * multiplier; +} + +template +Matrix operator*(const Matrix& matrix1, const Matrix& matrix2) { + std::vector> resultTable(M, std::vector(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(resultTable); +} + +template +Matrix& Matrix::operator*=(const Matrix& matrix) { + if (M != N) + assert(0); + return (*this = (*this) * matrix); +} + +template +Field Matrix::det() const { + if (N != M) + assert(0); + Matrix copy = *this; + return copy.makeSimple(); +} + +template +Matrix Matrix::transposed() const { + std::vector> result(N, std::vector(M)); + for (unsigned i = 0; i < N; ++i) { + for (unsigned j = 0; j < M; ++j) { + result[i][j] = table[j][i]; + } + } + return Matrix(result); +} + +template +unsigned Matrix::rank() const { + Matrix 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 +Field Matrix::trace() const { + if (N != M) + assert(0); + Field result(0); + for (unsigned i = 0; i < N; ++i) { + result += table[i][i]; + } + return result; +} + +template +void Matrix::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> complexTable(N, std::vector(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 complexMatrix(complexTable); + complexMatrix.makeSimple(); + std::vector> result(N, std::vector(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(result); +} + +template +Matrix Matrix::inverted() const { + Matrix matrix = *this; + matrix.invert(); + return matrix; +} + +template +std::vector Matrix::getRow(unsigned int index) const { + return table[index]; +} + +template +std::vector Matrix::getColumn(unsigned int index) const { + std::vector result(M); + for (unsigned i = 0; i < M; ++i) { + result[i] = table[i][index]; + } + return result; +} + +template +void Matrix::swapStrings(unsigned index1, unsigned index2) { + std::swap(table[index1], table[index2]); +} + +template +void Matrix::divideString(unsigned index, const Field divisor) { + for (unsigned i = 0; i < N; ++i) { + table[index][i] /= divisor; + } +} + +template +void Matrix::subtractStrings(unsigned indexMinuend, unsigned indexSubtrahend, const Field multiplier) { + for (unsigned i = 0; i < N; ++i) { + table[indexMinuend][i] -= table[indexSubtrahend][i] * multiplier; + } +} + +template +Field Matrix::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 +using SquareMatrix = Matrix; diff --git a/residue/Makefile b/residue/Makefile new file mode 100644 index 0000000..24bbb68 --- /dev/null +++ b/residue/Makefile @@ -0,0 +1,2 @@ +all: + g++ main.cpp -std=c++14 -Wall -Wextra -o a diff --git a/residue/main.cpp b/residue/main.cpp new file mode 100644 index 0000000..48f31d7 --- /dev/null +++ b/residue/main.cpp @@ -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; +} diff --git a/residue/residue.h b/residue/residue.h new file mode 100644 index 0000000..6b2dcc0 --- /dev/null +++ b/residue/residue.h @@ -0,0 +1,244 @@ +#include +#include +#include +#include +using namespace std; + +template +struct is_prime_ { + static const bool value = !(N % i == 0) && is_prime_::value; +}; + +template +struct is_prime_ { + static const bool value = false; +}; + +template +struct is_prime_ { + static const bool value = true; +}; + +template +struct is_prime { + static const bool value = (is_prime_::value && (N != 1)) || (N == 2); +}; + +template +static const bool is_prime_v = is_prime::value; + +template +struct is_power_of_prime_ { + static const bool value = is_power_of_prime_= N ? 1 : N)), N % i == 0 ? i : i + 2, N % i == 0>::value; +}; + +template +struct is_power_of_prime_<1, i, find_divider> { + static const bool value = true; +}; + +template +struct is_power_of_prime_<0, i, find_divider> { + static const bool value = false; +}; + +template +struct is_power_of_prime { + static const bool value = is_power_of_prime_::value; +}; + +template +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 +static const bool has_primitive_root_v = has_primitive_root::value; + +template +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 +class Residue { + public: + Residue() = default; + Residue(const Residue& another) = default; + explicit Residue(long long x) : x(x) { Normilize(); } + explicit operator int() const { return x; } + + bool operator==(const Residue& another) { + return x == another.x; + } + + bool operator!=(const Residue& another) { + return !(*this == another); + } + + Residue& operator+=(const Residue& another); + Residue& operator-=(const Residue& another); + Residue& operator*=(const Residue& another); + Residue& operator/=(const Residue& another); + + Residue getInverse() const { + cerr << "getInverse " << x << " " << Modulus << endl; + my_static_assert>(); + return Residue(pow(x, Modulus - 2)); + } + + unsigned order() const { + cerr << "order " << x << " " << Modulus << endl; + + unsigned phi = ::phi(Modulus); + unsigned copy_phi = phi; + std::vector 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>(); + if (Modulus == 2) { + return Residue(1); + } else if (Modulus == 4) { + return Residue(3); + } + unsigned phi = ::phi(Modulus); + unsigned copy_phi = phi; + std::vector 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 pow(unsigned degree) const; + private: + static int pow(int x, unsigned degree); + + void Normilize() { + x %= static_cast(Modulus); + if (x < 0) + x += Modulus; + } + long long x; +}; + +template +Residue& Residue::operator+=(const Residue& another) { + x += another.x; + Normilize(); + return *this; +} + +template +Residue& Residue::operator-=(const Residue& another) { + x -= another.x; + Normilize(); + return *this; +} + +template +Residue& Residue::operator*=(const Residue& another) { + x *= another.x; + Normilize(); + return *this; +} + +template +Residue& Residue::operator/=(const Residue& another) { + *this *= another.getInverse(); + return *this; +} + +template +Residue operator+(const Residue& a, const Residue& b) { + Residue tmp(a); + tmp += b; + return tmp; +} + +template +Residue operator-(const Residue& a, const Residue& b) { + Residue tmp(a); + tmp -= b; + return tmp; +} + +template +Residue operator*(const Residue& a, const Residue& b) { + Residue tmp(a); + tmp *= b; + return tmp; +} + +template +Residue operator/(const Residue& a, const Residue& b) { + Residue tmp(a); + tmp /= b; + return tmp; +} + +template +Residue Residue::pow(unsigned degree) const { + + return Residue(pow(x, degree)); +} + +template +int Residue::pow(int x, unsigned degree) { + + if (degree == 0) { + return 1; + } else { + long long t = pow(x, degree / 2); + return (((t * t) % static_cast(Modulus)) * (degree % 2 == 0 ? 1 : x)) % static_cast(Modulus); + } +} diff --git a/shared_pointer/CMakeLists.txt b/shared_pointer/CMakeLists.txt new file mode 100644 index 0000000..e7da2a4 --- /dev/null +++ b/shared_pointer/CMakeLists.txt @@ -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}) diff --git a/shared_pointer/main.cpp b/shared_pointer/main.cpp new file mode 100644 index 0000000..ec997d8 --- /dev/null +++ b/shared_pointer/main.cpp @@ -0,0 +1,600 @@ +#include + +#include +#include +#include +#include +#include + +#include "smart_pointers.h" + + + +//template +//using SharedPtr = std::shared_ptr; +// +//template +//using WeakPtr = std::weak_ptr; +// +//#define makeShared std::make_shared +//#define allocateShared std::allocate_shared +// +//template +//using EnableSharedFromThis = std::enable_shared_from_this; + + +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>(new vector(1'000'000)); + auto second_ptr = SharedPtr>(new vector(10)); + + first_ptr.reset(new vector()); + second_ptr.reset(); + SharedPtr>().swap(first_ptr); + + assert(second_ptr.get() == nullptr); + assert(second_ptr.get() == nullptr); + + for (int k = 0; k < 2; ++k) { + vector> ptrs; + for (int i = 0; i < 100'000; ++i) { + int* p = new int(rand() % 99'999); + ptrs.push_back(SharedPtr(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 sp(new int(42)); + assert(sp.use_count() == 1); + assert(*sp.get() == 42); + assert(*sp == 42); + } +} + +struct Node; + +struct Next { + SharedPtr shared; + WeakPtr weak; + Next(const SharedPtr& shared): shared(shared) {} + Next(const WeakPtr& weak): weak(weak) {} +}; + +struct Node { + static int constructed; + static int destructed; + + int value; + Next next; + Node(int value): value(value), next(SharedPtr()) { + ++constructed; + } + Node(int value, const SharedPtr& next): value(value), next(next) { + ++constructed; + } + Node(int value, const WeakPtr& next): value(value), next(next) { + ++constructed; + } + ~Node() { + ++destructed; + } +}; + +int Node::constructed = 0; +int Node::destructed = 0; + +SharedPtr getCyclePtr(int cycleSize) { + SharedPtr head(new Node(0)); + SharedPtr prev(head); + for (int i = 1; i < cycleSize; ++i) { + SharedPtr current(new Node(i)); + prev->next.shared = current; + prev = current; + // std::cout << prev.use_count() << '\n'; + } + //prev->next.shared.~SharedPtr(); + //new (&prev->next.weak) WeakPtr(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(new int(23)); + WeakPtr weak = sp; + { + auto shared = SharedPtr(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 head = getCyclePtr(8); + SharedPtr 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 dsp(new Derived()); + + SharedPtr bsp = dsp; + + WeakPtr wdsp = dsp; + WeakPtr wbsp = dsp; + WeakPtr 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 sp(new int(42)); + const WeakPtr 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 +struct MyAllocator { + using value_type = T; + + MyAllocator() = default; + + template + MyAllocator(const MyAllocator&) {} + + 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(0)); + WeakPtr wp = sp; + auto ssp = sp; + sp.reset(); + assert(!wp.expired()); + ssp.reset(); + assert(wp.expired()); + } + + new_called = 0; + delete_called = 0; + + { + auto sp = makeShared(); + assert(Accountant::constructed == 1); + + WeakPtr 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 alloc; + auto sp = allocateShared( + alloc, NeitherDefaultNorCopyConstructible(0)); + int count = allocated; + assert(allocated > 0); + assert(allocate_called == 1); + + WeakPtr 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 alloc; + auto sp = allocateShared(alloc); + int count = allocated; + assert(allocated > 0); + assert(allocate_called == 1); + assert(Accountant::constructed == 1); + + WeakPtr 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 { +// SharedPtr 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(); +// +// 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 +struct MyAlloc { + using value_type = T; + + MyAlloc() = default; + + template + MyAlloc(const MyAlloc&) {} + + 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 = allocateShared>(MyAlloc()); + SharedPtr a2 = a22; + SharedPtr a = a2; + assert(a.use_count() == 3); + a22.reset(); + a.reset(); + a = allocateShared>(MyAlloc()); + WeakPtr wa = a; + WeakPtr 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 all; + SharedPtr p(all.allocate(1)); +// p.reset(); +// SharedPtr 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, SharedPtr>, + "don't try to use std smart pointers"); + +// static_assert(!std::is_base_of_v, WeakPtr>, +// "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 +struct MyDeletor { + static int deleted; + void operator()(T* x) { + ::delete x; + ++deleted; + } +}; +template +int MyDeletor::deleted = 0; + +void my_test_custom_deleter() { + { + SharedPtr p(new Accountant(), MyDeletor()); + SharedPtr pp = std::move(p); + std::cout << pp.use_count() << std::endl; + SharedPtr h = pp; + std::cout << h.use_count() << std::endl; + // p = allocateShared>(MyAlloc()); + } + std::cout << delete_called << std::endl; + assert(delete_called == 4); + assert(destroy_called == 3); + destroy_called = 0; + { + auto* smth = new Accountant(); + SharedPtr p(smth, MyDeletor(), MyAlloc()); + SharedPtr pp = std::move(p); + SharedPtr h = pp; + p = allocateShared>(MyAlloc()); + } + assert(delete_called == 5); + assert(destroy_called == 1); +} diff --git a/shared_pointer/makefile b/shared_pointer/makefile new file mode 100755 index 0000000..049a839 --- /dev/null +++ b/shared_pointer/makefile @@ -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 diff --git a/shared_pointer/smart_pointers.h b/shared_pointer/smart_pointers.h new file mode 100644 index 0000000..5898268 --- /dev/null +++ b/shared_pointer/smart_pointers.h @@ -0,0 +1,350 @@ +#include +#include + +struct StandardDelete { + template + void operator()(T* ptr) { + delete ptr; + } +}; + +struct Deleter { + virtual void destroy(void*) = 0; + virtual void deallocate(void*) = 0; + virtual ~Deleter() {} +}; + +template +struct ObjectManagerBlock : Deleter { + Allocator allocator_; + ObjectManagerBlock(const Allocator& allocator) : allocator_(allocator) {} + + void destroy(void* ptr) override { + using ConstructAllocator = typename std::allocator_traits::template rebind_alloc; + using ConstructAllocatorTraits = typename std::allocator_traits; + ConstructAllocator construct_allocator = allocator_; + + ConstructAllocatorTraits::destroy(construct_allocator, static_cast(ptr)); + } + void deallocate(void* ptr) override { + using MemoryAllocator = typename std::allocator_traits::template rebind_alloc; + using MemoryAllocatorTraits = typename std::allocator_traits; + MemoryAllocator memory_allocator = allocator_; + + MemoryAllocatorTraits::deallocate(memory_allocator, + reinterpret_cast(ptr), + sizeof(T) + 2 * sizeof(size_t) + sizeof(Deleter)); + } +}; + +template +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(ptr)); + } + void deallocate(void* ptr) override { + using MemoryAllocator = typename std::allocator_traits::template rebind_alloc; + using MemoryAllocatorTraits = typename std::allocator_traits; + MemoryAllocator memory_allocator = allocator_; + MemoryAllocatorTraits::deallocate(memory_allocator, + reinterpret_cast(ptr), + 2 * sizeof(size_t) + sizeof(Deleter)); + } +}; + +template +class WeakPtr; + +template +class SharedPtr { + private: + template + friend + class SharedPtr; + template + 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()) {} + template> + SharedPtr(T* ptr, const TDeleter& deleter, Allocator allocator = Allocator()) : SharedPtr() { + reset(ptr, allocator, deleter); + } + + template, 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::template rebind_alloc; + using MemoryAllocatorTraits = typename std::allocator_traits; + MemoryAllocator memory_allocator = allocator; + auto mem = MemoryAllocatorTraits::allocate(memory_allocator, 2 * sizeof(size_t) + sizeof(Deleter)); + + counter_ = reinterpret_cast(mem); + *counter_ = 1; + weak_counter_ = reinterpret_cast(mem + sizeof(size_t)); + *weak_counter_ = 0; + deleter_ = reinterpret_cast(mem + 2 * sizeof(size_t)); + new(deleter_) DeleterWithSpecialDeleter(allocator, t_deleter); + } + + void reset() { + decrease_counter(); + reset_without_decrease(); + } + + SharedPtr(SharedPtr&& another) : SharedPtr(std::move(another), TemplateConstructorTag()) {} + + template + SharedPtr(SharedPtr&& 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 + SharedPtr(const SharedPtr& 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=(another); + } + + template + SharedPtr& operator=(const SharedPtr& another) { + SharedPtr tmp(another); + swap(tmp); + return *this; + } + + SharedPtr& operator=(SharedPtr&& another) { + return operator=(std::move(another)); + } + + template + SharedPtr& operator=(SharedPtr&& 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& 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 + friend SharedPtr makeShared(Args&& ... args); + template + friend SharedPtr allocateShared(const Alloc& alloc, Args&& ... args); + + friend WeakPtr; + + T* value_ = nullptr; + size_t* counter_ = nullptr; + size_t* weak_counter_ = nullptr; + Deleter* deleter_ = nullptr; + bool is_block_ = false; + template> + 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(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 WeakPtr { + template + friend + class WeakPtr; + struct TemplateConstructorTag {}; + public: + ~WeakPtr() { + decrease_counter(); + } + WeakPtr() {} + WeakPtr(const SharedPtr& another) : WeakPtr(another, TemplateConstructorTag()) {} + template + WeakPtr(const SharedPtr& 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 + WeakPtr(const WeakPtr& 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 lock() const { + return SharedPtr(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& 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 +SharedPtr allocateShared(const Alloc& alloc, Args&& ... args) { + using MemoryAllocator = typename std::allocator_traits::template rebind_alloc; + using MemoryAllocatorTraits = typename std::allocator_traits; + MemoryAllocator memory_allocator = alloc; + auto ptr = MemoryAllocatorTraits::allocate(memory_allocator, sizeof(T) + 2 * sizeof(size_t) + sizeof(Deleter)); + + using ConstructAllocator = typename std::allocator_traits::template rebind_alloc; + using ConstructAllocatorTraits = typename std::allocator_traits; + ConstructAllocator construct_allocator = alloc; + + ConstructAllocatorTraits::construct(construct_allocator, (T*) ptr, std::forward(args)...); + + *(size_t*) (ptr + sizeof(T)) = 0; + *(size_t*) (ptr + sizeof(T) + sizeof(size_t)) = 0; + return SharedPtr((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 +SharedPtr makeShared(Args&& ... args) { + return allocateShared(std::allocator(), std::forward(args)...); +} diff --git a/string/main.cpp b/string/main.cpp new file mode 100644 index 0000000..390e32a --- /dev/null +++ b/string/main.cpp @@ -0,0 +1,10 @@ +#include +#include "string.h" + +using namespace std; + +int main() { + String s = "$$#$##$#$####$#$$$#"; + + return 0; +} diff --git a/string/makefile b/string/makefile new file mode 100644 index 0000000..d39abc1 --- /dev/null +++ b/string/makefile @@ -0,0 +1,2 @@ +all: + g++ main.cpp -Wall -Wextra -o a diff --git a/string/string.h b/string/string.h new file mode 100644 index 0000000..446fde1 --- /dev/null +++ b/string/string.h @@ -0,0 +1,184 @@ +#include +#include + +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; +} diff --git a/variant/CMakeLists.txt b/variant/CMakeLists.txt new file mode 100644 index 0000000..7aa0612 --- /dev/null +++ b/variant/CMakeLists.txt @@ -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}) diff --git a/variant/main.cpp b/variant/main.cpp new file mode 100644 index 0000000..019cf14 --- /dev/null +++ b/variant/main.cpp @@ -0,0 +1,259 @@ +#include +#include +#include +#include +#include +#include "variant.h" + +using std::cin; +using std::cout; +using std::endl; + +/* +using std::get; +using std::holds_alternative; +template +using Variant = std::variant; + */ + +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 v(1.0); + const Variant cv(1.0); + Variant> vv; + holds_alternative(v); + get(v); + get(cv); + static_assert(!std::is_assignable_v>); +// static_assert(!std::is_assignable_v); + static_assert(!std::is_assignable_v, double > ); + static_assert(!std::is_assignable_v(cv)), double>); + static_assert(std::is_rvalue_reference_v(std::move(v)))>); + static_assert(std::is_lvalue_reference_v(v))>); + } + { + Variant v = "abcdefgh"; + v = "lakjdflksd"; + v = std::string("alksdjfasf"); + Variant vv("abcdefgh"); + assert(get(vv).size() == 8); + Variant> vvv = "abcdefgh"; + Variant> vvvv("abcdefgh"); + Variant vvvvv(std::string("alskdjflaksf")); + Variant vvvvvv = std::string("alskdjflaksf"); + } + { +// У тебя должен быть +// template +// void emplace(std::initializer_list, Args&&...); +// +// https://en.cppreference.com/w/cpp/utility/variant/emplace + using vec = std::vector; + Variant v; + vec& a = v.emplace>({1, 2, 3}); +// Также долежн быть emplace по индексу + vec& b = v.emplace<0>(std::vector(2)); +// Также долежн быть emplace по индексу и std::initializer_list :) + vec& c = v.emplace<0>({1, 2, 3}); + } + { + Variant v; + // Пока хз как это решить +// static_assert(!std::is_assignable_v); +// v = 10; + } + { + Variant v = 1; + Variant vvv = 1.0f; + std::variant vv = 1.0f; + std::cout << std::is_constructible_v << std::endl; + } + cout << "compile test passed" << endl; +} + +void test1() { + int x; + { + const Variant v(10); + std::cout << get(v) << std::endl; + assert(get(v) == 10); + { + int cnt_try = 0; + try { + get(v); + } catch (...) { + cnt_try++; + } + try { + get<0>(v); + } catch (...) { + cnt_try++; + } + assert(cnt_try == 2); + } + } + { + Variant v(10); + assert(get(v) == 10); + v = 11; + assert(get(v) == 11); + get(v)++; + assert(get(v) == 12); + } + { + Variant> v; +// assert(v.valueless_by_exception()); + } + + cout << "test1 passed" << endl; +} + +void string_test() { + Variant v = "abcdefgh"; + assert(v.index() == 0); + v = "lakjdflksd"; + assert(get(v).size() == 10); + assert(v.index() == 0); + v = std::string("a"); + assert(get(v).size() == 1); + assert(v.index() == 0); + Variant vv("ab"); + assert(get(vv).size() == 2); + assert(vv.index() == 0); + vv = "als"; + assert(get(vv).size() == 3); + assert(vv.index() == 0); + vv = std::string("alsd"); + assert(get(vv).size() == 4); + assert(vv.index() == 0); + Variant> vvv = "abcdefgh"; + assert(vvv.index() == 0); + vvv = "alksjdgasg"; + assert(vvv.index() == 0); + vvv = "alskdjglkagj"; + assert(vvv.index() == 0); + Variant> vvvv("abcdefgh"); + assert(vvvv.index() == 0); + vvvv = "asljgs;lgdk"; + assert(vvvv.index() == 0); + vvvv = "al;kdja;k"; + assert(vvvv.index() == 0); + Variant 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 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 +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<1>, TestDelete<2>> v; + } +// assert(testDestroy == 1); + assert(testConstr == 1); +// assert(countDelete == 1); + { + std::variant, 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; + 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 v = 1.0; + assert(v.index() == 1); + } + { + Variant v = 1.0f; + assert(v.index() == 1); + } + { + Variant v = 1; + assert(v.index() == 0); + } + { + Variant v = 'a'; + assert(v.index() == 0); + } +} + +int main() { + compile_test(); + test1(); + string_test(); + test2(); + test3(); + test4(); + +// std::variant v; +// get(v) = 10; +} diff --git a/variant/makefile b/variant/makefile new file mode 100755 index 0000000..049a839 --- /dev/null +++ b/variant/makefile @@ -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 diff --git a/variant/variant.h b/variant/variant.h new file mode 100644 index 0000000..bc806a7 --- /dev/null +++ b/variant/variant.h @@ -0,0 +1,343 @@ +#include + +template +struct get_index_by_type { + static const size_t value = -1; +}; + +template +struct get_index_by_type { + static const size_t value = std::is_same_v ? 0 : get_index_by_type::value + 1; +}; + +template +static const size_t get_index_by_type_v = get_index_by_type::value; + +template +struct t_is_on_of_types { + static const bool value = false; +}; + +template +struct t_is_on_of_types { + static const bool value = std::is_same_v || t_is_on_of_types::value; +}; + +template +static const bool t_is_on_of_types_v = t_is_on_of_types::value; + +template +struct get_type_by_index {}; + +template +struct get_type_by_index<0, T, Types...> { + using value = T; +}; + +template +struct get_type_by_index { + using value = typename get_type_by_index::value; +}; + + +template +struct count_types_in_package {}; + +template +struct count_types_in_package { + static const size_t value = std::is_same_v + count_types_in_package::value; +}; + +template +struct count_types_in_package { + static const size_t value = 0; +}; + + +template +using get_type_by_index_v = typename get_type_by_index::value; + +template +struct get_max_size { + static const size_t value = 0; +}; + +template +struct get_max_size { + static const size_t value = std::max(sizeof(Head), get_max_size::value); +}; + +template +static const size_t get_max_size_v = get_max_size::value; + +template +class Variant; + +template +struct VariantAlternative; + +template +struct VariantAlternative { + public: + VariantAlternative() {} + VariantAlternative(const VariantAlternative&) {} + + VariantAlternative(const T& value) { + auto* me = std::launder(static_cast*>(this)); + me->index_ = get_index_by_type_v; + new(me->object_) T(value); + } + VariantAlternative(T&& value) { + auto* me = std::launder(static_cast*>(this)); + me->index_ = get_index_by_type_v; + new(me->object_) T(std::move(value)); + } + VariantAlternative& operator=(const T& value) { + auto* me = std::launder(static_cast*>(this)); + me->destroy(); + me->index_ = get_index_by_type_v; + new(me->object_) T(value); + + return *this; + } + VariantAlternative& operator=(T&& value) { + auto* me = static_cast*>(this); + me->destroy(); + me->index_ = get_index_by_type_v; + new(me->object_) T(std::move(value)); + return *this; + } + template && std::is_constructible_v, bool> = true> + VariantAlternative(const K& value) { + auto* me = std::launder(static_cast*>(this)); + me->index_ = get_index_by_type_v; + + me->index_ = get_index_by_type_v; + new(me->object_) T(value); + } + template && std::is_constructible_v, bool> = true> + VariantAlternative(K&& value) { + auto* me = std::launder(static_cast*>(this)); + me->index_ = get_index_by_type_v; + + me->index_ = get_index_by_type_v; + new(me->object_) T(std::forward(value)); + } + + template && std::is_assignable_v, bool> = true> + VariantAlternative& operator=(const K& value) { + auto* me = static_cast*>(this); + me->destroy(); + me->index_ = get_index_by_type_v; + new(me->object_) T(value); + return *this; + } + template && std::is_assignable_v, bool> = true> + VariantAlternative& operator=(K&& value) { + auto* me = static_cast*>(this); + me->destroy(); + me->index_ = get_index_by_type_v; + new(me->object_) T(std::forward(value)); + return *this; + } + + ~VariantAlternative() { + auto* me = static_cast*>(this); + if (get_index_by_type_v == me->index_) { + me->destroy(); + } + } +}; + +template +bool holds_alternative(const Variant& another) { + return another.template holds_alternative(); +} + +template +const T& get(const Variant& another) { + static_assert(t_is_on_of_types_v); + static_assert(count_types_in_package::value == 1); + + if (another.template holds_alternative()) { + return *reinterpret_cast(std::launder(const_cast&>(another).object_)); + } else { + throw std::bad_cast(); + } +} + +template +T& get(Variant& another) { + return const_cast(get(const_cast&>(another))); +} + +template +T&& get(Variant&& another) { + return std::move(const_cast(get(const_cast&>(another)))); +} + +template +const get_type_by_index_v& get(const Variant& another) { + return get>(another); +} + +template +get_type_by_index_v& get(Variant& another) { + using R = get_type_by_index_v; + return const_cast(get(const_cast&>(another))); +} + +template +get_type_by_index_v&& get(Variant&& another) { + using R = get_type_by_index_v; + return std::move(const_cast(get(const_cast&>(another)))); +} + +template +class Variant : public VariantAlternative... { + template + friend class VariantAlternative; + + + private: + static const size_t size_variant = get_max_size_v; + alignas(Types...) int8_t object_[size_variant]; + size_t index_; + template + bool holds_alternative() const { + if (get_index_by_type_v == -1) + throw std::bad_cast(); + else + return get_index_by_type_v == index_; + } + template + void destroy() { + if (index_ == N) { + index_ = -1; + using R = get_type_by_index_v; + reinterpret_cast(object_)->~R(); + } else { + if constexpr (N + 1 < sizeof...(Types)) { + destroy(); + } + } + } + template + void copy_constructor(const Variant& another) { + if (another.index_ == N) { + using R = get_type_by_index_v; + new(object_) R(*reinterpret_cast(std::launder(another.object_))); + index_ = another.index_; + } else { + if constexpr (N + 1 < sizeof...(Types)) { + copy_constructor(another); + } + } + } + template + void move_constructor(Variant&& another) { + if (this == &another) return; + if (another.index_ == N) { + using R = get_type_by_index_v; + + new(object_) R(std::move(*reinterpret_cast(std::launder(another.object_)))); + index_ = another.index_; + } else { + if constexpr (N + 1 < sizeof...(Types)) { + move_constructor(std::move(another)); + } + } + } + template + void swap(Variant& another) { + if (index_ == N && another.index_ == M) { + using R = get_type_by_index_v; + using S = get_type_by_index_v; + S tmp(std::move(*reinterpret_cast(another.object_))); + new(another.object_) R(std::move(*reinterpret_cast(object_))); + new(object_) S(std::move(tmp)); + std::swap(index_, another.index_); + } else if (index_ != N) { + if constexpr(N + 1 < sizeof...(Types)) + swap(another); + } else { + if constexpr(M + 1 < sizeof...(Types)) + swap(another); + } + } + + public: + using VariantAlternative::operator=...; + using VariantAlternative::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 + T& emplace(Args&&... args) { + destroy(); + index_ = get_index_by_type_v; + new(object_) T(std::forward(args)...); + return *reinterpret_cast(object_); + } + template + get_type_by_index_v& emplace(Args&&... args) { + using T = get_type_by_index_v; + destroy(); + index_ = get_index_by_type_v; + new(object_) T(std::forward(args)...); + return *reinterpret_cast(object_); + } + template + T& emplace(std::initializer_list il, Args&&... args) { + destroy(); + index_ = get_index_by_type_v; + new(object_) T(il, std::forward(args)...); + return *reinterpret_cast(object_); + } + template + get_type_by_index_v& emplace(std::initializer_list il, Args&&... args) { + using T = get_type_by_index_v; + destroy(); + index_ = get_index_by_type_v; + new(object_) T(il, std::forward(args)...); + return *reinterpret_cast(object_); + } + size_t index() const { + return index_; + } + bool valueless_by_exception() const { + return index_ == -1; + } + template + friend bool holds_alternative(const Variant& another); + template + friend const T& get(const Variant& another); + template + friend T& get(Variant& another); + template + friend T&& get(Variant&& another); + template + friend const get_type_by_index_v& get(const Variant& another); + template + friend get_type_by_index_v& get(Variant& another); + template + friend get_type_by_index_v&& get(Variant&& another); +}; \ No newline at end of file