Commit 677af55f authored by Milo Yip's avatar Milo Yip

Merge remote-tracking branch 'origin/master' into schema

parents 24f060f7 5dee3940
...@@ -65,6 +65,12 @@ Pointer("/hello").Swap(d, x); ...@@ -65,6 +65,12 @@ Pointer("/hello").Swap(d, x);
// { "project" : "RapidJSON", "stars" : 11, "a" : { "b" : [ null ] }, "hello" : "C++" } // { "project" : "RapidJSON", "stars" : 11, "a" : { "b" : [ null ] }, "hello" : "C++" }
// x becomes "world" // x becomes "world"
// Erase a member or element, return true if the value exists
bool success = Pointer("/a").Erase(d);
assert(success);
// { "project" : "RapidJSON", "stars" : 10 }
~~~ ~~~
# Helper Functions {#HelperFunctions} # Helper Functions {#HelperFunctions}
...@@ -88,6 +94,9 @@ Value& hello = GetValueByPointerWithDefault(d, "/hello", "world"); ...@@ -88,6 +94,9 @@ Value& hello = GetValueByPointerWithDefault(d, "/hello", "world");
Value x("C++"); Value x("C++");
SwapValueByPointer(d, "/hello", x); SwapValueByPointer(d, "/hello", x);
bool success = EraseValueByPointer(d, "/a");
assert(success);
~~~ ~~~
The conventions are shown here for comparison: The conventions are shown here for comparison:
...@@ -166,6 +175,8 @@ private: ...@@ -166,6 +175,8 @@ private:
}; };
~~~ ~~~
`Erase()` or `EraseValueByPointer()` does not need allocator. And they return `true` if the value is erased successfully.
# Error Handling {#ErrorHandling} # Error Handling {#ErrorHandling}
A `Pointer` parses a source string in its constructor. If there is parsing error, `Pointer::IsValid()` returns false. And you can use `Pointer::GetParseErrorCode()` and `GetParseErrorOffset()` to retrieve the error information. A `Pointer` parses a source string in its constructor. If there is parsing error, `Pointer::IsValid()` returns false. And you can use `Pointer::GetParseErrorCode()` and `GetParseErrorOffset()` to retrieve the error information.
...@@ -185,7 +196,7 @@ String Representation | URI Fragment Representation | Pointer Tokens (UTF-8) ...@@ -185,7 +196,7 @@ String Representation | URI Fragment Representation | Pointer Tokens (UTF-8)
`"/m~0n"` | `"#/m~0n"` | `{"m~n"}` `"/m~0n"` | `"#/m~0n"` | `{"m~n"}`
`"/ "` | `"#/%20"` | `{" "}` `"/ "` | `"#/%20"` | `{" "}`
`"/\0"` | `"#/%00"` | `{"\0"}` `"/\0"` | `"#/%00"` | `{"\0"}`
`"/\xE2\x82\xAC"` | `"#/%E2%82%AC"` | `{"\xE2\x82\xAC"}` `"/€"` | `"#/%E2%82%AC"` | `{"€"}`
RapidJSON fully support URI fragment representation. It automatically detects the pound sign during parsing. RapidJSON fully support URI fragment representation. It automatically detects the pound sign during parsing.
......
...@@ -97,7 +97,7 @@ public: ...@@ -97,7 +97,7 @@ public:
if (u == 1) return *this; if (u == 1) return *this;
if (*this == 1) return *this = u; if (*this == 1) return *this = u;
uint32_t k = 0; uint64_t k = 0;
for (size_t i = 0; i < count_; i++) { for (size_t i = 0; i < count_; i++) {
const uint64_t c = digits_[i] >> 32; const uint64_t c = digits_[i] >> 32;
const uint64_t d = digits_[i] & 0xFFFFFFFF; const uint64_t d = digits_[i] & 0xFFFFFFFF;
...@@ -246,7 +246,7 @@ private: ...@@ -246,7 +246,7 @@ private:
__extension__ typedef unsigned __int128 uint128; __extension__ typedef unsigned __int128 uint128;
uint128 p = static_cast<uint128>(a) * static_cast<uint128>(b); uint128 p = static_cast<uint128>(a) * static_cast<uint128>(b);
p += k; p += k;
*outHigh = p >> 64; *outHigh = static_cast<uint64_t>(p >> 64);
return static_cast<uint64_t>(p); return static_cast<uint64_t>(p);
#else #else
const uint64_t a0 = a & 0xFFFFFFFF, a1 = a >> 32, b0 = b & 0xFFFFFFFF, b1 = b >> 32; const uint64_t a0 = a & 0xFFFFFFFF, a1 = a >> 32, b0 = b & 0xFFFFFFFF, b1 = b >> 32;
......
...@@ -45,7 +45,7 @@ struct DiyFp { ...@@ -45,7 +45,7 @@ struct DiyFp {
uint64_t u64; uint64_t u64;
} u = { d }; } u = { d };
int biased_e = (u.u64 & kDpExponentMask) >> kDpSignificandSize; int biased_e = static_cast<int>((u.u64 & kDpExponentMask) >> kDpSignificandSize);
uint64_t significand = (u.u64 & kDpSignificandMask); uint64_t significand = (u.u64 & kDpSignificandMask);
if (biased_e != 0) { if (biased_e != 0) {
f = significand + kDpHiddenBit; f = significand + kDpHiddenBit;
...@@ -71,7 +71,7 @@ struct DiyFp { ...@@ -71,7 +71,7 @@ struct DiyFp {
#elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__) #elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__)
__extension__ typedef unsigned __int128 uint128; __extension__ typedef unsigned __int128 uint128;
uint128 p = static_cast<uint128>(f) * static_cast<uint128>(rhs.f); uint128 p = static_cast<uint128>(f) * static_cast<uint128>(rhs.f);
uint64_t h = p >> 64; uint64_t h = static_cast<uint64_t>(p >> 64);
uint64_t l = static_cast<uint64_t>(p); uint64_t l = static_cast<uint64_t>(p);
if (l & (uint64_t(1) << 63)) // rounding if (l & (uint64_t(1) << 63)) // rounding
h++; h++;
......
...@@ -23,29 +23,29 @@ namespace internal { ...@@ -23,29 +23,29 @@ namespace internal {
class Double { class Double {
public: public:
Double() {} Double() {}
Double(double d) : d(d) {} Double(double d) : d_(d) {}
Double(uint64_t u) : u(u) {} Double(uint64_t u) : u_(u) {}
double Value() const { return d; } double Value() const { return d_; }
uint64_t Uint64Value() const { return u; } uint64_t Uint64Value() const { return u_; }
double NextPositiveDouble() const { double NextPositiveDouble() const {
RAPIDJSON_ASSERT(!Sign()); RAPIDJSON_ASSERT(!Sign());
return Double(u + 1).Value(); return Double(u_ + 1).Value();
} }
bool Sign() const { return (u & kSignMask) != 0; } bool Sign() const { return (u_ & kSignMask) != 0; }
uint64_t Significand() const { return u & kSignificandMask; } uint64_t Significand() const { return u_ & kSignificandMask; }
int Exponent() const { return ((u & kExponentMask) >> kSignificandSize) - kExponentBias; } int Exponent() const { return static_cast<int>(((u_ & kExponentMask) >> kSignificandSize) - kExponentBias); }
bool IsNan() const { return (u & kExponentMask) == kExponentMask && Significand() != 0; } bool IsNan() const { return (u_ & kExponentMask) == kExponentMask && Significand() != 0; }
bool IsInf() const { return (u & kExponentMask) == kExponentMask && Significand() == 0; } bool IsInf() const { return (u_ & kExponentMask) == kExponentMask && Significand() == 0; }
bool IsNormal() const { return (u & kExponentMask) != 0 || Significand() == 0; } bool IsNormal() const { return (u_ & kExponentMask) != 0 || Significand() == 0; }
bool IsZero() const { return (u & (kExponentMask | kSignificandMask)) == 0; } bool IsZero() const { return (u_ & (kExponentMask | kSignificandMask)) == 0; }
uint64_t IntegerSignificand() const { return IsNormal() ? Significand() | kHiddenBit : Significand(); } uint64_t IntegerSignificand() const { return IsNormal() ? Significand() | kHiddenBit : Significand(); }
int IntegerExponent() const { return (IsNormal() ? Exponent() : kDenormalExponent) - kSignificandSize; } int IntegerExponent() const { return (IsNormal() ? Exponent() : kDenormalExponent) - kSignificandSize; }
uint64_t ToBias() const { return (u & kSignMask) ? ~u + 1 : u | kSignMask; } uint64_t ToBias() const { return (u_ & kSignMask) ? ~u_ + 1 : u_ | kSignMask; }
static unsigned EffectiveSignificandSize(int order) { static unsigned EffectiveSignificandSize(int order) {
if (order >= -1021) if (order >= -1021)
...@@ -66,8 +66,8 @@ private: ...@@ -66,8 +66,8 @@ private:
static const uint64_t kHiddenBit = RAPIDJSON_UINT64_C2(0x00100000, 0x00000000); static const uint64_t kHiddenBit = RAPIDJSON_UINT64_C2(0x00100000, 0x00000000);
union { union {
double d; double d_;
uint64_t u; uint64_t u_;
}; };
}; };
......
This diff is collapsed.
...@@ -241,8 +241,12 @@ ...@@ -241,8 +241,12 @@
alignment. User can customize by defining the RAPIDJSON_ALIGN function macro., alignment. User can customize by defining the RAPIDJSON_ALIGN function macro.,
*/ */
#ifndef RAPIDJSON_ALIGN #ifndef RAPIDJSON_ALIGN
#if RAPIDJSON_64BIT == 1
#define RAPIDJSON_ALIGN(x) ((x + 7u) & ~7u)
#else
#define RAPIDJSON_ALIGN(x) ((x + 3u) & ~3u) #define RAPIDJSON_ALIGN(x) ((x + 3u) & ~3u)
#endif #endif
#endif
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// RAPIDJSON_UINT64_C2 // RAPIDJSON_UINT64_C2
......
...@@ -276,7 +276,7 @@ TEST(Document, UTF16_Document) { ...@@ -276,7 +276,7 @@ TEST(Document, UTF16_Document) {
GenericValue< UTF16<> >& s = v[L"created_at"]; GenericValue< UTF16<> >& s = v[L"created_at"];
ASSERT_TRUE(s.IsString()); ASSERT_TRUE(s.IsString());
EXPECT_EQ(0, wcscmp(L"Wed Oct 30 17:13:20 +0000 2012", s.GetString())); EXPECT_EQ(0, memcmp(L"Wed Oct 30 17:13:20 +0000 2012", s.GetString(), (s.GetStringLength() + 1) * sizeof(wchar_t)));
} }
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS #if RAPIDJSON_HAS_CXX11_RVALUE_REFS
......
...@@ -45,12 +45,22 @@ TEST(Pointer, Parse) { ...@@ -45,12 +45,22 @@ TEST(Pointer, Parse) {
EXPECT_EQ(0u, p.GetTokenCount()); EXPECT_EQ(0u, p.GetTokenCount());
} }
{
Pointer p("/");
EXPECT_TRUE(p.IsValid());
EXPECT_EQ(1u, p.GetTokenCount());
EXPECT_EQ(0u, p.GetTokens()[0].length);
EXPECT_STREQ("", p.GetTokens()[0].name);
EXPECT_EQ(kPointerInvalidIndex, p.GetTokens()[0].index);
}
{ {
Pointer p("/foo"); Pointer p("/foo");
EXPECT_TRUE(p.IsValid()); EXPECT_TRUE(p.IsValid());
EXPECT_EQ(1u, p.GetTokenCount()); EXPECT_EQ(1u, p.GetTokenCount());
EXPECT_EQ(3u, p.GetTokens()[0].length); EXPECT_EQ(3u, p.GetTokens()[0].length);
EXPECT_STREQ("foo", p.GetTokens()[0].name); EXPECT_STREQ("foo", p.GetTokens()[0].name);
EXPECT_EQ(kPointerInvalidIndex, p.GetTokens()[0].index);
} }
#if RAPIDJSON_HAS_STDSTRING #if RAPIDJSON_HAS_STDSTRING
...@@ -60,6 +70,7 @@ TEST(Pointer, Parse) { ...@@ -60,6 +70,7 @@ TEST(Pointer, Parse) {
EXPECT_EQ(1u, p.GetTokenCount()); EXPECT_EQ(1u, p.GetTokenCount());
EXPECT_EQ(3u, p.GetTokens()[0].length); EXPECT_EQ(3u, p.GetTokens()[0].length);
EXPECT_STREQ("foo", p.GetTokens()[0].name); EXPECT_STREQ("foo", p.GetTokens()[0].name);
EXPECT_EQ(kPointerInvalidIndex, p.GetTokens()[0].index);
} }
#endif #endif
...@@ -69,6 +80,7 @@ TEST(Pointer, Parse) { ...@@ -69,6 +80,7 @@ TEST(Pointer, Parse) {
EXPECT_EQ(2u, p.GetTokenCount()); EXPECT_EQ(2u, p.GetTokenCount());
EXPECT_EQ(3u, p.GetTokens()[0].length); EXPECT_EQ(3u, p.GetTokens()[0].length);
EXPECT_STREQ("foo", p.GetTokens()[0].name); EXPECT_STREQ("foo", p.GetTokens()[0].name);
EXPECT_EQ(kPointerInvalidIndex, p.GetTokens()[0].index);
EXPECT_EQ(1u, p.GetTokens()[1].length); EXPECT_EQ(1u, p.GetTokens()[1].length);
EXPECT_STREQ("0", p.GetTokens()[1].name); EXPECT_STREQ("0", p.GetTokens()[1].name);
EXPECT_EQ(0u, p.GetTokens()[1].index); EXPECT_EQ(0u, p.GetTokens()[1].index);
...@@ -487,6 +499,14 @@ TEST(Pointer, Assignment) { ...@@ -487,6 +499,14 @@ TEST(Pointer, Assignment) {
EXPECT_EQ(1u, q.GetTokens()[1].length); EXPECT_EQ(1u, q.GetTokens()[1].length);
EXPECT_STREQ("0", q.GetTokens()[1].name); EXPECT_STREQ("0", q.GetTokens()[1].name);
EXPECT_EQ(0u, q.GetTokens()[1].index); EXPECT_EQ(0u, q.GetTokens()[1].index);
q = q;
EXPECT_TRUE(q.IsValid());
EXPECT_EQ(2u, q.GetTokenCount());
EXPECT_EQ(3u, q.GetTokens()[0].length);
EXPECT_STREQ("foo", q.GetTokens()[0].name);
EXPECT_EQ(1u, q.GetTokens()[1].length);
EXPECT_STREQ("0", q.GetTokens()[1].name);
EXPECT_EQ(0u, q.GetTokens()[1].index);
} }
// Static tokens // Static tokens
...@@ -504,6 +524,26 @@ TEST(Pointer, Assignment) { ...@@ -504,6 +524,26 @@ TEST(Pointer, Assignment) {
} }
} }
TEST(Pointer, Append) {
{
Pointer p;
Pointer q = p.Append("foo");
EXPECT_TRUE(Pointer("/foo") == q);
q = q.Append(0);
EXPECT_TRUE(Pointer("/foo/0") == q);
q = q.Append("");
EXPECT_TRUE(Pointer("/foo/0/") == q);
}
#if RAPIDJSON_HAS_STDSTRING
{
Pointer p;
Pointer q = p.Append(std::string("foo"));
EXPECT_TRUE(Pointer("/foo") == q);
}
#endif
}
TEST(Pointer, Equality) { TEST(Pointer, Equality) {
EXPECT_TRUE(Pointer("/foo/0") == Pointer("/foo/0")); EXPECT_TRUE(Pointer("/foo/0") == Pointer("/foo/0"));
EXPECT_FALSE(Pointer("/foo/0") == Pointer("/foo/1")); EXPECT_FALSE(Pointer("/foo/0") == Pointer("/foo/1"));
...@@ -824,6 +864,21 @@ TEST(Pointer, Swap_NoAllocator) { ...@@ -824,6 +864,21 @@ TEST(Pointer, Swap_NoAllocator) {
EXPECT_STREQ("bar", d["foo"][1].GetString()); EXPECT_STREQ("bar", d["foo"][1].GetString());
} }
TEST(Pointer, Erase) {
Document d;
d.Parse(kJson);
EXPECT_FALSE(Pointer("").Erase(d));
EXPECT_FALSE(Pointer("/foo/nonexist").Erase(d));
EXPECT_TRUE(Pointer("/foo/0").Erase(d));
EXPECT_EQ(1u, d["foo"].Size());
EXPECT_STREQ("baz", d["foo"][0].GetString());
EXPECT_TRUE(Pointer("/foo/0").Erase(d));
EXPECT_TRUE(d["foo"].Empty());
EXPECT_TRUE(Pointer("/foo").Erase(d));
EXPECT_TRUE(Pointer("/foo").Get(d) == 0);
}
TEST(Pointer, CreateValueByPointer) { TEST(Pointer, CreateValueByPointer) {
Document d; Document d;
Document::AllocatorType& a = d.GetAllocator(); Document::AllocatorType& a = d.GetAllocator();
...@@ -1325,6 +1380,36 @@ TEST(Pointer, SwapValueByPointer_NoAllocator) { ...@@ -1325,6 +1380,36 @@ TEST(Pointer, SwapValueByPointer_NoAllocator) {
EXPECT_STREQ("baz", d["foo"][1].GetString()); EXPECT_STREQ("baz", d["foo"][1].GetString());
} }
TEST(Pointer, EraseValueByPointer_Pointer) {
Document d;
d.Parse(kJson);
EXPECT_FALSE(EraseValueByPointer(d, Pointer("")));
EXPECT_FALSE(Pointer("/foo/nonexist").Erase(d));
EXPECT_TRUE(EraseValueByPointer(d, Pointer("/foo/0")));
EXPECT_EQ(1u, d["foo"].Size());
EXPECT_STREQ("baz", d["foo"][0].GetString());
EXPECT_TRUE(EraseValueByPointer(d, Pointer("/foo/0")));
EXPECT_TRUE(d["foo"].Empty());
EXPECT_TRUE(EraseValueByPointer(d, Pointer("/foo")));
EXPECT_TRUE(Pointer("/foo").Get(d) == 0);
}
TEST(Pointer, EraseValueByPointer_String) {
Document d;
d.Parse(kJson);
EXPECT_FALSE(EraseValueByPointer(d, ""));
EXPECT_FALSE(Pointer("/foo/nonexist").Erase(d));
EXPECT_TRUE(EraseValueByPointer(d, "/foo/0"));
EXPECT_EQ(1u, d["foo"].Size());
EXPECT_STREQ("baz", d["foo"][0].GetString());
EXPECT_TRUE(EraseValueByPointer(d, "/foo/0"));
EXPECT_TRUE(d["foo"].Empty());
EXPECT_TRUE(EraseValueByPointer(d, "/foo"));
EXPECT_TRUE(Pointer("/foo").Get(d) == 0);
}
TEST(Pointer, Ambiguity) { TEST(Pointer, Ambiguity) {
{ {
Document d; Document d;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment