rj_schema 1.0.0 → 1.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (30) hide show
  1. checksums.yaml +4 -4
  2. data/ext/rj_schema/rapidjson/CMakeLists.txt +23 -1
  3. data/ext/rj_schema/rapidjson/appveyor.yml +49 -1
  4. data/ext/rj_schema/rapidjson/bin/types/alotofkeys.json +502 -0
  5. data/ext/rj_schema/rapidjson/bin/unittestschema/idandref.json +69 -0
  6. data/ext/rj_schema/rapidjson/doc/stream.md +7 -7
  7. data/ext/rj_schema/rapidjson/doc/stream.zh-cn.md +1 -1
  8. data/ext/rj_schema/rapidjson/doc/tutorial.md +15 -15
  9. data/ext/rj_schema/rapidjson/example/schemavalidator/schemavalidator.cpp +2 -0
  10. data/ext/rj_schema/rapidjson/example/traverseaspointer.cpp +39 -0
  11. data/ext/rj_schema/rapidjson/include/rapidjson/allocators.h +460 -52
  12. data/ext/rj_schema/rapidjson/include/rapidjson/document.h +350 -60
  13. data/ext/rj_schema/rapidjson/include/rapidjson/internal/strfunc.h +14 -0
  14. data/ext/rj_schema/rapidjson/include/rapidjson/pointer.h +68 -1
  15. data/ext/rj_schema/rapidjson/include/rapidjson/rapidjson.h +60 -11
  16. data/ext/rj_schema/rapidjson/include/rapidjson/schema.h +249 -102
  17. data/ext/rj_schema/rapidjson/include/rapidjson/uri.h +466 -0
  18. data/ext/rj_schema/rapidjson/test/perftest/perftest.h +5 -4
  19. data/ext/rj_schema/rapidjson/test/perftest/rapidjsontest.cpp +20 -2
  20. data/ext/rj_schema/rapidjson/test/unittest/CMakeLists.txt +2 -0
  21. data/ext/rj_schema/rapidjson/test/unittest/allocatorstest.cpp +193 -1
  22. data/ext/rj_schema/rapidjson/test/unittest/documenttest.cpp +2 -0
  23. data/ext/rj_schema/rapidjson/test/unittest/platformtest.cpp +40 -0
  24. data/ext/rj_schema/rapidjson/test/unittest/pointertest.cpp +62 -2
  25. data/ext/rj_schema/rapidjson/test/unittest/schematest.cpp +372 -7
  26. data/ext/rj_schema/rapidjson/test/unittest/uritest.cpp +718 -0
  27. data/ext/rj_schema/rapidjson/test/unittest/valuetest.cpp +12 -2
  28. data/ext/rj_schema/rj_schema.cpp +3 -10
  29. data/lib/rj_schema.rb +1 -1
  30. metadata +9 -3
@@ -42,12 +42,21 @@ RAPIDJSON_DIAG_OFF(4244) // conversion from kXxxFlags to 'uint16_t', possible lo
42
42
  RAPIDJSON_DIAG_OFF(effc++)
43
43
  #endif // __GNUC__
44
44
 
45
+ #ifdef GetObject
46
+ // see https://github.com/Tencent/rapidjson/issues/1448
47
+ // a former included windows.h might have defined a macro called GetObject, which affects
48
+ // GetObject defined here. This ensures the macro does not get applied
49
+ #pragma push_macro("GetObject")
50
+ #define RAPIDJSON_WINDOWS_GETOBJECT_WORKAROUND_APPLIED
51
+ #undef GetObject
52
+ #endif
53
+
45
54
  #ifndef RAPIDJSON_NOMEMBERITERATORCLASS
46
55
  #include <iterator> // std::random_access_iterator_tag
47
56
  #endif
48
57
 
49
- #if RAPIDJSON_HAS_CXX11_RVALUE_REFS
50
- #include <utility> // std::move
58
+ #if RAPIDJSON_USE_MEMBERSMAP
59
+ #include <map> // std::multimap
51
60
  #endif
52
61
 
53
62
  RAPIDJSON_NAMESPACE_BEGIN
@@ -732,18 +741,8 @@ public:
732
741
  template <typename SourceAllocator>
