mirror of
https://github.com/Tencent/rapidjson.git
synced 2025-10-27 19:10:24 +01:00
Later clang compilers will warn on float -> double promotion because it can add precision. In the context of RapidJSON – especially with its float methods on GenericValue – I think this warning holds no water and should be ignored.
Trim whitespace off the end of various lines. Added an additional NumberStream specialization that will always perform a TakePush() even when just Take() is called. This supports RawNumber parsing by pushing onto our StackStream particular parts of the number that currently aren't captured because of full precision double parsing, such as the negative sign, scientific number exponents, etc. RawNumber parsing fails with input streams that don't have copy optimization, such as the BasicIStreamWrapper stream. To work around this, instead do the Transcode copy operation by reading from a UTF8 StringStream instead of the original InputStream. Since the NumberStream downcasts all input Ch into chars, we know we're dealing with UTF8/ASCII compatible stack characters during the Transcoding.
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
@@ -7,9 +7,9 @@
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// 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
|
||||
// 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.
|
||||
|
||||
#include "unittest.h"
|
||||
@@ -241,13 +241,13 @@ static void TestParseDouble() {
|
||||
TEST_DOUBLE(fullPrecision, "0.017976931348623157e+310", 1.7976931348623157e+308); // Max double in another form
|
||||
|
||||
// Since
|
||||
// abs((2^-1022 - 2^-1074) - 2.2250738585072012e-308) = 3.109754131239141401123495768877590405345064751974375599... <20><> 10^-324
|
||||
// abs((2^-1022) - 2.2250738585072012e-308) = 1.830902327173324040642192159804623318305533274168872044... <20><> 10 ^ -324
|
||||
// abs((2^-1022 - 2^-1074) - 2.2250738585072012e-308) = 3.109754131239141401123495768877590405345064751974375599... <20><> 10^-324
|
||||
// abs((2^-1022) - 2.2250738585072012e-308) = 1.830902327173324040642192159804623318305533274168872044... <20><> 10 ^ -324
|
||||
// So 2.2250738585072012e-308 should round to 2^-1022 = 2.2250738585072014e-308
|
||||
TEST_DOUBLE(fullPrecision, "2.2250738585072012e-308", 2.2250738585072014e-308); // http://www.exploringbinary.com/java-hangs-when-converting-2-2250738585072012e-308/
|
||||
|
||||
// More closer to normal/subnormal boundary
|
||||
// boundary = 2^-1022 - 2^-1075 = 2.225073858507201136057409796709131975934819546351645648... <20><> 10^-308
|
||||
// boundary = 2^-1022 - 2^-1075 = 2.225073858507201136057409796709131975934819546351645648... <20><> 10^-308
|
||||
TEST_DOUBLE(fullPrecision, "2.22507385850720113605740979670913197593481954635164564e-308", 2.2250738585072009e-308);
|
||||
TEST_DOUBLE(fullPrecision, "2.22507385850720113605740979670913197593481954635164565e-308", 2.2250738585072014e-308);
|
||||
|
||||
@@ -297,7 +297,7 @@ static void TestParseDouble() {
|
||||
}
|
||||
|
||||
// Cover trimming
|
||||
TEST_DOUBLE(fullPrecision,
|
||||
TEST_DOUBLE(fullPrecision,
|
||||
"2.22507385850720113605740979670913197593481954635164564802342610972482222202107694551652952390813508"
|
||||
"7914149158913039621106870086438694594645527657207407820621743379988141063267329253552286881372149012"
|
||||
"9811224514518898490572223072852551331557550159143974763979834118019993239625482890171070818506906306"
|
||||
@@ -306,7 +306,7 @@ static void TestParseDouble() {
|
||||
"5722898802581825451803257070188608721131280795122334262883686223215037756666225039825343359745688844"
|
||||
"2390026549819838548794829220689472168983109969836584681402285424333066033985088644580400103493397042"
|
||||
"7567186443383770486037861622771738545623065874679014086723327636718751234567890123456789012345678901"
|
||||
"e-308",
|
||||
"e-308",
|
||||
2.2250738585072014e-308);
|
||||
|
||||
{
|
||||
@@ -457,12 +457,12 @@ template <typename Encoding>
|
||||
struct ParseStringHandler : BaseReaderHandler<Encoding, ParseStringHandler<Encoding> > {
|
||||
ParseStringHandler() : str_(0), length_(0), copy_() {}
|
||||
~ParseStringHandler() { EXPECT_TRUE(str_ != 0); if (copy_) free(const_cast<typename Encoding::Ch*>(str_)); }
|
||||
|
||||
|
||||
ParseStringHandler(const ParseStringHandler&);
|
||||
ParseStringHandler& operator=(const ParseStringHandler&);
|
||||
|
||||
bool Default() { ADD_FAILURE(); return false; }
|
||||
bool String(const typename Encoding::Ch* str, size_t length, bool copy) {
|
||||
bool String(const typename Encoding::Ch* str, size_t length, bool copy) {
|
||||
EXPECT_EQ(0, str_);
|
||||
if (copy) {
|
||||
str_ = static_cast<typename Encoding::Ch*>(malloc((length + 1) * sizeof(typename Encoding::Ch)));
|
||||
@@ -470,7 +470,7 @@ struct ParseStringHandler : BaseReaderHandler<Encoding, ParseStringHandler<Encod
|
||||
}
|
||||
else
|
||||
str_ = str;
|
||||
length_ = length;
|
||||
length_ = length;
|
||||
copy_ = copy;
|
||||
return true;
|
||||
}
|
||||
@@ -499,7 +499,7 @@ TEST(Reader, ParseString) {
|
||||
EXPECT_EQ(StrLen(e), h2.length_); \
|
||||
}
|
||||
|
||||
// String constant L"\xXX" can only specify character code in bytes, which is not endianness-neutral.
|
||||
// String constant L"\xXX" can only specify character code in bytes, which is not endianness-neutral.
|
||||
// And old compiler does not support u"" and U"" string literal. So here specify string literal by array of Ch.
|
||||
// In addition, GCC 4.8 generates -Wnarrowing warnings when character code >= 128 are assigned to signed integer types.
|
||||
// Therefore, utype is added for declaring unsigned array, and then cast it to Encoding::Ch.
|
||||
@@ -650,7 +650,7 @@ TEST(Reader, ParseString_Error) {
|
||||
|
||||
// http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt
|
||||
|
||||
// 3 Malformed sequences
|
||||
// 3 Malformed sequences
|
||||
|
||||
// 3.1 Unexpected continuation bytes
|
||||
{
|
||||
@@ -684,19 +684,19 @@ TEST(Reader, ParseString_Error) {
|
||||
}
|
||||
}
|
||||
|
||||
// 4 Overlong sequences
|
||||
// 4 Overlong sequences
|
||||
|
||||
// 4.1 Examples of an overlong ASCII character
|
||||
TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0xC0u, 0xAFu, '\"', ']', '\0'));
|
||||
TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0xE0u, 0x80u, 0xAFu, '\"', ']', '\0'));
|
||||
TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0xF0u, 0x80u, 0x80u, 0xAFu, '\"', ']', '\0'));
|
||||
|
||||
// 4.2 Maximum overlong sequences
|
||||
// 4.2 Maximum overlong sequences
|
||||
TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0xC1u, 0xBFu, '\"', ']', '\0'));
|
||||
TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0xE0u, 0x9Fu, 0xBFu, '\"', ']', '\0'));
|
||||
TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0xF0u, 0x8Fu, 0xBFu, 0xBFu, '\"', ']', '\0'));
|
||||
|
||||
// 4.3 Overlong representation of the NUL character
|
||||
// 4.3 Overlong representation of the NUL character
|
||||
TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0xC0u, 0x80u, '\"', ']', '\0'));
|
||||
TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0xE0u, 0x80u, 0x80u, '\"', ']', '\0'));
|
||||
TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0xF0u, 0x80u, 0x80u, 0x80u, '\"', ']', '\0'));
|
||||
@@ -790,14 +790,14 @@ struct ParseObjectHandler : BaseReaderHandler<UTF8<>, ParseObjectHandler> {
|
||||
|
||||
bool Default() { ADD_FAILURE(); return false; }
|
||||
bool Null() { EXPECT_EQ(8u, step_); step_++; return true; }
|
||||
bool Bool(bool b) {
|
||||
bool Bool(bool b) {
|
||||
switch(step_) {
|
||||
case 4: EXPECT_TRUE(b); step_++; return true;
|
||||
case 6: EXPECT_FALSE(b); step_++; return true;
|
||||
default: ADD_FAILURE(); return false;
|
||||
}
|
||||
}
|
||||
bool Int(int i) {
|
||||
bool Int(int i) {
|
||||
switch(step_) {
|
||||
case 10: EXPECT_EQ(123, i); step_++; return true;
|
||||
case 15: EXPECT_EQ(1, i); step_++; return true;
|
||||
@@ -808,7 +808,7 @@ struct ParseObjectHandler : BaseReaderHandler<UTF8<>, ParseObjectHandler> {
|
||||
}
|
||||
bool Uint(unsigned i) { return Int(static_cast<int>(i)); }
|
||||
bool Double(double d) { EXPECT_EQ(12u, step_); EXPECT_DOUBLE_EQ(3.1416, d); step_++; return true; }
|
||||
bool String(const char* str, size_t, bool) {
|
||||
bool String(const char* str, size_t, bool) {
|
||||
switch(step_) {
|
||||
case 1: EXPECT_STREQ("hello", str); step_++; return true;
|
||||
case 2: EXPECT_STREQ("world", str); step_++; return true;
|
||||
@@ -1045,7 +1045,7 @@ struct StreamTraits<CustomStringStream<Encoding> > {
|
||||
};
|
||||
|
||||
} // namespace rapidjson
|
||||
#endif
|
||||
#endif
|
||||
|
||||
TEST(Reader, CustomStringStream) {
|
||||
const char* json = "{ \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3] } ";
|
||||
@@ -1069,7 +1069,7 @@ public:
|
||||
return c == std::char_traits<char>::eof() ? '\0' : static_cast<Ch>(c);
|
||||
}
|
||||
|
||||
Ch Take() {
|
||||
Ch Take() {
|
||||
int c = is_.get();
|
||||
return c == std::char_traits<char>::eof() ? '\0' : static_cast<Ch>(c);
|
||||
}
|
||||
@@ -1097,7 +1097,7 @@ TEST(Reader, Parse_IStreamWrapper_StringStream) {
|
||||
Reader reader;
|
||||
ParseArrayHandler<4> h;
|
||||
reader.Parse(is, h);
|
||||
EXPECT_FALSE(reader.HasParseError());
|
||||
EXPECT_FALSE(reader.HasParseError());
|
||||
}
|
||||
|
||||
// Test iterative parsing.
|
||||
@@ -1195,7 +1195,7 @@ struct IterativeParsingReaderHandler {
|
||||
bool StartObject() { RAPIDJSON_ASSERT(LogCount < LogCapacity); Logs[LogCount++] = LOG_STARTOBJECT; return true; }
|
||||
|
||||
bool Key (const Ch*, SizeType, bool) { RAPIDJSON_ASSERT(LogCount < LogCapacity); Logs[LogCount++] = LOG_KEY; return true; }
|
||||
|
||||
|
||||
bool EndObject(SizeType c) {
|
||||
RAPIDJSON_ASSERT(LogCount < LogCapacity);
|
||||
Logs[LogCount++] = LOG_ENDOBJECT;
|
||||
@@ -1446,7 +1446,7 @@ TEST(Reader, ParseEmptyOnelineComment) {
|
||||
}
|
||||
|
||||
TEST(Reader, ParseMultipleCommentsInARow) {
|
||||
const char* json =
|
||||
const char* json =
|
||||
"{/* first comment *//* second */\n"
|
||||
"/* third */ /*fourth*/// last one\n"
|
||||
"\"hello\" : \"world\", \"t\" : true, \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3] }";
|
||||
@@ -1541,7 +1541,8 @@ struct NumbersAsStringsHandler {
|
||||
// 'str' is not null-terminated
|
||||
bool RawNumber(const char* str, SizeType length, bool) {
|
||||
EXPECT_TRUE(str != 0);
|
||||
EXPECT_TRUE(strncmp(str, "3.1416", length) == 0);
|
||||
EXPECT_TRUE(expected_len_ == length);
|
||||
EXPECT_TRUE(strncmp(str, expected_, length) == 0);
|
||||
return true;
|
||||
}
|
||||
bool String(const char*, SizeType, bool) { return true; }
|
||||
@@ -1550,24 +1551,84 @@ struct NumbersAsStringsHandler {
|
||||
bool EndObject(SizeType) { return true; }
|
||||
bool StartArray() { return true; }
|
||||
bool EndArray(SizeType) { return true; }
|
||||
|
||||
NumbersAsStringsHandler(const char* expected)
|
||||
: expected_(expected)
|
||||
, expected_len_(strlen(expected)) {}
|
||||
|
||||
const char* expected_;
|
||||
size_t expected_len_;
|
||||
};
|
||||
|
||||
TEST(Reader, NumbersAsStrings) {
|
||||
{
|
||||
const char* json = "{ \"pi\": 3.1416 } ";
|
||||
StringStream s(json);
|
||||
NumbersAsStringsHandler h;
|
||||
Reader reader;
|
||||
EXPECT_TRUE(reader.Parse<kParseNumbersAsStringsFlag>(s, h));
|
||||
}
|
||||
{
|
||||
char* json = StrDup("{ \"pi\": 3.1416 } ");
|
||||
InsituStringStream s(json);
|
||||
NumbersAsStringsHandler h;
|
||||
Reader reader;
|
||||
EXPECT_TRUE(reader.Parse<kParseInsituFlag|kParseNumbersAsStringsFlag>(s, h));
|
||||
free(json);
|
||||
}
|
||||
{
|
||||
const char* json = "{ \"pi\": 3.1416 } ";
|
||||
StringStream s(json);
|
||||
NumbersAsStringsHandler h("3.1416");
|
||||
Reader reader;
|
||||
EXPECT_TRUE(reader.Parse<kParseNumbersAsStringsFlag>(s, h));
|
||||
}
|
||||
{
|
||||
char* json = StrDup("{ \"pi\": 3.1416 } ");
|
||||
InsituStringStream s(json);
|
||||
NumbersAsStringsHandler h("3.1416");
|
||||
Reader reader;
|
||||
EXPECT_TRUE(reader.Parse<kParseInsituFlag|kParseNumbersAsStringsFlag>(s, h));
|
||||
free(json);
|
||||
}
|
||||
{
|
||||
const char* json = "{ \"gigabyte\": 1.0e9 } ";
|
||||
StringStream s(json);
|
||||
NumbersAsStringsHandler h("1.0e9");
|
||||
Reader reader;
|
||||
EXPECT_TRUE(reader.Parse<kParseNumbersAsStringsFlag>(s, h));
|
||||
}
|
||||
{
|
||||
char* json = StrDup("{ \"gigabyte\": 1.0e9 } ");
|
||||
InsituStringStream s(json);
|
||||
NumbersAsStringsHandler h("1.0e9");
|
||||
Reader reader;
|
||||
EXPECT_TRUE(reader.Parse<kParseInsituFlag|kParseNumbersAsStringsFlag>(s, h));
|
||||
free(json);
|
||||
}
|
||||
{
|
||||
const char* json = "{ \"pi\": 314.159e-2 } ";
|
||||
StringStream s(json);
|
||||
NumbersAsStringsHandler h("314.159e-2");
|
||||
Reader reader;
|
||||
EXPECT_TRUE(reader.Parse<kParseNumbersAsStringsFlag>(s, h));
|
||||
}
|
||||
{
|
||||
char* json = StrDup("{ \"gigabyte\": 314.159e-2 } ");
|
||||
InsituStringStream s(json);
|
||||
NumbersAsStringsHandler h("314.159e-2");
|
||||
Reader reader;
|
||||
EXPECT_TRUE(reader.Parse<kParseInsituFlag|kParseNumbersAsStringsFlag>(s, h));
|
||||
free(json);
|
||||
}
|
||||
{
|
||||
const char* json = "{ \"negative\": -1.54321 } ";
|
||||
StringStream s(json);
|
||||
NumbersAsStringsHandler h("-1.54321");
|
||||
Reader reader;
|
||||
EXPECT_TRUE(reader.Parse<kParseNumbersAsStringsFlag>(s, h));
|
||||
}
|
||||
{
|
||||
char* json = StrDup("{ \"negative\": -1.54321 } ");
|
||||
InsituStringStream s(json);
|
||||
NumbersAsStringsHandler h("-1.54321");
|
||||
Reader reader;
|
||||
EXPECT_TRUE(reader.Parse<kParseInsituFlag|kParseNumbersAsStringsFlag>(s, h));
|
||||
free(json);
|
||||
}
|
||||
{
|
||||
const char* json = "{ \"pi\": 314.159e-2 } ";
|
||||
std::stringstream ss(json);
|
||||
IStreamWrapper s(ss);
|
||||
NumbersAsStringsHandler h("314.159e-2");
|
||||
Reader reader;
|
||||
EXPECT_TRUE(reader.Parse<kParseNumbersAsStringsFlag>(s, h));
|
||||
}
|
||||
}
|
||||
|
||||
template <unsigned extraFlags>
|
||||
|
||||
Reference in New Issue
Block a user