arkcompiler_ets_runtime/ecmascript/base/dtoa_helper.h
yangxiaoshuai2022 0aeb702aa0 fix warning of signed type cannot be involved in the bit operation
Signed-off-by: yangxiaoshuai2022 <yangxiaoshuai@huawei.com>
2024-05-28 12:09:40 +08:00

296 lines
11 KiB
C++

/*
* Copyright (c) 2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ECMASCRIPT_BASE_DTOA_HELPER_H
#define ECMASCRIPT_BASE_DTOA_HELPER_H
#include <math.h>
#include <stdint.h>
#include <stdint.h>
#include <limits>
#include "ecmascript/common.h"
namespace panda::ecmascript::base {
template <typename T>
class BufferVector {
public:
BufferVector() : start_(NULL), length_(0) {}
BufferVector(T* data, int length) : start_(data), length_(length)
{
ASSERT(length == 0 || (length > 0 && data != NULL));
}
int length() const { return length_; }
T* start() const { return start_; }
// Access individual vector elements - checks bounds in debug mode.
T& operator[](int index) const
{
ASSERT(0 <= index && index < length_);
return start_[index];
}
T& first() { return start_[0]; }
T& last() { return start_[length_ - 1]; }
private:
T* start_;
int length_;
};
class UInt128 {
public:
UInt128() : high_bits_(0), low_bits_(0) { }
UInt128(uint64_t high, uint64_t low) : high_bits_(high), low_bits_(low) { }
static constexpr int SHIFT_32BIT = 32;
static constexpr int SHIFT_64BIT = 64;
static constexpr int NEGATIVE_64BIT = -64;
void Multiply(uint32_t multiplicand)
{
uint64_t accumulator = (low_bits_ & kMask32) * multiplicand;
uint32_t part = static_cast<uint32_t>(accumulator & kMask32);
accumulator >>= SHIFT_32BIT;
accumulator = accumulator + (low_bits_ >> SHIFT_32BIT) * multiplicand;
low_bits_ = (accumulator << SHIFT_32BIT) + part;
accumulator >>= SHIFT_32BIT;
accumulator = accumulator + (high_bits_ & kMask32) * multiplicand;
part = static_cast<uint32_t>(accumulator & kMask32);
accumulator >>= SHIFT_32BIT;
accumulator = accumulator + (high_bits_ >> SHIFT_32BIT) * multiplicand;
high_bits_ = (accumulator << SHIFT_32BIT) + part;
ASSERT((accumulator >> SHIFT_32BIT) == 0);
}
void Shift(int shift_amount)
{
ASSERT(NEGATIVE_64BIT <= shift_amount && shift_amount <= SHIFT_64BIT);
if (shift_amount == 0) {
return;
} else if (shift_amount == NEGATIVE_64BIT) {
high_bits_ = low_bits_;
low_bits_ = 0;
} else if (shift_amount == SHIFT_64BIT) {
low_bits_ = high_bits_;
high_bits_ = 0;
} else if (shift_amount <= 0) {
high_bits_ <<= -shift_amount;
high_bits_ += low_bits_ >> (SHIFT_64BIT + shift_amount);
low_bits_ <<= -shift_amount;
} else {
low_bits_ >>= shift_amount;
low_bits_ += high_bits_ << (SHIFT_64BIT - shift_amount);
high_bits_ >>= shift_amount;
}
}
// Modifies *this to *this MOD (2^power).
// Returns *this DIV (2^power).
int DivModPowerOf2(int power)
{
if (power >= SHIFT_64BIT) {
int result = static_cast<int>(high_bits_ >> (power - SHIFT_64BIT));
high_bits_ -= static_cast<uint64_t>(result) << (power - SHIFT_64BIT);
return result;
} else {
uint64_t part_low = low_bits_ >> power;
uint64_t part_high = high_bits_ << (SHIFT_64BIT - power);
int result = static_cast<int>(part_low + part_high);
high_bits_ = 0;
low_bits_ -= part_low << power;
return result;
}
}
bool IsZero() const
{
return high_bits_ == 0 && low_bits_ == 0;
}
int BitAt(int position)
{
if (position >= SHIFT_64BIT) {
return static_cast<int>((high_bits_ >> (position - SHIFT_64BIT)) & 1);
} else {
return static_cast<int>((low_bits_ >> position) & 1);
}
}
private:
static const uint64_t kMask32 = 0xFFFFFFFF;
uint64_t high_bits_;
uint64_t low_bits_;
};
class DtoaHelper {
public:
static const int kDoubleSignificandSize = 53; // Includes the hidden bit.
static const uint32_t kMaxUInt32 = 0xFFFFFFFF;
static constexpr int CACHED_POWERS_OFFSET = 348;
static constexpr double kD_1_LOG2_10 = 0.30102999566398114; //1 / lg(10)
static constexpr int kQ = -61;
static constexpr int kIndex = 20;
static constexpr int MIN_DECIMAL_EXPONENT = -348;
static constexpr int EXPONENT_64 = 64;
static constexpr int EXPONENT_128 = 128;
static constexpr int NEGATIVE_128BIT = -128;
static constexpr uint64_t POW10[] = { 1ULL, 10ULL, 100ULL, 1000ULL, 10000ULL, 100000ULL, 1000000ULL,
10000000ULL, 100000000ULL, 1000000000ULL, 10000000000ULL, 100000000000ULL,
1000000000000ULL, 10000000000000ULL, 100000000000000ULL, 1000000000000000ULL,
10000000000000000ULL, 100000000000000000ULL, 1000000000000000000ULL,
10000000000000000000ULL };
static constexpr uint32_t TEN = 10;
static constexpr uint32_t TEN2POW = 100;
static constexpr uint32_t TEN3POW = 1000;
static constexpr uint32_t TEN4POW = 10000;
static constexpr uint32_t TEN5POW = 100000;
static constexpr uint32_t TEN6POW = 1000000;
static constexpr uint32_t TEN7POW = 10000000;
static constexpr uint32_t TEN8POW = 100000000;
// DiyFp is a floating-point number type, consists of a uint64 significand and one integer exponent.
struct DiyFp {
DiyFp() : f(), e() {}
DiyFp(uint64_t fp, int exp) : f(fp), e(exp) {}
explicit DiyFp(double d)
{
union {
double d;
uint64_t u64;
} u = { d };
int biased_e = static_cast<int>((u.u64 & kDpExponentMask) >> kDpSignificandSize);
uint64_t significand = (u.u64 & kDpSignificandMask);
if (biased_e != 0) {
f = significand + kDpHiddenBit;
e = biased_e - kDpExponentBias;
} else {
f = significand;
e = kDpMinExponent + 1;
}
}
DiyFp operator - (const DiyFp &rhs) const
{
return DiyFp(f - rhs.f, e);
}
DiyFp operator*(const DiyFp &rhs) const
{
const uint64_t M32 = 0xFFFFFFFF;
const uint64_t a = f >> 32;
const uint64_t b = f & M32;
const uint64_t c = rhs.f >> 32;
const uint64_t d = rhs.f & M32;
const uint64_t ac = a * c;
const uint64_t bc = b * c;
const uint64_t ad = a * d;
const uint64_t bd = b * d;
uint64_t tmp = (bd >> kInt32Bits) + (ad & M32) + (bc & M32);
tmp += 1U << kRoundBits; // mult_round
return DiyFp(ac + (ad >> kInt32Bits) + (bc >> kInt32Bits) + (tmp >> kInt32Bits), e + rhs.e + kInt64Bits);
}
DiyFp Normalize() const
{
DiyFp res = *this;
while (!(res.f & kDpHiddenBit)) {
res.f <<= 1;
res.e--;
}
res.f <<= (kDiySignificandSize - kDpSignificandSize - 1);
res.e = res.e - (kDiySignificandSize - kDpSignificandSize - 1);
return res;
}
DiyFp NormalizeBoundary() const
{
DiyFp res = *this;
while (!(res.f & (kDpHiddenBit << 1))) {
res.f <<= 1;
res.e--;
}
res.f <<= (kDiySignificandSize - kDpSignificandSize - 2); // 2: parameter
res.e = res.e - (kDiySignificandSize - kDpSignificandSize - 2); // 2: parameter
return res;
}
void NormalizedBoundaries(DiyFp *minus, DiyFp *plus) const
{
DiyFp pl = DiyFp((f << 1) + 1, e - 1).NormalizeBoundary();
DiyFp mi = (f == kDpHiddenBit) ? DiyFp((f << 2) - 1, e - 2) : DiyFp((f << 1) - 1, e - 1); // 2: parameter
mi.f <<= mi.e - pl.e;
mi.e = pl.e;
*plus = pl;
*minus = mi;
}
static const int kInt64Bits = 64;
static const int kInt32Bits = 32;
static const int kRoundBits = 31;
static const int kDiySignificandSize = 64;
static const int kDpSignificandSize = 52;
static const int kDpExponentBias = 0x3FF + kDpSignificandSize;
static const int kDpMaxExponent = 0x7FF - kDpExponentBias;
static const int kDpMinExponent = -kDpExponentBias;
static const int kDpDenormalExponent = -kDpExponentBias + 1;
static const uint64_t kDpExponentMask =
(static_cast<uint64_t>(0x7FF00000) << 32) | static_cast<uint64_t>(0x00000000);
static const uint64_t kDpSignificandMask =
(static_cast<uint64_t>(0x000FFFFF) << 32) | static_cast<uint64_t>(0xFFFFFFFF);
static const uint64_t kDpHiddenBit =
(static_cast<uint64_t>(0x00100000) << 32) | static_cast<uint64_t>(0x00000000);
uint64_t f;
int e;
};
static DiyFp GetCachedPower(int e, int *K)
{
// dk must be positive, so can do ceiling in positive
double dk = (kQ - e) * kD_1_LOG2_10 + CACHED_POWERS_OFFSET - 1;
int k = static_cast<int>(dk);
if (dk - k > 0.0) {
k++;
}
unsigned index = static_cast<unsigned>((static_cast<unsigned>(k) >> 3) + 1); // 3: parameter
*K = -(MIN_DECIMAL_EXPONENT + static_cast<int>(index << 3)); // 3: parameter
return GetCachedPowerByIndex(index);
}
static DiyFp GetCachedPowerByIndex(size_t index);
static void GrisuRound(char* buffer, int len, uint64_t delta, uint64_t rest, uint64_t tenKappa, uint64_t distance);
static int CountDecimalDigit32(uint32_t n);
static void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buffer, int* len, int* K);
static void Grisu(double value, char* buffer, int* length, int* K);
static void Dtoa(double value, char* buffer, int* point, int* length);
static void FillDigits32FixedLength(uint32_t number, int requested_length, BufferVector<char> buffer, int* length);
static void FillDigits32(uint32_t number, BufferVector<char> buffer, int* length);
static void FillDigits64FixedLength(uint64_t number, [[maybe_unused]] int requested_length,
BufferVector<char> buffer, int* length);
static void FillDigits64(uint64_t number, BufferVector<char> buffer, int* length);
static void RoundUp(BufferVector<char> buffer, int* length, int* decimal_point);
static void FillFractionals(uint64_t fractionals, int exponent, int fractional_count, BufferVector<char> buffer,
int* length, int* decimal_point);
static void TrimZeros(BufferVector<char> buffer, int* length, int* decimal_point);
static bool FixedDtoa(double v, int fractional_count, BufferVector<char> buffer, int* length, int* decimal_point);
};
}
#endif