733
742
  GenericValue(const GenericValue<Encoding,SourceAllocator>& rhs, Allocator& allocator, bool copyConstStrings = false) {
734
743
  switch (rhs.GetType()) {
735
- case kObjectType: {
736
- SizeType count = rhs.data_.o.size;
737
- Member* lm = reinterpret_cast<Member*>(allocator.Malloc(count * sizeof(Member)));
738
- const typename GenericValue<Encoding,SourceAllocator>::Member* rm = rhs.GetMembersPointer();
739
- for (SizeType i = 0; i < count; i++) {
740
- new (&lm[i].name) GenericValue(rm[i].name, allocator, copyConstStrings);
741
- new (&lm[i].value) GenericValue(rm[i].value, allocator, copyConstStrings);
742
- }
743
- data_.f.flags = kObjectFlag;
744
- data_.o.size = data_.o.capacity = count;
745
- SetMembersPointer(lm);
746
- }
744
+ case kObjectType:
745
+ DoCopyMembers(rhs, allocator, copyConstStrings);
747
746
  break;
748
747
  case kArrayType: {
749
748
  SizeType count = rhs.data_.a.size;
@@ -879,25 +878,30 @@ public:
879
878
  /*! Need to destruct elements of array, members of object, or copy-string.
880
879
  */
881
880
  ~GenericValue() {
882
- if (Allocator::kNeedFree) { // Shortcut by Allocator's trait
881
+ // With RAPIDJSON_USE_MEMBERSMAP, the maps need to be destroyed to release
882
+ // their Allocator if it's refcounted (e.g. MemoryPoolAllocator).
883
+ if (Allocator::kNeedFree || (RAPIDJSON_USE_MEMBERSMAP+0 &&
884
+ internal::IsRefCounted<Allocator>::Value)) {
883
885
  switch(data_.f.flags) {
884
886
  case kArrayFlag:
885
887
  {
886
888
  GenericValue* e = GetElementsPointer();
887
889
  for (GenericValue* v = e; v != e + data_.a.size; ++v)
888
890
  v->~GenericValue();
889
- Allocator::Free(e);
891
+ if (Allocator::kNeedFree) { // Shortcut by Allocator's trait
892
+ Allocator::Free(e);
893
+ }
890
894
  }
891
895
  break;
892
896
 
893
897
  case kObjectFlag:
894
- for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m)
895
- m->~Member();
896
- Allocator::Free(GetMembersPointer());
898
+ DoFreeMembers();
897
899
  break;
898
900
 
899
901
  case kCopyStringFlag:
900
- Allocator::Free(const_cast<Ch*>(GetStringPointer()));
902
+ if (Allocator::kNeedFree) { // Shortcut by Allocator's trait
903
+ Allocator::Free(const_cast<Ch*>(GetStringPointer()));
904
+ }
901
905
  break;
902
906
 
903
907
  default:
@@ -916,8 +920,13 @@ public:
916
920
  */
917
921
  GenericValue& operator=(GenericValue& rhs) RAPIDJSON_NOEXCEPT {
918
922
  if (RAPIDJSON_LIKELY(this != &rhs)) {
923
+ // Can't destroy "this" before assigning "rhs", otherwise "rhs"
924
+ // could be used after free if it's an sub-Value of "this",
925
+ // hence the temporary danse.
926
+ GenericValue temp;
927
+ temp.RawAssign(rhs);
919
928
  this->~GenericValue();
920
- RawAssign(rhs);
929
+ RawAssign(temp);
921
930
  }
922
931
  return *this;
923
932
  }
@@ -1083,6 +1092,7 @@ public:
1083
1092
  */
1084
1093
  template <typename T> RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue<T>), (bool)) operator!=(const T& rhs) const { return !(*this == rhs); }
1085
1094
 
1095
+ #ifndef __cpp_lib_three_way_comparison
1086
1096
  //! Equal-to operator with arbitrary types (symmetric version)
1087
1097
  /*! \return (rhs == lhs)
1088
1098
  */
@@ -1093,6 +1103,7 @@ public:
1093
1103
  */
1094
1104
  template <typename T> friend RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue<T>), (bool)) operator!=(const T& lhs, const GenericValue& rhs) { return !(rhs == lhs); }
1095
1105
  //@}
1106
+ #endif
1096
1107
 
1097
1108
  //!@name Type
1098
1109
  //@{
@@ -1258,10 +1269,7 @@ public:
1258
1269
  */
1259
1270
  GenericValue& MemberReserve(SizeType newCapacity, Allocator &allocator) {
1260
1271
  RAPIDJSON_ASSERT(IsObject());
1261
- if (newCapacity > data_.o.capacity) {
1262
- SetMembersPointer(reinterpret_cast<Member*>(allocator.Realloc(GetMembersPointer(), data_.o.capacity * sizeof(Member), newCapacity * sizeof(Member))));
1263
- data_.o.capacity = newCapacity;
1264
- }
1272
+ DoReserveMembers(newCapacity, allocator);
1265
1273
  return *this;
1266
1274
  }
1267
1275
 
@@ -1335,11 +1343,7 @@ public:
1335
1343
  MemberIterator FindMember(const GenericValue<Encoding, SourceAllocator>& name) {
1336
1344
  RAPIDJSON_ASSERT(IsObject());
1337
1345
  RAPIDJSON_ASSERT(name.IsString());
1338
- MemberIterator member = MemberBegin();
1339
- for ( ; member != MemberEnd(); ++member)
1340
- if (name.StringEqual(member->name))
1341
- break;
1342
- return member;
1346
+ return DoFindMember(name);
1343
1347
  }
1344
1348
  template <typename SourceAllocator> ConstMemberIterator FindMember(const GenericValue<Encoding, SourceAllocator>& name) const { return const_cast<GenericValue&>(*this).FindMember(name); }
1345
1349
 
@@ -1368,14 +1372,7 @@ public:
1368
1372
  GenericValue& AddMember(GenericValue& name, GenericValue& value, Allocator& allocator) {
1369
1373
  RAPIDJSON_ASSERT(IsObject());
1370
1374
  RAPIDJSON_ASSERT(name.IsString());
1371
-
1372
- ObjectData& o = data_.o;
1373
- if (o.size >= o.capacity)
1374
- MemberReserve(o.capacity == 0 ? kDefaultObjectCapacity : (o.capacity + (o.capacity + 1) / 2), allocator);
1375
- Member* members = GetMembersPointer();
1376
- members[o.size].name.RawAssign(name);
1377
- members[o.size].value.RawAssign(value);
1378
- o.size++;
1375
+ DoAddMember(name, value, allocator);
1379
1376
  return *this;
1380
1377
  }
1381
1378
 
@@ -1509,9 +1506,7 @@ public:
1509
1506
  */
1510
1507
  void RemoveAllMembers() {
1511
1508
  RAPIDJSON_ASSERT(IsObject());
1512
- for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m)
1513
- m->~Member();
1514
- data_.o.size = 0;
1509
+ DoClearMembers();
1515
1510
  }
1516
1511
 
1517
1512
  //! Remove a member in object by its name.
@@ -1555,14 +1550,7 @@ public:
1555
1550
  RAPIDJSON_ASSERT(data_.o.size > 0);
1556
1551
  RAPIDJSON_ASSERT(GetMembersPointer() != 0);
1557
1552
  RAPIDJSON_ASSERT(m >= MemberBegin() && m < MemberEnd());
1558
-
1559
- MemberIterator last(GetMembersPointer() + (data_.o.size - 1));
1560
- if (data_.o.size > 1 && m != last)
1561
- *m = *last; // Move the last one to this place
1562
- else
1563
- m->~Member(); // Only one left, just destroy
1564
- --data_.o.size;
1565
- return m;
1553
+ return DoRemoveMember(m);
1566
1554
  }
