Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

use locale independ way to convert string to double #51

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
[submodule "vendor/jsonsl"]
path = vendor/jsonsl
url = https://github.com/snej/jsonsl.git
[submodule "vendor/double-conversion"]
path = vendor/double-conversion
url = https://github.com/google/double-conversion
6 changes: 5 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,8 @@ matrix:
before_install:
- eval "${MATRIX_EVAL}"

script: "cd build_cmake && ./build.sh"
script:
- cd build_cmake && ./build.sh
- cd ..
- LC_NUMERIC="C" ./build_cmake/FleeceTests
- LC_NUMERIC="ru_RU.UTF-8" ./build_cmake/FleeceTests
3 changes: 3 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,12 @@ if(CMAKE_COMPILER_IS_GNUCC)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-psabi")
endif()

add_subdirectory(vendor/double-conversion)
set_source_files(RESULT FLEECE_SRC)
add_library(Fleece SHARED ${FLEECE_SRC})
target_link_libraries(Fleece double-conversion)
add_library(FleeceStatic STATIC ${FLEECE_SRC})
target_link_libraries(FleeceStatic double-conversion)

# "FleeceBase" static lib for clients that just need support stuff like slice, varint, RefCounted...
set_base_platform_files(RESULT FLEECE_BASE_PLATFORM_SRC)
Expand Down
10 changes: 8 additions & 2 deletions Fleece/Core/JSONConverter.cc
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

#include "JSONConverter.hh"
#include "jsonsl.h"
#include "double-conversion/string-to-double.h"
#include <map>

namespace fleece { namespace impl {
Expand Down Expand Up @@ -114,8 +115,13 @@ namespace fleece { namespace impl {
unsigned f = state->special_flags;
if (f & JSONSL_SPECIALf_FLOAT) {
char *start = (char*)&_input[state->pos_begin];
char *end;
double n = ::strtod(start, &end);
double_conversion::StringToDoubleConverter double_conv{
double_conversion::StringToDoubleConverter::ALLOW_TRAILING_JUNK, 0., 0., "Infinity", "NaN"
};
int processed_characters_count = 0;
double n = double_conv.StringToDouble(start,
static_cast<int>(_input.size - state->pos_begin),
&processed_characters_count);
_encoder.writeDouble(n);
} else if (f & JSONSL_SPECIALf_UNSIGNED) {
_encoder.writeUInt(state->nelem);
Expand Down
12 changes: 8 additions & 4 deletions Fleece/Core/Value.cc
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include "ParseDate.hh"
#include <math.h>
#include "betterassert.hh"
#include "double-conversion/double-to-string.h"


namespace fleece { namespace impl {
Expand Down Expand Up @@ -198,11 +199,14 @@ namespace fleece { namespace impl {
break;
}
case kFloatTag: {
const auto &dbl_to_str = double_conversion::DoubleToStringConverter::EcmaScriptConverter();
double_conversion::StringBuilder str_builder{buf, static_cast<int>(sizeof(buf))};
if (_byte[0] & 0x8)
sprintf(str, "%.16g", asDouble());
else
sprintf(str, "%.6g", asFloat());
break;
dbl_to_str.ToShortest(asDouble(), &str_builder);
else
dbl_to_str.ToShortestSingle(asFloat(), &str_builder);

return alloc_slice(buf, str_builder.position());
}
default:
return alloc_slice(asString());
Expand Down
19 changes: 19 additions & 0 deletions Fleece/Support/JSONEncoder.cc
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "ParseDate.hh"
#include <algorithm>
#include "betterassert.hh"
#include "double-conversion/double-to-string.h"

namespace fleece { namespace impl {

Expand Down Expand Up @@ -178,4 +179,22 @@ namespace fleece { namespace impl {
}
}

void JSONEncoder::writeFloat(float f) {
comma();
char buf[32] = {0};
double_conversion::StringBuilder str_builder{buf, static_cast<int>(sizeof(buf))};
const auto &dbl_to_str = double_conversion::DoubleToStringConverter::EcmaScriptConverter();
dbl_to_str.ToShortestSingle(f, &str_builder);
_out.write(buf, str_builder.position());
}

void JSONEncoder::writeDouble(double d) {
comma();
char buf[32];
double_conversion::StringBuilder str_builder{buf, static_cast<int>(sizeof(buf))};
const auto &dbl_to_str = double_conversion::DoubleToStringConverter::EcmaScriptConverter();
dbl_to_str.ToShortest(d, &str_builder);
_out.write(buf, str_builder.position());
}

} }
4 changes: 2 additions & 2 deletions Fleece/Support/JSONEncoder.hh
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@ namespace fleece { namespace impl {

void writeInt(int64_t i) {writef("%lld", i);}
void writeUInt(uint64_t i) {writef("%llu", i);}
void writeFloat(float f) {writef("%.6g", f);}
void writeDouble(double d) {writef("%.16g", d);}
void writeFloat(float f);
void writeDouble(double d);

void writeString(const std::string &s) {writeString(slice(s));}
void writeString(slice s);
Expand Down
11 changes: 8 additions & 3 deletions Tests/EncoderTests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "jsonsl.h"
#include "mn_wordlist.h"
#include <iostream>
#include <locale.h>
#include <float.h>

#ifndef _MSC_VER
Expand All @@ -38,7 +39,10 @@ class EncoderTests {
public:
EncoderTests()
:enc()
{ }
{
// to make sure that we don't depend on current locale
setlocale(LC_ALL, "");
}

~EncoderTests() {
enc.reset();
Expand Down Expand Up @@ -564,11 +568,12 @@ class EncoderTests {
TEST_CASE_METHOD(EncoderTests, "JSON", "[Encoder]") {
slice json("{\"\":\"hello\\nt\\\\here\","
"\"\\\"ironic\\\"\":[null,false,true,-100,0,100,123.456,6.02e+23],"
"\"foo\":123}");
"\"foo\":123,"
"\"foo2\":123.13274}");
JSONConverter j(enc);
REQUIRE(j.encodeJSON(json));
endEncoding();
auto d = checkDict(3);
auto d = checkDict(4);
auto output = d->toJSON();
REQUIRE((slice)output == json);
}
Expand Down
2 changes: 1 addition & 1 deletion Tests/MutableTests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ namespace fleece {
CHECK(!i);
}

CHECK(ma->asArray()->toJSON() == "[null,false,true,0,-123,2017,123456789,-123456789,\"Hot dog\",3.14159,3.141592653589793]"_sl);
CHECK(ma->asArray()->toJSON() == "[null,false,true,0,-123,2017,123456789,-123456789,\"Hot dog\",3.1415927,3.141592653589793]"_sl);

ma->remove(3, 5);
CHECK(ma->count() == 6);
Expand Down
2 changes: 1 addition & 1 deletion Tests/ObjCTests.mm
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ static void checkIt(id obj, const char* json) {
TEST_CASE("Obj-C Floats", "[Encoder]") {
checkIt(@0.5, "0.5");
checkIt(@-0.5, "-0.5");
checkIt(@((float)M_PI), "3.14159");
checkIt(@((float)M_PI), "3.1415927");
checkIt(@((double)M_PI), "3.141592653589793");
}

Expand Down
1 change: 1 addition & 0 deletions vendor/double-conversion
Submodule double-conversion added at 4a51e7