mirror of
https://github.com/danog/ton.git
synced 2024-12-02 09:28:02 +01:00
13140ddf29
1. Updated block header, proofs now contain more data Notice, that old proofs may become invalid in the future 2. Fixed message routing 3. Fixed block creator id in block header 4. Support for full proofs in tonlib 5. Support for partial state download 6. Some other bugfixes
303 lines
7.3 KiB
C++
303 lines
7.3 KiB
C++
/*
|
|
This file is part of TON Blockchain Library.
|
|
|
|
TON Blockchain Library is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU Lesser General Public License as published by
|
|
the Free Software Foundation, either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
TON Blockchain Library is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU Lesser General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Lesser General Public License
|
|
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
Copyright 2017-2019 Telegram Systems LLP
|
|
*/
|
|
#pragma once
|
|
|
|
#include "td/utils/bits.h"
|
|
#include "td/utils/common.h"
|
|
|
|
#include <limits>
|
|
#include <type_traits>
|
|
|
|
namespace td {
|
|
|
|
class uint128_emulated {
|
|
public:
|
|
using uint128 = uint128_emulated;
|
|
uint128_emulated(uint64 hi, uint64 lo) : hi_(hi), lo_(lo) {
|
|
}
|
|
template <class T, typename = std::enable_if_t<std::is_unsigned<T>::value>>
|
|
uint128_emulated(T lo) : uint128_emulated(0, lo) {
|
|
}
|
|
uint128_emulated() = default;
|
|
|
|
uint64 hi() const {
|
|
return hi_;
|
|
}
|
|
uint64 lo() const {
|
|
return lo_;
|
|
}
|
|
uint64 rounded_hi() const {
|
|
return hi_ + (lo_ >> 63);
|
|
}
|
|
static uint128 from_signed(int64 x) {
|
|
if (x >= 0) {
|
|
return uint128(0, x);
|
|
}
|
|
return uint128(std::numeric_limits<uint64>::max(), static_cast<uint64>(x));
|
|
}
|
|
static uint128 from_unsigned(uint64 x) {
|
|
return uint128(0, x);
|
|
}
|
|
|
|
uint128 add(uint128 other) const {
|
|
uint128 res(other.hi() + hi(), other.lo() + lo());
|
|
if (res.lo() < lo()) {
|
|
res.hi_++;
|
|
}
|
|
return res;
|
|
}
|
|
|
|
uint128 shl(int cnt) const {
|
|
if (cnt == 0) {
|
|
return *this;
|
|
}
|
|
if (cnt < 64) {
|
|
return uint128((hi() << cnt) | (lo() >> (64 - cnt)), lo() << cnt);
|
|
}
|
|
if (cnt < 128) {
|
|
return uint128(lo() << (cnt - 64), 0);
|
|
}
|
|
return uint128();
|
|
}
|
|
uint128 shr(int cnt) const {
|
|
if (cnt == 0) {
|
|
return *this;
|
|
}
|
|
if (cnt < 64) {
|
|
return uint128(hi() >> cnt, (lo() >> cnt) | (hi() << (64 - cnt)));
|
|
}
|
|
if (cnt < 128) {
|
|
return uint128(0, hi() >> (cnt - 64));
|
|
}
|
|
return uint128();
|
|
}
|
|
|
|
uint128 mult(uint128 other) const {
|
|
uint64 a_lo = lo() & 0xffffffff;
|
|
uint64 a_hi = lo() >> 32;
|
|
uint64 b_lo = other.lo() & 0xffffffff;
|
|
uint64 b_hi = other.lo() >> 32;
|
|
uint128 res(lo() * other.hi() + hi() * other.lo() + a_hi * b_hi, a_lo * b_lo);
|
|
uint128 add1(0, a_lo * b_hi);
|
|
uint128 add2(0, a_hi * b_lo);
|
|
return res.add(add1.shl(32)).add(add2.shl(32));
|
|
}
|
|
uint128 mult(uint64 other) const {
|
|
return mult(uint128(0, other));
|
|
}
|
|
uint128 mult_signed(int64 other) const {
|
|
return mult(uint128::from_signed(other));
|
|
}
|
|
bool is_zero() const {
|
|
return lo() == 0 && hi() == 0;
|
|
}
|
|
uint128 sub(uint128 other) const {
|
|
uint32 carry = 0;
|
|
if (other.lo() > lo()) {
|
|
carry = 1;
|
|
}
|
|
return uint128(hi() - other.hi() - carry, lo() - other.lo());
|
|
}
|
|
void divmod(uint128 other, uint128 *div_res, uint128 *mod_res) const {
|
|
CHECK(!other.is_zero());
|
|
|
|
auto from = *this;
|
|
auto ctz = from.count_leading_zeroes();
|
|
auto other_ctz = other.count_leading_zeroes();
|
|
if (ctz > other_ctz) {
|
|
*div_res = uint128();
|
|
*mod_res = from;
|
|
return;
|
|
}
|
|
auto shift = other_ctz - ctz;
|
|
auto res = uint128();
|
|
for (int i = shift; i >= 0; i--) {
|
|
auto sub = other.shl(i);
|
|
res = res.shl(1);
|
|
if (from.greater_or_equal(sub)) {
|
|
from = from.sub(sub);
|
|
res = res.set_lower_bit();
|
|
}
|
|
}
|
|
|
|
*div_res = res;
|
|
*mod_res = from;
|
|
}
|
|
uint128 div(uint128 other) const {
|
|
uint128 a, b;
|
|
divmod(other, &a, &b);
|
|
return a;
|
|
}
|
|
uint128 mod(uint128 other) const {
|
|
uint128 a, b;
|
|
divmod(other, &a, &b);
|
|
return b;
|
|
}
|
|
|
|
void divmod_signed(int64 y, int64 *quot, int64 *rem) const {
|
|
CHECK(y != 0);
|
|
auto x = *this;
|
|
int x_sgn = x.is_negative();
|
|
int y_sgn = y < 0;
|
|
if (x_sgn) {
|
|
x = x.negate();
|
|
}
|
|
uint128 uy = from_signed(y);
|
|
if (uy.is_negative()) {
|
|
uy = uy.negate();
|
|
}
|
|
|
|
uint128 t_quot, t_mod;
|
|
x.divmod(uy, &t_quot, &t_mod);
|
|
*quot = t_quot.lo();
|
|
*rem = t_mod.lo();
|
|
if (x_sgn != y_sgn) {
|
|
*quot = -*quot;
|
|
}
|
|
if (x_sgn) {
|
|
*rem = -*rem;
|
|
}
|
|
}
|
|
|
|
private:
|
|
uint64 hi_{0};
|
|
uint64 lo_{0};
|
|
|
|
bool is_negative() const {
|
|
return (hi_ >> 63) == 1;
|
|
}
|
|
|
|
int32 count_leading_zeroes() const {
|
|
if (hi() == 0) {
|
|
return 64 + count_leading_zeroes64(lo());
|
|
}
|
|
return count_leading_zeroes64(hi());
|
|
}
|
|
uint128 set_lower_bit() const {
|
|
return uint128(hi(), lo() | 1);
|
|
}
|
|
bool greater_or_equal(uint128 other) const {
|
|
return hi() > other.hi() || (hi() == other.hi() && lo() >= other.lo());
|
|
}
|
|
uint128 negate() const {
|
|
uint128 res(~hi(), ~lo() + 1);
|
|
if (res.lo() == 0) {
|
|
return uint128(res.hi() + 1, 0);
|
|
}
|
|
return res;
|
|
}
|
|
};
|
|
|
|
#if TD_HAVE_INT128
|
|
class uint128_intrinsic {
|
|
public:
|
|
using ValueT = unsigned __int128;
|
|
using uint128 = uint128_intrinsic;
|
|
explicit uint128_intrinsic(ValueT value) : value_(value) {
|
|
}
|
|
uint128_intrinsic(uint64 hi, uint64 lo) : value_((ValueT(hi) << 64) | lo) {
|
|
}
|
|
uint128_intrinsic() = default;
|
|
|
|
static uint128 from_signed(int64 x) {
|
|
return uint128(static_cast<ValueT>(x));
|
|
}
|
|
static uint128 from_unsigned(uint64 x) {
|
|
return uint128(static_cast<ValueT>(x));
|
|
}
|
|
uint64 hi() const {
|
|
return uint64(value() >> 64);
|
|
}
|
|
uint64 lo() const {
|
|
return uint64(value() & std::numeric_limits<uint64>::max());
|
|
}
|
|
uint64 rounded_hi() const {
|
|
return uint64((value() + (1ULL << 63)) >> 64);
|
|
}
|
|
uint128 add(uint128 other) const {
|
|
return uint128(value() + other.value());
|
|
}
|
|
uint128 sub(uint128 other) const {
|
|
return uint128(value() - other.value());
|
|
}
|
|
|
|
uint128 shl(int cnt) const {
|
|
if (cnt >= 128) {
|
|
return uint128();
|
|
}
|
|
return uint128(value() << cnt);
|
|
}
|
|
|
|
uint128 shr(int cnt) const {
|
|
if (cnt >= 128) {
|
|
return uint128();
|
|
}
|
|
return uint128(value() >> cnt);
|
|
}
|
|
|
|
uint128 mult(uint128 other) const {
|
|
return uint128(value() * other.value());
|
|
}
|
|
uint128 mult(uint64 other) const {
|
|
return uint128(value() * other);
|
|
}
|
|
uint128 mult_signed(int64 other) const {
|
|
return uint128(value() * other);
|
|
}
|
|
bool is_zero() const {
|
|
return value() == 0;
|
|
}
|
|
void divmod(uint128 other, uint128 *div_res, uint128 *mod_res) const {
|
|
CHECK(!other.is_zero());
|
|
*div_res = uint128(value() / other.value());
|
|
*mod_res = uint128(value() % other.value());
|
|
}
|
|
uint128 div(uint128 other) const {
|
|
CHECK(!other.is_zero());
|
|
return uint128(value() / other.value());
|
|
}
|
|
uint128 mod(uint128 other) const {
|
|
CHECK(!other.is_zero());
|
|
return uint128(value() % other.value());
|
|
}
|
|
void divmod_signed(int64 y, int64 *quot, int64 *rem) const {
|
|
CHECK(y != 0);
|
|
*quot = (int64)(signed_value() / y);
|
|
*rem = (int64)(signed_value() % y);
|
|
}
|
|
|
|
private:
|
|
unsigned __int128 value_{0};
|
|
ValueT value() const {
|
|
return value_;
|
|
}
|
|
__int128 signed_value() const {
|
|
return static_cast<__int128>(value());
|
|
}
|
|
};
|
|
#endif
|
|
|
|
#if TD_HAVE_INT128
|
|
using uint128 = uint128_intrinsic;
|
|
#else
|
|
using uint128 = uint128_emulated;
|
|
#endif
|
|
|
|
} // namespace td
|