1567
1555
 
1568
1556
  //! Remove a member from an object by iterator.
@@ -1594,13 +1582,7 @@ public:
1594
1582
  RAPIDJSON_ASSERT(first >= MemberBegin());
1595
1583
  RAPIDJSON_ASSERT(first <= last);
1596
1584
  RAPIDJSON_ASSERT(last <= MemberEnd());
1597
-
1598
- MemberIterator pos = MemberBegin() + (first - MemberBegin());
1599
- for (MemberIterator itr = pos; itr != last; ++itr)
1600
- itr->~Member();
1601
- std::memmove(static_cast<void*>(&*pos), &*last, static_cast<size_t>(MemberEnd() - last) * sizeof(Member));
1602
- data_.o.size -= static_cast<SizeType>(last - first);
1603
- return pos;
1585
+ return DoEraseMembers(first, last);
1604
1586
  }
1605
1587
 
1606
1588
  //! Erase a member in object by its name.
@@ -1629,7 +1611,9 @@ public:
1629
1611
  }
1630
1612
 
1631
1613
  Object GetObject() { RAPIDJSON_ASSERT(IsObject()); return Object(*this); }
1614
+ Object GetObj() { RAPIDJSON_ASSERT(IsObject()); return Object(*this); }
1632
1615
  ConstObject GetObject() const { RAPIDJSON_ASSERT(IsObject()); return ConstObject(*this); }
1616
+ ConstObject GetObj() const { RAPIDJSON_ASSERT(IsObject()); return ConstObject(*this); }
1633
1617
 
1634
1618
  //@}
1635
1619
 
@@ -1851,12 +1835,12 @@ public:
1851
1835
  //!@name String
1852
1836
  //@{
1853
1837
 
1854
- const Ch* GetString() const { RAPIDJSON_ASSERT(IsString()); return (data_.f.flags & kInlineStrFlag) ? data_.ss.str : GetStringPointer(); }
1838
+ const Ch* GetString() const { RAPIDJSON_ASSERT(IsString()); return DataString(data_); }
1855
1839
 
1856
1840
  //! Get the length of string.
1857
1841
  /*! Since rapidjson permits "\\u0000" in the json string, strlen(v.GetString()) may not equal to v.GetStringLength().
1858
1842
  */
1859
- SizeType GetStringLength() const { RAPIDJSON_ASSERT(IsString()); return ((data_.f.flags & kInlineStrFlag) ? (data_.ss.GetLength()) : data_.s.length); }
1843
+ SizeType GetStringLength() const { RAPIDJSON_ASSERT(IsString()); return DataStringLength(data_); }
1860
1844
 
1861
1845
  //! Set this value as a string without copying source string.
