DOUBLE_CONVERSION_ASSERT(sizeof(uint64_t) * 8 >= kBigitSize + 4); // TODO: static_assert
// Accumulates converted hex digits until at least kBigitSize bits.
// Works with non-factor-of-four kBigitSizes.
- uint64_t tmp = 0; // Accumulates converted hex digits until at least
+ uint64_t tmp = 0;
for (int cnt = 0; !value.is_empty(); value.pop_back()) {
tmp |= (HexCharValue(value.last()) << cnt);
if ((cnt += 4) >= kBigitSize) {
}
}
if (tmp > 0) {
- RawBigit(used_bigits_++) = tmp;
+ DOUBLE_CONVERSION_ASSERT(tmp <= kBigitMask);
+ RawBigit(used_bigits_++) = static_cast<Bignum::Chunk>(tmp & kBigitMask);
}
Clamp();
}
carry = sum >> kBigitSize;
++bigit_pos;
}
- used_bigits_ = (std::max)(bigit_pos, static_cast<int>(used_bigits_));
+ used_bigits_ = static_cast<int16_t>(std::max(bigit_pos, static_cast<int>(used_bigits_)));
DOUBLE_CONVERSION_ASSERT(IsClamped());
}
if (used_bigits_ == 0) {
return;
}
- exponent_ += (shift_amount / kBigitSize);
+ exponent_ += static_cast<int16_t>(shift_amount / kBigitSize);
const int local_shift = shift_amount % kBigitSize;
EnsureCapacity(used_bigits_ + 1);
BigitsShiftLeft(local_shift);
DOUBLE_CONVERSION_ASSERT(accumulator == 0);
// Don't forget to update the used_digits and the exponent.
- used_bigits_ = product_length;
+ used_bigits_ = static_cast<int16_t>(product_length);
exponent_ *= 2;
Clamp();
}
for (int i = 0; i < zero_bigits; ++i) {
RawBigit(i) = 0;
}
- used_bigits_ += zero_bigits;
- exponent_ -= zero_bigits;
+ used_bigits_ += static_cast<int16_t>(zero_bigits);
+ exponent_ -= static_cast<int16_t>(zero_bigits);
DOUBLE_CONVERSION_ASSERT(used_bigits_ >= 0);
DOUBLE_CONVERSION_ASSERT(exponent_ >= 0);
StringBuilder* result_builder) const {
Double double_inspect(value);
if (double_inspect.IsInfinite()) {
- if (infinity_symbol_ == NULL) return false;
+ if (infinity_symbol_ == DOUBLE_CONVERSION_NULLPTR) return false;
if (value < 0) {
result_builder->AddCharacter('-');
}
return true;
}
if (double_inspect.IsNan()) {
- if (nan_symbol_ == NULL) return false;
+ if (nan_symbol_ == DOUBLE_CONVERSION_NULLPTR) return false;
result_builder->AddString(nan_symbol_);
return true;
}
current = next_non_space;
}
- if (infinity_symbol_ != NULL) {
+ if (infinity_symbol_ != DOUBLE_CONVERSION_NULLPTR) {
if (ConsumeFirstCharacter(*current, infinity_symbol_, allow_case_insensitivity)) {
if (!ConsumeSubString(¤t, end, infinity_symbol_, allow_case_insensitivity)) {
return junk_string_value_;
}
}
- if (nan_symbol_ != NULL) {
+ if (nan_symbol_ != DOUBLE_CONVERSION_NULLPTR) {
if (ConsumeFirstCharacter(*current, nan_symbol_, allow_case_insensitivity)) {
if (!ConsumeSubString(¤t, end, nan_symbol_, allow_case_insensitivity)) {
return junk_string_value_;
#include <cstdlib>
#include <cstring>
+// For pre-C++11 compatibility
+#if __cplusplus >= 201103L
+#define DOUBLE_CONVERSION_NULLPTR nullptr
+#else
+#define DOUBLE_CONVERSION_NULLPTR NULL
+#endif
+
// ICU PATCH: Use U_ASSERT instead of <assert.h>
#include "uassert.h"
#ifndef DOUBLE_CONVERSION_ASSERT
template <typename T>
class Vector {
public:
- Vector() : start_(NULL), length_(0) {}
+ Vector() : start_(DOUBLE_CONVERSION_NULLPTR), length_(0) {}
Vector(T* data, int len) : start_(data), length_(len) {
- DOUBLE_CONVERSION_ASSERT(len == 0 || (len > 0 && data != NULL));
+ DOUBLE_CONVERSION_ASSERT(len == 0 || (len > 0 && data != DOUBLE_CONVERSION_NULLPTR));
}
// Returns a vector using the same backing storage as this one,
void AddSubstring(const char* s, int n) {
DOUBLE_CONVERSION_ASSERT(!is_finalized() && position_ + n < buffer_.length());
DOUBLE_CONVERSION_ASSERT(static_cast<size_t>(n) <= strlen(s));
- memmove(&buffer_[position_], s, n);
+ memmove(&buffer_[position_], s, static_cast<size_t>(n));
position_ += n;
}
+++ /dev/null
-name: CMake
-
-on:
- push:
- branches: [ master ]
- pull_request:
- branches: [ master ]
-
-env:
- # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
- BUILD_TYPE: Debug
-
-jobs:
- build:
- # The CMake configure and build commands are platform agnostic and should work equally well on Windows or Mac.
- # You can convert this to a matrix build if you need cross-platform coverage.
- # See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix
- runs-on: ubuntu-latest
-
- steps:
- - uses: actions/checkout@v2
-
- - name: Configure CMake
- # Configure CMake in a 'build' subdirectory.
- run: cmake -B ${{github.workspace}}/build -DBUILD_TESTING=ON
-
- - name: Build
- # Build your program with the given configuration
- run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}}
-
- - name: Test
- working-directory: ${{github.workspace}}/build
- # Execute all tests.
- run: test/cctest/cctest
cmake_minimum_required(VERSION 3.0)
project(double-conversion VERSION 3.2.0)
+option(BUILD_SHARED_LIBS "Build shared libraries (.dll/.so) instead of static ones (.lib/.a)" OFF)
+
if(BUILD_SHARED_LIBS AND MSVC)
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
endif()
NAMESPACE "${namespace}"
DESTINATION "${config_install_dir}"
)
+
+if (MSVC AND BUILD_SHARED_LIBS)
+ # Install companion PDB for Visual Studio
+ install(
+ FILES $<TARGET_PDB_FILE:double-conversion>
+ TYPE BIN
+ OPTIONAL
+ )
+endif()
+
+2022-01-16:
+ Install Visual Studio debugger (pdb) files.
+
2022-01-10:
Fix quiet NANs on MIPS* and PA-RISC architectures.
Update version number.
DOUBLE_CONVERSION_ASSERT(sizeof(uint64_t) * 8 >= kBigitSize + 4); // TODO: static_assert
// Accumulates converted hex digits until at least kBigitSize bits.
// Works with non-factor-of-four kBigitSizes.
- uint64_t tmp = 0; // Accumulates converted hex digits until at least
+ uint64_t tmp = 0;
for (int cnt = 0; !value.is_empty(); value.pop_back()) {
tmp |= (HexCharValue(value.last()) << cnt);
if ((cnt += 4) >= kBigitSize) {
}
}
if (tmp > 0) {
- RawBigit(used_bigits_++) = tmp;
+ DOUBLE_CONVERSION_ASSERT(tmp <= kBigitMask);
+ RawBigit(used_bigits_++) = static_cast<Bignum::Chunk>(tmp & kBigitMask);
}
Clamp();
}
carry = sum >> kBigitSize;
++bigit_pos;
}
- used_bigits_ = (std::max)(bigit_pos, static_cast<int>(used_bigits_));
+ used_bigits_ = static_cast<int16_t>(std::max(bigit_pos, static_cast<int>(used_bigits_)));
DOUBLE_CONVERSION_ASSERT(IsClamped());
}
if (used_bigits_ == 0) {
return;
}
- exponent_ += (shift_amount / kBigitSize);
+ exponent_ += static_cast<int16_t>(shift_amount / kBigitSize);
const int local_shift = shift_amount % kBigitSize;
EnsureCapacity(used_bigits_ + 1);
BigitsShiftLeft(local_shift);
DOUBLE_CONVERSION_ASSERT(accumulator == 0);
// Don't forget to update the used_digits and the exponent.
- used_bigits_ = product_length;
+ used_bigits_ = static_cast<int16_t>(product_length);
exponent_ *= 2;
Clamp();
}
for (int i = 0; i < zero_bigits; ++i) {
RawBigit(i) = 0;
}
- used_bigits_ += zero_bigits;
- exponent_ -= zero_bigits;
+ used_bigits_ += static_cast<int16_t>(zero_bigits);
+ exponent_ -= static_cast<int16_t>(zero_bigits);
DOUBLE_CONVERSION_ASSERT(used_bigits_ >= 0);
DOUBLE_CONVERSION_ASSERT(exponent_ >= 0);
StringBuilder* result_builder) const {
Double double_inspect(value);
if (double_inspect.IsInfinite()) {
- if (infinity_symbol_ == NULL) return false;
+ if (infinity_symbol_ == DOUBLE_CONVERSION_NULLPTR) return false;
if (value < 0) {
result_builder->AddCharacter('-');
}
return true;
}
if (double_inspect.IsNan()) {
- if (nan_symbol_ == NULL) return false;
+ if (nan_symbol_ == DOUBLE_CONVERSION_NULLPTR) return false;
result_builder->AddString(nan_symbol_);
return true;
}
current = next_non_space;
}
- if (infinity_symbol_ != NULL) {
+ if (infinity_symbol_ != DOUBLE_CONVERSION_NULLPTR) {
if (ConsumeFirstCharacter(*current, infinity_symbol_, allow_case_insensitivity)) {
if (!ConsumeSubString(¤t, end, infinity_symbol_, allow_case_insensitivity)) {
return junk_string_value_;
}
}
- if (nan_symbol_ != NULL) {
+ if (nan_symbol_ != DOUBLE_CONVERSION_NULLPTR) {
if (ConsumeFirstCharacter(*current, nan_symbol_, allow_case_insensitivity)) {
if (!ConsumeSubString(¤t, end, nan_symbol_, allow_case_insensitivity)) {
return junk_string_value_;
#include <cstdlib>
#include <cstring>
+// For pre-C++11 compatibility
+#if __cplusplus >= 201103L
+#define DOUBLE_CONVERSION_NULLPTR nullptr
+#else
+#define DOUBLE_CONVERSION_NULLPTR NULL
+#endif
+
#include <cassert>
#ifndef DOUBLE_CONVERSION_ASSERT
#define DOUBLE_CONVERSION_ASSERT(condition) \
template <typename T>
class Vector {
public:
- Vector() : start_(NULL), length_(0) {}
+ Vector() : start_(DOUBLE_CONVERSION_NULLPTR), length_(0) {}
Vector(T* data, int len) : start_(data), length_(len) {
- DOUBLE_CONVERSION_ASSERT(len == 0 || (len > 0 && data != NULL));
+ DOUBLE_CONVERSION_ASSERT(len == 0 || (len > 0 && data != DOUBLE_CONVERSION_NULLPTR));
}
// Returns a vector using the same backing storage as this one,
void AddSubstring(const char* s, int n) {
DOUBLE_CONVERSION_ASSERT(!is_finalized() && position_ + n < buffer_.length());
DOUBLE_CONVERSION_ASSERT(static_cast<size_t>(n) <= strlen(s));
- memmove(&buffer_[position_], s, n);
+ memmove(&buffer_[position_], s, static_cast<size_t>(n));
position_ += n;
}
CcTest* CcTest::last_ = NULL;
+// The windows compiler doesn't like to use `strdup`, and claims it's a
+// deprecated name.
+// For simplicity just implement it ourselves.
+static char* Strdup(const char* str) {
+ size_t len = strlen(str);
+ char* result = reinterpret_cast<char*>(malloc(len + 1));
+ memcpy(result, str, len + 1);
+ return result;
+}
CcTest::CcTest(TestFunction* callback, const char* test_file,
const char* test_name, const char* test_dependency,
basename = strrchr(const_cast<char *>(test_file), '\\');
}
if (!basename) {
- basename = strdup(test_file);
+ basename = Strdup(test_file);
} else {
- basename = strdup(basename + 1);
+ basename = Strdup(basename + 1);
}
// Drop the extension, if there is one.
char *extension = strrchr(basename, '.');
print_run_count = false;
} else {
- char* arg_copy = strdup(arg);
+ char* arg_copy = Strdup(arg);
char* testname = strchr(arg_copy, '/');
if (testname) {
// Split the string in two by nulling the slash and then run
#include <stdio.h>
#include <string.h>
+#include <inttypes.h>
#include "double-conversion/utils.h"
#define CHECK_EQ(a, b) CheckEqualsHelper(__FILE__, __LINE__, #a, a, #b, b)
-static inline void CheckEqualsHelper(const char* file, int line,
- const char* expected_source,
- const char* expected,
- const char* value_source,
- const char* value) {
+template<typename T> inline void PrintfValue(T x);
+template<> inline void PrintfValue(int x) { printf("%d", x); }
+template<> inline void PrintfValue(unsigned int x) { printf("%u", x); }
+template<> inline void PrintfValue(short x) { printf("%hd", x); }
+template<> inline void PrintfValue(unsigned short x) { printf("%hu", x); }
+template<> inline void PrintfValue(int64_t x) { printf("%" PRId64, x); }
+template<> inline void PrintfValue(uint64_t x) { printf("%" PRIu64, x); }
+template<> inline void PrintfValue(float x) { printf("%.30e", static_cast<double>(x)); }
+template<> inline void PrintfValue(double x) { printf("%.30e", x); }
+template<> inline void PrintfValue(bool x) { printf("%s", x ? "true" : "false"); }
+
+template<typename T1, typename T2>
+inline void CheckEqualsHelper(const char* file, int line,
+ const char* expected_source,
+ T1 expected,
+ const char* value_source,
+ T2 value) {
+ // If expected and value are NaNs then expected != value.
+ if (expected != value && (expected == expected || value == value)) {
+ printf("%s:%d:\n CHECK_EQ(%s, %s) failed\n",
+ file, line, expected_source, value_source);
+ printf("# Expected: ");
+ PrintfValue(expected);
+ printf("\n");
+ printf("# Found: ");
+ PrintfValue(value);
+ printf("\n");
+ abort();
+ }
+}
+
+template<>
+inline void CheckEqualsHelper(const char* file, int line,
+ const char* expected_source,
+ const char* expected,
+ const char* value_source,
+ const char* value) {
if ((expected == NULL && value != NULL) ||
(expected != NULL && value == NULL)) {
abort();
}
}
-static inline void CheckEqualsHelper(const char* file, int line,
- const char* expected_source,
- int expected,
- const char* value_source,
- int value) {
- if (expected != value) {
- printf("%s:%d:\n CHECK_EQ(%s, %s) failed\n"
- "# Expected: %d\n"
- "# Found: %d\n",
- file, line, expected_source, value_source, expected, value);
- abort();
- }
+template<>
+inline void CheckEqualsHelper(const char* file, int line,
+ const char* expected_source,
+ const char* expected,
+ const char* value_source,
+ char* value) {
+ CheckEqualsHelper(file, line, expected_source, expected, value_source, static_cast<const char*>(value));
}
-static inline void CheckEqualsHelper(const char* file, int line,
- const char* expected_source,
- double expected,
- const char* value_source,
- double value) {
- // If expected and value are NaNs then expected != value.
- if (expected != value && (expected == expected || value == value)) {
- printf("%s:%d:\n CHECK_EQ(%s, %s) failed\n"
- "# Expected: %.30e\n"
- "# Found: %.30e\n",
- file, line, expected_source, value_source, expected, value);
- abort();
- }
-}
-
-
class CcTest {
public:
typedef void (TestFunction)();
// Removes trailing '0' digits.
// Can return the empty string if all digits are 0.
static void TrimRepresentation(Vector<char> representation) {
- int len = strlen(representation.start());
+ int len = static_cast<int>(strlen(representation.start()));
int i;
for (i = len - 1; i >= 0; --i) {
if (representation[i] != '0') break;
static const int kBufferSize = 1024;
static void AssignHexString(Bignum* bignum, const char* str) {
- bignum->AssignHexString(Vector<const char>(str, strlen(str)));
+ int len = static_cast<int>(strlen(str));
+ bignum->AssignHexString(Vector<const char>(str, len));
}
static void AssignDecimalString(Bignum* bignum, const char* str) {
- bignum->AssignDecimalString(Vector<const char>(str, strlen(str)));
+ int len = static_cast<int>(strlen(str));
+ bignum->AssignDecimalString(Vector<const char>(str, len));
}
uc16 separator = StringToDoubleConverter::kNoSeparator) {
StringToDoubleConverter converter(flags, empty_string_value, Double::NaN(),
NULL, NULL, separator);
- double result = converter.StringToDouble(str, strlen(str),
+ int len = static_cast<int>(strlen(str));
+ double result = converter.StringToDouble(str, len,
processed_characters_count);
*processed_all =
((strlen(str) == static_cast<unsigned>(*processed_characters_count)));
uc16 buffer16[256];
DOUBLE_CONVERSION_ASSERT(strlen(str) < DOUBLE_CONVERSION_ARRAY_SIZE(buffer16));
- int len = strlen(str);
for (int i = 0; i < len; i++) {
buffer16[i] = str[i];
}
bool* processed_all) {
StringToDoubleConverter converter(flags, empty_string_value, Double::NaN(),
NULL, NULL);
- double result =
+ float result =
converter.StringToFloat(str16, length, processed_characters_count);
*processed_all = (length == *processed_characters_count);
return result;
}
-static double StrToF(const char* str, int flags, double empty_string_value,
- int* processed_characters_count, bool* processed_all) {
+static float StrToF(const char* str, int flags, double empty_string_value,
+ int* processed_characters_count, bool* processed_all) {
StringToDoubleConverter converter(flags, empty_string_value, Single::NaN(),
NULL, NULL);
- float result = converter.StringToFloat(str, strlen(str),
+ int len = static_cast<int>(strlen(str));
+ float result = converter.StringToFloat(str, len,
processed_characters_count);
*processed_all =
((strlen(str) == static_cast<unsigned>(*processed_characters_count)));
uc16 buffer16[256];
DOUBLE_CONVERSION_ASSERT(strlen(str) < DOUBLE_CONVERSION_ARRAY_SIZE(buffer16));
- int len = strlen(str);
for (int i = 0; i < len; i++) {
buffer16[i] = str[i];
}
// Removes trailing '0' digits.
static void TrimRepresentation(Vector<char> representation) {
- int len = strlen(representation.start());
+ int len = static_cast<int>(strlen(representation.start()));
int i;
for (i = len - 1; i >= 0; --i) {
if (representation[i] != '0') break;
DoubleToAscii(-2147483648.0, SHORTEST, 0,
buffer, &sign, &length, &point);
- CHECK_EQ(1, sign);
+ CHECK_EQ(true, sign);
CHECK_EQ("2147483648", buffer.start());
CHECK_EQ(10, point);
DoubleToAscii(-2147483648.0, SHORTEST_SINGLE, 0,
buffer, &sign, &length, &point);
- CHECK_EQ(1, sign);
+ CHECK_EQ(true, sign);
CHECK_EQ("21474836", buffer.start());
CHECK_EQ(10, point);
DoubleToAscii(-2147483648.0, FIXED, 2, buffer, &sign, &length, &point);
CHECK_GE(2, length - point);
TrimRepresentation(buffer);
- CHECK_EQ(1, sign);
+ CHECK_EQ(true, sign);
CHECK_EQ("2147483648", buffer.start());
CHECK_EQ(10, point);
buffer, &sign, &length, &point);
CHECK_GE(5, length);
TrimRepresentation(buffer);
- CHECK_EQ(1, sign);
+ CHECK_EQ(true, sign);
CHECK_EQ("21475", buffer.start());
CHECK_EQ(10, point);
DoubleToAscii(-3.5844466002796428e+298, SHORTEST, 0,
buffer, &sign, &length, &point);
- CHECK_EQ(1, sign);
+ CHECK_EQ(true, sign);
CHECK_EQ("35844466002796428", buffer.start());
CHECK_EQ(299, point);
DoubleToAscii(-3.5844466002796428e+298, PRECISION, 10,
buffer, &sign, &length, &point);
- CHECK_EQ(1, sign);
+ CHECK_EQ(true, sign);
CHECK_GE(10, length);
TrimRepresentation(buffer);
CHECK_EQ("35844466", buffer.start());
DoubleToAscii(4128420500802942e-24, SHORTEST, 0,
buffer, &sign, &length, &point);
- CHECK_EQ(0, sign);
+ CHECK_EQ(false, sign);
CHECK_EQ("4128420500802942", buffer.start());
CHECK_EQ(-8, point);
// Removes trailing '0' digits.
static void TrimRepresentation(Vector<char> representation) {
- int len = strlen(representation.start());
+ int len = static_cast<int>(strlen(representation.start()));
int i;
for (i = len - 1; i >= 0; --i) {
if (representation[i] != '0') break;
DiyFp diy_fp = Single(ordered).AsDiyFp();
CHECK_EQ(0x2 - 0x7F - 23, diy_fp.e());
// The 23 mantissa bits, plus the implicit 1 in bit 24 as a uint32_t.
- CHECK_EQ(0xA34567, diy_fp.f());
+ CHECK_EQ(0xA34567u, diy_fp.f());
uint32_t min_float32 = 0x00000001;
diy_fp = Single(min_float32).AsDiyFp();
CHECK_EQ(-0x7F - 23 + 1, diy_fp.e());
// This is a denormal; so no hidden bit.
- CHECK_EQ(1, diy_fp.f());
+ CHECK_EQ(1u, diy_fp.f());
uint32_t max_float32 = 0x7f7fffff;
diy_fp = Single(max_float32).AsDiyFp();
CHECK_EQ(0xFE - 0x7F - 23, diy_fp.e());
- CHECK_EQ(0x00ffffff, diy_fp.f());
+ CHECK_EQ(0x00ffffffu, diy_fp.f());
}
CHECK(nan.IsNan());
CHECK(nan.IsQuietNan());
CHECK(Single(std::numeric_limits<float>::quiet_NaN()).IsQuietNan());
+#ifndef _MSC_VER
+ // Visual studio has a bug for generating signaling NaNs:
+ // https://developercommunity.visualstudio.com/t/stdnumeric-limitssignaling-nan-returns-quiet-nan/155064
CHECK(Single(std::numeric_limits<float>::signaling_NaN()).IsSignalingNan());
+#endif
}
using namespace double_conversion;
static Vector<const char> StringToVector(const char* str) {
- return Vector<const char>(str, strlen(str));
+ int len = static_cast<int>(strlen(str));
+ return Vector<const char>(str, len);
}