/
githubmirror
/
aria2
Обзор
Документация
Войти
/
githubmirror
/
aria2
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
src/bignum.h
328 строк
7 KB
Tatsuhiro Tsujikawa
Fix runtime error: left shift of negative value
30 июн 2024, 11:07
30 июн 2024, 11:07
c13821a
Код
Авторство
О чём код?
/*** * This software was written by Nils Maier. No copyright is claimed, and the * software is hereby placed in the public domain. * * In case this attempt to disclaim copyright and place the software in the * public domain is deemed null and void in your jurisdiction, then the * software is Copyright 2004,2013 Nils Maier and it is hereby released to the * general public under the following terms: * Redistribution and use in source and binary forms, with or without * modification, are permitted. * There's ABSOLUTELY NO WARRANTY, express or implied. */ #ifndef BIGNUM_H #define BIGNUM_H #include <cstring> #include <algorithm> #include <memory> #include <stdint.h> #include "a2functional.h" namespace bignum { template <size_t dim> class ulong { public: typedef char char_t; typedef std::make_unsigned<char_t>::type uchar_t; private: std::unique_ptr<uchar_t[]> buf_; public: inline ulong() : buf_(aria2::make_unique<uchar_t[]>(dim)) {} inline ulong(size_t t) : buf_(aria2::make_unique<uchar_t[]>(dim)) { memcpy(buf_.get(), (uchar_t*)&t, sizeof(t)); } inline ulong(const ulong<dim>& rhs) : buf_(aria2::make_unique<uchar_t[]>(dim)) { memcpy(buf_.get(), rhs.buf_.get(), dim); } explicit inline ulong(const uchar_t* data, size_t size) : buf_(aria2::make_unique<uchar_t[]>(dim)) { if (size > dim) { throw std::bad_alloc(); } memcpy(buf_.get(), data, size); } virtual ~ulong() = default; ulong<dim>& operator=(const ulong<dim>& rhs) { memcpy(buf_.get(), rhs.buf_.get(), dim); return *this; } bool operator==(const ulong<dim>& rhs) const { return memcmp(buf_.get(), rhs.buf_.get(), dim) == 0; } bool operator!=(const ulong<dim>& rhs) const { return memcmp(buf_.get(), rhs.buf_.get(), dim) != 0; } bool operator>(const ulong<dim>& rhs) const { const auto b1 = buf_.get(); const auto b2 = rhs.buf_.get(); for (ssize_t i = dim - 1; i >= 0; --i) { for (ssize_t j = 1; j >= 0; --j) { uchar_t t = ((uchar_t)(b1[i] << 4 * (1 - j))) >> 4; uchar_t r = ((uchar_t)(b2[i] << 4 * (1 - j))) >> 4; if (t != r) { return t > r; } } } return false; } bool operator>=(const ulong<dim>& rhs) const { return *this == rhs || *this > rhs; } bool operator<(const ulong<dim>& rhs) const { return !(*this >= rhs); } bool operator<=(const ulong<dim>& rhs) const { return *this == rhs || *this < rhs; } ulong<dim> operator+(const ulong<dim>& rhs) const { ulong<dim> rv; const auto b1 = buf_.get(); const auto b2 = rhs.buf_.get(); const auto rb = rv.buf_.get(); bool base = false; for (size_t i = 0; i < dim; ++i) { for (ssize_t j = 0; j < 2; ++j) { uchar_t t = ((uchar_t)(b1[i] << 4 * (1 - j))) >> 4; uchar_t r = ((uchar_t)(b2[i] << 4 * (1 - j))) >> 4; if (base) { t++; } if (r + t >= 16) { rb[i] += (t + r - 16) << j * 4; base = true; } else { rb[i] += (t + r) << j * 4; base = false; } } } return rv; } ulong<dim>& operator+=(const ulong<dim>& rhs) { *this = *this + rhs; return *this; } ulong<dim>& operator++() { *this = *this + 1; return *this; } ulong<dim> operator++(int) { ulong<dim> tmp = *this; *this = *this + 1; return tmp; } ulong<dim> operator-(const ulong<dim>& rhs) const { ulong<dim> rv; const auto b1 = buf_.get(); const auto b2 = rhs.buf_.get(); const auto rb = rv.buf_.get(); bool base = false; for (size_t i = 0; i < dim; ++i) { for (ssize_t j = 0; j < 2; ++j) { uchar_t t = ((uchar_t)(b1[i] << 4 * (1 - j))) >> 4; uchar_t r = ((uchar_t)(b2[i] << 4 * (1 - j))) >> 4; if (base) { t--; } if (t >= r) { rb[i] += (t - r) << j * 4; base = false; } else { rb[i] += (t + 16 - r) << j * 4; base = true; } } } return rv; } ulong<dim>& operator-=(const ulong<dim>& rhs) { *this = *this - rhs; return *this; } ulong<dim>& operator--() { *this = *this - 1; return *this; } ulong<dim> operator--(int) { ulong<dim> tmp = *this; *this = *this - 1; return tmp; } ulong<dim> operator*(const ulong<dim>& rhs) const { ulong<dim> c = rhs, rv; const ulong<dim> null; size_t cap = c.capacity(); while (c != null) { ulong<dim> tmp = *this; tmp.mul(cap - 1); rv += tmp; ulong<dim> diff(1); diff.mul(cap - 1); c -= diff; cap = c.capacity(); } return rv; } ulong<dim>& operator*=(const ulong<dim>& rhs) { *this = *this * rhs; return *this; } ulong<dim> operator/(const ulong<dim>& rhs) const { ulong<dim> quotient, remainder; div(rhs, quotient, remainder); return quotient; } ulong<dim>& operator/=(const ulong<dim>& rhs) { *this = *this / rhs; return *this; } ulong<dim> operator%(const ulong<dim>& rhs) const { ulong<dim> quotient, remainder; div(rhs, quotient, remainder); return remainder; } ulong<dim>& operator%=(const ulong<dim>& rhs) { *this = *this % rhs; return *this; } ulong<dim> mul_mod(const ulong<dim>& mul, const ulong<dim>& mod) const { if (capacity() + mul.capacity() <= dim) { return (*this * mul) % mod; } ulong<dim * 2> et(buf_.get(), dim), emul(mul.buf_.get(), dim), emod(mod.buf_.get(), dim), erv = (et * emul) % emod; ulong<dim> rv; erv.binary(rv.buf_.get(), dim); return rv; } std::unique_ptr<uchar_t[]> binary() const { ulong<dim> c = *this; std::unique_ptr<uchar_t[]> rv; rv.swap(c.buf_); return rv; } void binary(uchar_t* buf, size_t len) const { memcpy(buf, buf_.get(), std::min(dim, len)); } size_t length() const { return dim; } private: size_t capacity() const { size_t rv = dim * 2; const auto b = buf_.get(); for (ssize_t i = dim - 1; i >= 0; --i) { uchar_t f = b[i] >> 4; uchar_t s = (b[i] << 4) >> 4; if (!f && !s) { rv -= 2; continue; } if (!f) { --rv; } return rv; } return rv; } void mul(size_t digits) { ulong<dim> tmp = *this; auto bt = tmp.buf_.get(); auto b = buf_.get(); memset(b, 0, dim); const size_t npar = digits % 2; const size_t d2 = digits / 2; for (size_t i = d2; i < dim; ++i) { for (size_t j = 0; j < 2; ++j) { uchar_t c = ((uchar_t)(bt[(dim - 1) - i] << 4 * (1 - j))) >> 4; uchar_t r = c << (npar * (1 - j) * 4 + (1 - npar) * j * 4); ssize_t idx = i - d2 - npar * j; if (idx >= 0) { b[(dim - 1) - idx] += r; } } } } void div(const ulong<dim>& d, ulong<dim>& q, ulong<dim>& r) const { ulong<dim> tmp = d; r = *this; q = 0; size_t cr = r.capacity(); const size_t cd = d.capacity(); while (cr > cd) { tmp = d; tmp.mul(cr - cd - 1); ulong<dim> qt(1); qt.mul(cr - cd - 1); ulong<dim> t = tmp; t.mul(1); if (r >= t) { tmp = t; qt.mul(1); } while (r >= tmp) { r -= tmp; q += qt; } cr = r.capacity(); } while (r >= d) { r -= d; ++q; } } }; } // namespace bignum #endif