1862
1846
  /*! This version has better performance with supplied length, and also support string containing null character.
@@ -1967,7 +1951,7 @@ public:
1967
1951
  case kArrayType:
1968
1952
  if (RAPIDJSON_UNLIKELY(!handler.StartArray()))
1969
1953
  return false;
1970
- for (const GenericValue* v = Begin(); v != End(); ++v)
1954
+ for (ConstValueIterator v = Begin(); v != End(); ++v)
1971
1955
  if (RAPIDJSON_UNLIKELY(!v->Accept(handler)))
1972
1956
  return false;
1973
1957
  return handler.EndArray(data_.a.size);
@@ -2105,6 +2089,13 @@ private:
2105
2089
  Flag f;
2106
2090
  }; // 16 bytes in 32-bit mode, 24 bytes in 64-bit mode, 16 bytes in 64-bit with RAPIDJSON_48BITPOINTER_OPTIMIZATION
2107
2091
 
2092
+ static RAPIDJSON_FORCEINLINE const Ch* DataString(const Data& data) {
2093
+ return (data.f.flags & kInlineStrFlag) ? data.ss.str : RAPIDJSON_GETPOINTER(Ch, data.s.str);
2094
+ }
2095
+ static RAPIDJSON_FORCEINLINE SizeType DataStringLength(const Data& data) {
2096
+ return (data.f.flags & kInlineStrFlag) ? data.ss.GetLength() : data.s.length;
2097
+ }
2098
+
2108
2099
  RAPIDJSON_FORCEINLINE const Ch* GetStringPointer() const { return RAPIDJSON_GETPOINTER(Ch, data_.s.str); }
2109
2100
  RAPIDJSON_FORCEINLINE const Ch* SetStringPointer(const Ch* str) { return RAPIDJSON_SETPOINTER(Ch, data_.s.str, str); }
2110
2101
  RAPIDJSON_FORCEINLINE GenericValue* GetElementsPointer() const { return RAPIDJSON_GETPOINTER(GenericValue, data_.a.elements); }
@@ -2112,6 +2103,286 @@ private:
2112
2103
  RAPIDJSON_FORCEINLINE Member* GetMembersPointer() const { return RAPIDJSON_GETPOINTER(Member, data_.o.members); }
2113
2104
  RAPIDJSON_FORCEINLINE Member* SetMembersPointer(Member* members) { return RAPIDJSON_SETPOINTER(Member, data_.o.members, members); }
2114
2105
 
2106
+ #if RAPIDJSON_USE_MEMBERSMAP
2107
+
2108
+ struct MapTraits {
2109
+ struct Less {
2110
+ bool operator()(const Data& s1, const Data& s2) const {
2111
+ SizeType n1 = DataStringLength(s1), n2 = DataStringLength(s2);
2112
+ int cmp = std::memcmp(DataString(s1), DataString(s2), sizeof(Ch) * (n1 < n2 ? n1 : n2));
2113
+ return cmp < 0 || (cmp == 0 && n1 < n2);
2114
+ }
2115
+ };
2116
+ typedef std::pair<const Data, SizeType> Pair;
2117
+ typedef std::multimap<Data, SizeType, Less, StdAllocator<Pair, Allocator> > Map;
2118
+ typedef typename Map::iterator Iterator;
2119
+ };
2120
+ typedef typename MapTraits::Map Map;
2121
+ typedef typename MapTraits::Less MapLess;
2122
+ typedef typename MapTraits::Pair MapPair;
2123
+ typedef typename MapTraits::Iterator MapIterator;
2124
+
2125
+ //
2126
+ // Layout of the members' map/array, re(al)located according to the needed capacity:
2127
+ //
2128
+ // {Map*}<>{capacity}<>{Member[capacity]}<>{MapIterator[capacity]}
2129
+ //
2130
+ // (where <> stands for the RAPIDJSON_ALIGN-ment, if needed)
2131
+ //
2132
+
2133
+ static RAPIDJSON_FORCEINLINE size_t GetMapLayoutSize(SizeType capacity) {
2134
+ return RAPIDJSON_ALIGN(sizeof(Map*)) +
2135
+ RAPIDJSON_ALIGN(sizeof(SizeType)) +
2136
+ RAPIDJSON_ALIGN(capacity * sizeof(Member)) +
2137
+ capacity * sizeof(MapIterator);
2138
+ }
2139
+
2140
+ static RAPIDJSON_FORCEINLINE SizeType &GetMapCapacity(Map* &map) {
2141
+ return *reinterpret_cast<SizeType*>(reinterpret_cast<uintptr_t>(&map) +
2142
+ RAPIDJSON_ALIGN(sizeof(Map*)));
2143
+ }
2144
+
2145
+ static RAPIDJSON_FORCEINLINE Member* GetMapMembers(Map* &map) {
2146
+ return reinterpret_cast<Member*>(reinterpret_cast<uintptr_t>(&map) +
2147
+ RAPIDJSON_ALIGN(sizeof(Map*)) +
2148
+ RAPIDJSON_ALIGN(sizeof(SizeType)));
2149
+ }
2150
+
2151
+ static RAPIDJSON_FORCEINLINE MapIterator* GetMapIterators(Map* &map) {
2152
+ return reinterpret_cast<MapIterator*>(reinterpret_cast<uintptr_t>(&map) +
2153
+ RAPIDJSON_ALIGN(sizeof(Map*)) +
2154
+ RAPIDJSON_ALIGN(sizeof(SizeType)) +
2155
+ RAPIDJSON_ALIGN(GetMapCapacity(map) * sizeof(Member)));
2156
+ }
2157
+
2158
+ static RAPIDJSON_FORCEINLINE Map* &GetMap(Member* members) {
2159
+ RAPIDJSON_ASSERT(members != 0);
2160
+ return *reinterpret_cast<Map**>(reinterpret_cast<uintptr_t>(members) -
2161
+ RAPIDJSON_ALIGN(sizeof(SizeType)) -
2162
+ RAPIDJSON_ALIGN(sizeof(Map*)));
2163
+ }
2164
+
2165
+ // Some compilers' debug mechanisms want all iterators to be destroyed, for their accounting..
2166
+ RAPIDJSON_FORCEINLINE MapIterator DropMapIterator(MapIterator& rhs) {
2167
+ #if RAPIDJSON_HAS_CXX11
2168
+ MapIterator ret = std::move(rhs);
2169
+ #else
2170
+ MapIterator ret = rhs;
2171
+ #endif
2172
+ rhs.~MapIterator();
2173
+ return ret;
2174
+ }
2175
+
2176
+ Map* &DoReallocMap(Map** oldMap, SizeType newCapacity, Allocator& allocator) {
2177
+ Map **newMap = static_cast<Map**>(allocator.Malloc(GetMapLayoutSize(newCapacity)));
2178
+ GetMapCapacity(*newMap) = newCapacity;
2179
+ if (!oldMap) {
2180
+ *newMap = new (allocator.Malloc(sizeof(Map))) Map(MapLess(), allocator);
2181
+ }
2182
+ else {
2183
+ *newMap = *oldMap;
2184
+ size_t count = (*oldMap)->size();
2185
+ std::memcpy(static_cast<void*>(GetMapMembers(*newMap)),
2186
+ static_cast<void*>(GetMapMembers(*oldMap)),
2187
+ count * sizeof(Member));
2188
+ MapIterator *oldIt = GetMapIterators(*oldMap),
2189
+ *newIt = GetMapIterators(*newMap);
2190
+ while (count--) {
2191
+ new (&newIt[count]) MapIterator(DropMapIterator(oldIt[count]));
2192
+ }
2193
+ Allocator::Free(oldMap);
2194
+ }
2195
+ return *newMap;
2196
+ }
2197
+
2198
+ RAPIDJSON_FORCEINLINE Member* DoAllocMembers(SizeType capacity, Allocator& allocator) {
2199
+ return GetMapMembers(DoReallocMap(0, capacity, allocator));
2200
+ }
2201
+
2202
+ void DoReserveMembers(SizeType newCapacity, Allocator& allocator) {
2203
+ ObjectData& o = data_.o;
2204
+ if (newCapacity > o.capacity) {
2205
+ Member* oldMembers = GetMembersPointer();
2206
+ Map **oldMap = oldMembers ? &GetMap(oldMembers) : 0,
2207
+ *&newMap = DoReallocMap(oldMap, newCapacity, allocator);
2208
+ RAPIDJSON_SETPOINTER(Member, o.members, GetMapMembers(newMap));
2209
+ o.capacity = newCapacity;
2210
+ }
2211
+ }
2212
+
2213
+ template <typename SourceAllocator>
2214
+ MemberIterator DoFindMember(const GenericValue<Encoding, SourceAllocator>& name) {
2215
+ if (Member* members = GetMembersPointer()) {
2216
+ Map* &map = GetMap(members);
2217
+ MapIterator mit = map->find(reinterpret_cast<const Data&>(name.data_));
2218
+ if (mit != map->end()) {
2219
+ return MemberIterator(&members[mit->second]);
2220
+ }
2221
+ }
2222
+ return MemberEnd();
2223
+ }
2224
+
2225
+ void DoClearMembers() {
2226
+ if (Member* members = GetMembersPointer()) {
2227
+ Map* &map = GetMap(members);
2228
+ MapIterator* mit = GetMapIterators(map);
2229
+ for (SizeType i = 0; i < data_.o.size; i++) {
2230
+ map->erase(DropMapIterator(mit[i]));
2231
+ members[i].~Member();
2232
+ }
2233
+ data_.o.size = 0;
2234
+ }
2235
+ }
2236
+
2237
+ void DoFreeMembers() {
2238
+ if (Member* members = GetMembersPointer()) {
2239
+ GetMap(members)->~Map();
2240
+ for (SizeType i = 0; i < data_.o.size; i++) {
2241
+ members[i].~Member();
2242
+ }
2243
+ if (Allocator::kNeedFree) { // Shortcut by Allocator's trait
2244
+ Map** map = &GetMap(members);
2245
+ Allocator::Free(*map);
2246
+ Allocator::Free(map);
2247
+ }
2248
+ }
2249
+ }
2250
+
2251
+ #else // !RAPIDJSON_USE_MEMBERSMAP
2252
+
2253
+ RAPIDJSON_FORCEINLINE Member* DoAllocMembers(SizeType capacity, Allocator& allocator) {
2254
+ return Malloc<Member>(allocator, capacity);
2255
+ }
2256
+
2257
+ void DoReserveMembers(SizeType newCapacity, Allocator& allocator) {
2258
+ ObjectData& o = data_.o;
2259
+ if (newCapacity > o.capacity) {
2260
+ Member* newMembers = Realloc<Member>(allocator, GetMembersPointer(), o.capacity, newCapacity);
2261
+ RAPIDJSON_SETPOINTER(Member, o.members, newMembers);
2262
+ o.capacity = newCapacity;
2263
+ }
2264
+ }
2265
+
2266
+ template <typename SourceAllocator>
2267
+ MemberIterator DoFindMember(const GenericValue<Encoding, SourceAllocator>& name) {
2268
+ MemberIterator member = MemberBegin();
2269
+ for ( ; member != MemberEnd(); ++member)
2270
+ if (name.StringEqual(member->name))
2271
+ break;
2272
+ return member;
2273
+ }
2274
+
2275
+ void DoClearMembers() {
2276
+ for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m)
2277
+ m->~Member();
2278
+ data_.o.size = 0;
2279
+ }
2280
+
2281
+ void DoFreeMembers() {
2282
+ for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m)
2283
+ m->~Member();
2284
+ Allocator::Free(GetMembersPointer());
2285
+ }
2286
+
2287
+ #endif // !RAPIDJSON_USE_MEMBERSMAP
2288
+
2289
+ void DoAddMember(GenericValue& name, GenericValue& value, Allocator& allocator) {
2290
+ ObjectData& o = data_.o;
2291
+ if (o.size >= o.capacity)
2292
+ DoReserveMembers(o.capacity ? (o.capacity + (o.capacity + 1) / 2) : kDefaultObjectCapacity, allocator);
2293
+ Member* members = GetMembersPointer();
2294
+ Member* m = members + o.size;
2295
+ m->name.RawAssign(name);
2296
+ m->value.RawAssign(value);
2297
+ #if RAPIDJSON_USE_MEMBERSMAP
2298
+ Map* &map = GetMap(members);
2299
+ MapIterator* mit = GetMapIterators(map);
2300
+ new (&mit[o.size]) MapIterator(map->insert(MapPair(m->name.data_, o.size)));
2301
+ #endif
2302
+ ++o.size;
2303
+ }
2304
+
2305
+ MemberIterator DoRemoveMember(MemberIterator m) {
2306
+ ObjectData& o = data_.o;
2307
+ Member* members = GetMembersPointer();
2308
+ #if RAPIDJSON_USE_MEMBERSMAP
2309
+ Map* &map = GetMap(members);
2310
+ MapIterator* mit = GetMapIterators(map);
2311
+ SizeType mpos = static_cast<SizeType>(&*m - members);
2312
+ map->erase(DropMapIterator(mit[mpos]));
2313
+ #endif
2314
+ MemberIterator last(members + (o.size - 1));
2315
+ if (o.size > 1 && m != last) {
2316
+ #if RAPIDJSON_USE_MEMBERSMAP
2317
+ new (&mit[mpos]) MapIterator(DropMapIterator(mit[&*last - members]));
2318
+ mit[mpos]->second = mpos;
2319
+ #endif
2320
+ *m = *last; // Move the last one to this place
2321
+ }
2322
+ else {
2323
+ m->~Member(); // Only one left, just destroy
2324
+ }
2325
+ --o.size;
2326
+ return m;
2327
+ }
2328
+
2329
+ MemberIterator DoEraseMembers(ConstMemberIterator first, ConstMemberIterator last) {
2330
+ ObjectData& o = data_.o;
2331
+ MemberIterator beg = MemberBegin(),
2332
+ pos = beg + (first - beg),
2333
+ end = MemberEnd();
2334
+ #if RAPIDJSON_USE_MEMBERSMAP
2335
+ Map* &map = GetMap(GetMembersPointer());
2336
+ MapIterator* mit = GetMapIterators(map);
2337
+ #endif
2338
+ for (MemberIterator itr = pos; itr != last; ++itr) {
2339
+ #if RAPIDJSON_USE_MEMBERSMAP
2340
+ map->erase(DropMapIterator(mit[itr - beg]));
2341
+ #endif
2342
+ itr->~Member();
2343
+ }
2344
+ #if RAPIDJSON_USE_MEMBERSMAP
2345
+ if (first != last) {
2346
+ // Move remaining members/iterators
2347
+ MemberIterator next = pos + (last - first);
2348
+ for (MemberIterator itr = pos; next != end; ++itr, ++next) {
2349
+ std::memcpy(static_cast<void*>(&*itr), &*next, sizeof(Member));
2350
+ SizeType mpos = static_cast<SizeType>(itr - beg);
2351
+ new (&mit[mpos]) MapIterator(DropMapIterator(mit[next - beg]));
2352
+ mit[mpos]->second = mpos;
2353
+ }
2354
+ }
2355
+ #else
2356
+ std::memmove(static_cast<void*>(&*pos), &*last,
2357
+ static_cast<size_t>(end - last) * sizeof(Member));
2358
+ #endif
2359
+ o.size -= static_cast<SizeType>(last - first);
2360
+ return pos;
2361
+ }
2362
+
2363
+ template <typename SourceAllocator>
2364
+ void DoCopyMembers(const GenericValue<Encoding,SourceAllocator>& rhs, Allocator& allocator, bool copyConstStrings) {
2365
+ RAPIDJSON_ASSERT(rhs.GetType() == kObjectType);
2366
+
2367
+ data_.f.flags = kObjectFlag;
2368
+ SizeType count = rhs.data_.o.size;
2369
+ Member* lm = DoAllocMembers(count, allocator);
2370
+ const typename GenericValue<Encoding,SourceAllocator>::Member* rm = rhs.GetMembersPointer();
2371
+ #if RAPIDJSON_USE_MEMBERSMAP
2372
+ Map* &map = GetMap(lm);
2373
+ MapIterator* mit = GetMapIterators(map);
2374
+ #endif
2375
+ for (SizeType i = 0; i < count; i++) {
2376
+ new (&lm[i].name) GenericValue(rm[i].name, allocator, copyConstStrings);
2377
+ new (&lm[i].value) GenericValue(rm[i].value, allocator, copyConstStrings);
2378
+ #if RAPIDJSON_USE_MEMBERSMAP
2379
+ new (&mit[i]) MapIterator(map->insert(MapPair(lm[i].name.data_, i)));
2380
+ #endif
2381
+ }
2382
+ data_.o.size = data_.o.capacity = count;
2383
+ SetMembersPointer(lm);
2384
+ }
2385
+
2115
2386
  // Initialize this value as array with initial data, without calling destructor.
2116
2387
  void SetArrayRaw(GenericValue* values, SizeType count, Allocator& allocator) {
2117
2388
  data_.f.flags = kArrayFlag;
@@ -2129,9 +2400,16 @@ private:
2129
2400
  void SetObjectRaw(Member* members, SizeType count, Allocator& allocator) {
2130
2401
  data_.f.flags = kObjectFlag;
2131
2402
  if (count) {
2132
- Member* m = static_cast<Member*>(allocator.Malloc(count * sizeof(Member)));
2403
+ Member* m = DoAllocMembers(count, allocator);
2133
2404
  SetMembersPointer(m);
2134
2405
  std::memcpy(static_cast<void*>(m), members, count * sizeof(Member));
2406
+ #if RAPIDJSON_USE_MEMBERSMAP
2407
+ Map* &map = GetMap(m);
2408
+ MapIterator* mit = GetMapIterators(map);
2409
+ for (SizeType i = 0; i < count; i++) {
2410
+ new (&mit[i]) MapIterator(map->insert(MapPair(m[i].name.data_, i)));
2411
+ }
2412
+ #endif
2135
2413
  }
2136
2414
  else
2137
2415
  SetMembersPointer(0);
@@ -2252,6 +2530,13 @@ public:
2252
2530
  #endif
2253
2531
 
2254
2532
  ~GenericDocument() {
2533
+ // Clear the ::ValueType before ownAllocator is destroyed, ~ValueType()
2534
+ // runs last and may access its elements or members which would be freed
2535
+ // with an allocator like MemoryPoolAllocator (CrtAllocator does not
2536
+ // free its data when destroyed, but MemoryPoolAllocator does).
2537
+ if (ownAllocator_) {
2538
+ ValueType::SetNull();
2539
+ }
2255
2540
  Destroy();
2256
2541
  }
2257
2542
 
@@ -2734,4 +3019,9 @@ private:
2734
3019
  RAPIDJSON_NAMESPACE_END
2735
3020
  RAPIDJSON_DIAG_POP
2736
3021
 
3022
+ #ifdef RAPIDJSON_WINDOWS_GETOBJECT_WORKAROUND_APPLIED
3023
+ #pragma pop_macro("GetObject")
3024
+ #undef RAPIDJSON_WINDOWS_GETOBJECT_WORKAROUND_APPLIED
3025
+ #endif
3026
+
2737
3027
  #endif // RAPIDJSON_DOCUMENT_H_
@@ -45,6 +45,20 @@ inline SizeType StrLen(const wchar_t* s) {
45
45
  return SizeType(std::wcslen(s));
46
46
  }
47
47
 
48
+ //! Custom strcmpn() which works on different character types.
49
+ /*! \tparam Ch Character type (e.g. char, wchar_t, short)
50
+ \param s1 Null-terminated input string.
51
+ \param s2 Null-terminated input string.
52
+ \return 0 if equal
53
+ */
54
+ template<typename Ch>
55
+ inline int StrCmp(const Ch* s1, const Ch* s2) {
56
+ RAPIDJSON_ASSERT(s1 != 0);
57
+ RAPIDJSON_ASSERT(s2 != 0);
58
+ while(*s1 && (*s1 == *s2)) { s1++; s2++; }
59
+ return static_cast<unsigned>(*s1) < static_cast<unsigned>(*s2) ? -1 : static_cast<unsigned>(*s1) > static_cast<unsigned>(*s2);
60
+ }
61
+
48
62
  //! Returns number of code points in a encoded string.
49
63
  template<typename Encoding>
50
64
  bool CountStringCodePoint(const typename Encoding::Ch* s, SizeType length, SizeType* outCount) {
@@ -16,6 +16,7 @@
16
16
  #define RAPIDJSON_POINTER_H_
17
17
 
18
18
  #include "document.h"
19
+ #include "uri.h"
19
20
  #include "internal/itoa.h"
20
21
 
21
22
  #ifdef __clang__
@@ -80,6 +81,8 @@ class GenericPointer {
80
81
  public:
81
82
  typedef typename ValueType::EncodingType EncodingType; //!< Encoding type from Value
82
83
  typedef typename ValueType::Ch Ch; //!< Character type from Value
84
+ typedef GenericUri<ValueType, Allocator> UriType;
85
+
83
86
 
84
87
  //! A token is the basic units of internal representation.
85
88
  /*!
@@ -163,7 +166,7 @@ public:
163
166
  GenericPointer(const Token* tokens, size_t tokenCount) : allocator_(), ownAllocator_(), nameBuffer_(), tokens_(const_cast<Token*>(tokens)), tokenCount_(tokenCount), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {}
164
167
 
165
168
  //! Copy constructor.
166
- GenericPointer(const GenericPointer& rhs) : allocator_(rhs.allocator_), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {
169
+ GenericPointer(const GenericPointer& rhs) : allocator_(), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {
167
170
  *this = rhs;
168
171
  }
169
172
 
@@ -520,6 +523,70 @@ public:
520
523
 
521
524
  //@}
522
525
 
526
+ //!@name Compute URI
527
+ //@{
528
+
529
+ //! Compute the in-scope URI for a subtree.
530
+ // For use with JSON pointers into JSON schema documents.
531
+ /*!
532
+ \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root.
533
+ \param rootUri Root URI
534
+ \param unresolvedTokenIndex If the pointer cannot resolve a token in the pointer, this parameter can obtain the index of unresolved token.
535
+ \param allocator Allocator for Uris
536
+ \return Uri if it can be resolved. Otherwise null.
537
+
538
+ \note
539
+ There are only 3 situations when a URI cannot be resolved:
540
+ 1. A value in the path is not an array nor object.
541
+ 2. An object value does not contain the token.
542
+ 3. A token is out of range of an array value.
543
+
544
+ Use unresolvedTokenIndex to retrieve the token index.
545
+ */
546
+ UriType GetUri(ValueType& root, const UriType& rootUri, size_t* unresolvedTokenIndex = 0, Allocator* allocator = 0) const {
547
+ static const Ch kIdString[] = { 'i', 'd', '\0' };
548
+ static const ValueType kIdValue(kIdString, 2);
549
+ UriType base = UriType(rootUri, allocator);
550
+ RAPIDJSON_ASSERT(IsValid());
551
+ ValueType* v = &root;
552
+ for (const Token *t = tokens_; t != tokens_ + tokenCount_; ++t) {
553
+ switch (v->GetType()) {
554
+ case kObjectType:
555
+ {
556
+ // See if we have an id, and if so resolve with the current base
557
+ typename ValueType::MemberIterator m = v->FindMember(kIdValue);
558
+ if (m != v->MemberEnd() && (m->value).IsString()) {
559
+ UriType here = UriType(m->value, allocator).Resolve(base, allocator);
560
+ base = here;
561
+ }
562
+ m = v->FindMember(GenericValue<EncodingType>(GenericStringRef<Ch>(t->name, t->length)));
563
+ if (m == v->MemberEnd())
564
+ break;
565
+ v = &m->value;
566
+ }
567
+ continue;
568
+ case kArrayType:
569
+ if (t->index == kPointerInvalidIndex || t->index >= v->Size())
570
+ break;
571
+ v = &((*v)[t->index]);
572
+ continue;
573
+ default:
574
+ break;
575
+ }
576
+
577
+ // Error: unresolved token
578
+ if (unresolvedTokenIndex)
579
+ *unresolvedTokenIndex = static_cast<size_t>(t - tokens_);
580
+ return UriType(allocator);
581
+ }
582
+ return base;
583
+ }
584
+
585
+ UriType GetUri(const ValueType& root, const UriType& rootUri, size_t* unresolvedTokenIndex = 0, Allocator* allocator = 0) const {
586
+ return GetUri(const_cast<ValueType&>(root), rootUri, unresolvedTokenIndex, allocator);
587
+ }
588
+
589
+
523
590
  //!@name Query value
524
591
  //@{
525
592