16#ifndef RAPIDJSON_POINTER_H_
17#define RAPIDJSON_POINTER_H_
20#include "internal/itoa.h"
24RAPIDJSON_DIAG_OFF(
switch-
enum)
25#elif defined(_MSC_VER)
27RAPIDJSON_DIAG_OFF(4512)
32static const SizeType kPointerInvalidIndex = ~SizeType(0);
79template <
typename ValueType,
typename Allocator = CrtAllocator>
83 typedef typename ValueType::Ch
Ch;
116 Parse(source, internal::StrLen(source));
119#if RAPIDJSON_HAS_STDSTRING
127 Parse(source.c_str(), source.size());
139 Parse(source, length);
213 internal::Swap(
tokens_, other.tokens_);
248 Ch *p = r.CopyFromRaw(*
this, 1, token.
length + 1);
249 std::memcpy(p, token.
name, (token.
length + 1) *
sizeof(
Ch));
264 Token token = { name, length, kPointerInvalidIndex };
265 return Append(token, allocator);
274 template <
typename T>
277 return Append(name, internal::StrLen(name), allocator);
280#if RAPIDJSON_HAS_STDSTRING
288 return Append(name.c_str(),
static_cast<SizeType>(name.size()), allocator);
300 char* end =
sizeof(
SizeType) == 4 ? internal::u32toa(index, buffer) : internal::u64toa(index, buffer);
302 buffer[length] =
'\0';
304 if (
sizeof(
Ch) == 1) {
305 Token token = {
reinterpret_cast<Ch*
>(buffer), length, index };
306 return Append(token, allocator);
310 for (
size_t i = 0; i <= length; i++)
311 name[i] =
static_cast<Ch>(buffer[i]);
312 Token token = { name, length, index };
313 return Append(token, allocator);
324 if (token.IsString())
325 return Append(token.GetString(), token.GetStringLength(), allocator);
329 return Append(
static_cast<SizeType>(token.GetUint64()), allocator);
354 const Token* GetTokens()
const {
return tokens_; }
357 size_t GetTokenCount()
const {
return tokenCount_; }
388 bool operator!=(
const GenericPointer& rhs)
const {
return !(*
this == rhs); }
427 template<
typename OutputStream>
428 bool Stringify(OutputStream& os)
const {
429 return Stringify<false, OutputStream>(os);
437 template<
typename OutputStream>
438 bool StringifyUriFragment(OutputStream& os)
const {
439 return Stringify<true, OutputStream>(os);
462 ValueType& Create(ValueType& root,
typename ValueType::AllocatorType& allocator,
bool* alreadyExist = 0)
const {
464 ValueType* v = &root;
467 if (v->IsArray() && t->name[0] ==
'-' && t->length == 1) {
468 v->PushBack(ValueType().Move(), allocator);
469 v = &((*v)[v->Size() - 1]);
473 if (t->index == kPointerInvalidIndex) {
478 if (!v->IsArray() && !v->IsObject())
483 if (t->index >= v->Size()) {
484 v->Reserve(t->index + 1, allocator);
485 while (t->index >= v->Size())
486 v->PushBack(ValueType().Move(), allocator);
489 v = &((*v)[t->index]);
493 if (m == v->MemberEnd()) {
494 v->AddMember(ValueType(t->name, t->length, allocator).Move(), ValueType().Move(), allocator);
506 *alreadyExist = exist;
517 template <
typename stackAllocator>
519 return Create(document, document.
GetAllocator(), alreadyExist);
541 ValueType* Get(ValueType& root,
size_t* unresolvedTokenIndex = 0)
const {
543 ValueType* v = &root;
545 switch (v->GetType()) {
549 if (m == v->MemberEnd())
555 if (t->index == kPointerInvalidIndex || t->index >= v->Size())
557 v = &((*v)[t->index]);
564 if (unresolvedTokenIndex)
565 *unresolvedTokenIndex =
static_cast<size_t>(t -
tokens_);
576 const ValueType* Get(
const ValueType& root,
size_t* unresolvedTokenIndex = 0)
const {
577 return Get(
const_cast<ValueType&
>(root), unresolvedTokenIndex);
595 ValueType& GetWithDefault(ValueType& root,
const ValueType& defaultValue,
typename ValueType::AllocatorType& allocator)
const {
597 ValueType& v = Create(root, allocator, &alreadyExist);
598 return alreadyExist ? v : v.CopyFrom(defaultValue, allocator);
602 ValueType& GetWithDefault(ValueType& root,
const Ch* defaultValue,
typename ValueType::AllocatorType& allocator)
const {
604 ValueType& v = Create(root, allocator, &alreadyExist);
605 return alreadyExist ? v : v.SetString(defaultValue, allocator);
608#if RAPIDJSON_HAS_STDSTRING
610 ValueType& GetWithDefault(ValueType& root,
const std::basic_string<Ch>& defaultValue,
typename ValueType::AllocatorType& allocator)
const {
612 ValueType& v = Create(root, allocator, &alreadyExist);
613 return alreadyExist ? v : v.SetString(defaultValue, allocator);
621 template <
typename T>
623 GetWithDefault(ValueType& root, T defaultValue,
typename ValueType::AllocatorType& allocator)
const {
624 return GetWithDefault(root, ValueType(defaultValue).Move(), allocator);
628 template <
typename stackAllocator>
630 return GetWithDefault(document, defaultValue, document.
GetAllocator());
634 template <
typename stackAllocator>
636 return GetWithDefault(document, defaultValue, document.
GetAllocator());
639#if RAPIDJSON_HAS_STDSTRING
641 template <
typename stackAllocator>
643 return GetWithDefault(document, defaultValue, document.
GetAllocator());
651 template <
typename T,
typename stackAllocator>
654 return GetWithDefault(document, defaultValue, document.
GetAllocator());
672 ValueType& Set(ValueType& root, ValueType& value,
typename ValueType::AllocatorType& allocator)
const {
673 return Create(root, allocator) = value;
677 ValueType& Set(ValueType& root,
const ValueType& value,
typename ValueType::AllocatorType& allocator)
const {
678 return Create(root, allocator).CopyFrom(value, allocator);
682 ValueType& Set(ValueType& root,
const Ch* value,
typename ValueType::AllocatorType& allocator)
const {
683 return Create(root, allocator) = ValueType(value, allocator).Move();
686#if RAPIDJSON_HAS_STDSTRING
688 ValueType& Set(ValueType& root,
const std::basic_string<Ch>& value,
typename ValueType::AllocatorType& allocator)
const {
689 return Create(root, allocator) = ValueType(value, allocator).Move();
697 template <
typename T>
699 Set(ValueType& root, T value,
typename ValueType::AllocatorType& allocator)
const {
700 return Create(root, allocator) = ValueType(value).Move();
704 template <
typename stackAllocator>
706 return Create(document) = value;
710 template <
typename stackAllocator>
712 return Create(document).CopyFrom(value, document.
GetAllocator());
716 template <
typename stackAllocator>
718 return Create(document) = ValueType(value, document.
GetAllocator()).Move();
721#if RAPIDJSON_HAS_STDSTRING
723 template <
typename stackAllocator>
725 return Create(document) = ValueType(value, document.
GetAllocator()).Move();
733 template <
typename T,
typename stackAllocator>
736 return Create(document) = value;
754 ValueType&
Swap(ValueType& root, ValueType& value,
typename ValueType::AllocatorType& allocator)
const {
755 return Create(root, allocator).
Swap(value);
759 template <
typename stackAllocator>
761 return Create(document).
Swap(value);
773 bool Erase(ValueType& root)
const {
778 ValueType* v = &root;
780 for (
const Token *t =
tokens_; t != last; ++t) {
781 switch (v->GetType()) {
785 if (m == v->MemberEnd())
791 if (t->index == kPointerInvalidIndex || t->index >= v->Size())
793 v = &((*v)[t->index]);
800 switch (v->GetType()) {
804 if (last->index == kPointerInvalidIndex || last->index >= v->Size())
806 v->Erase(v->Begin() + last->index);
821 Ch* CopyFromRaw(
const GenericPointer& rhs,
size_t extraToken = 0,
size_t extraNameBufferSize = 0) {
827 nameBufferSize += t->length;
835 if (nameBufferSize > 0) {
852 bool NeedPercentEncode(
Ch c)
const {
853 return !((c >=
'0' && c <=
'9') || (c >=
'A' && c <=
'Z') || (c >=
'a' && c <=
'z') || c ==
'-' || c ==
'.' || c ==
'_' || c ==
'~');
864 void Parse(
const Ch* source,
size_t length) {
875 for (
const Ch* s = source; s != source + length; s++)
884 bool uriFragment =
false;
885 if (source[i] ==
'#') {
890 if (i != length && source[i] !=
'/') {
900 bool isNumber =
true;
902 while (i < length && source[i] !=
'/') {
907 PercentDecodeStream is(&source[i], source + length);
909 Ch* begin = os.PutBegin();
914 size_t len = os.PutEnd(begin);
925 else if (NeedPercentEncode(c)) {
937 if (c ==
'0') c =
'~';
938 else if (c ==
'1') c =
'/';
952 if (c <
'0' || c >
'9')
957 token->length =
static_cast<SizeType>(name - token->name);
958 if (token->length == 0)
963 if (isNumber && token->length > 1 && token->name[0] ==
'0')
969 for (
size_t j = 0; j < token->length; j++) {
979 token->index = isNumber ? n : kPointerInvalidIndex;
1002 template<
bool uriFragment,
typename OutputStream>
1003 bool Stringify(OutputStream& os)
const {
1011 for (
size_t j = 0; j < t->length; j++) {
1017 else if (c ==
'/') {
1021 else if (uriFragment && NeedPercentEncode(c)) {
1024 PercentEncodeStream<OutputStream> target(os);
1027 j += source.Tell() - 1;
1042 class PercentDecodeStream {
1044 typedef typename ValueType::Ch Ch;
1051 PercentDecodeStream(
const Ch* source,
const Ch* end) : src_(source), head_(source), end_(end), valid_(true) {}
1054 if (*src_ !=
'%' || src_ + 3 > end_) {
1060 for (
int j = 0; j < 2; j++) {
1061 c =
static_cast<Ch
>(c << 4);
1063 if (h >=
'0' && h <=
'9') c =
static_cast<Ch
>(c + h -
'0');
1064 else if (h >=
'A' && h <=
'F') c =
static_cast<Ch
>(c + h -
'A' + 10);
1065 else if (h >=
'a' && h <=
'f') c =
static_cast<Ch
>(c + h -
'a' + 10);
1075 size_t Tell()
const {
return static_cast<size_t>(src_ - head_); }
1076 bool IsValid()
const {
return valid_; }
1086 template <
typename OutputStream>
1091 unsigned char u =
static_cast<unsigned char>(c);
1092 static const char hexDigits[16] = {
'0',
'1',
'2',
'3',
'4',
'5',
'6',
'7',
'8',
'9',
'A',
'B',
'C',
'D',
'E',
'F' };
1094 os_.Put(
static_cast<typename OutputStream::Ch
>(hexDigits[u >> 4]));
1095 os_.Put(
static_cast<typename OutputStream::Ch
>(hexDigits[u & 15]));
1118template <
typename T>
1120 return pointer.Create(root, a);
1123template <
typename T,
typename CharType,
size_t N>
1124typename T::ValueType& CreateValueByPointer(T& root,
const CharType(&source)[N],
typename T::AllocatorType& a) {
1130template <
typename DocumentType>
1132 return pointer.Create(document);
1135template <
typename DocumentType,
typename CharType,
size_t N>
1136typename DocumentType::ValueType& CreateValueByPointer(DocumentType& document,
const CharType(&source)[N]) {
1142template <
typename T>
1144 return pointer.Get(root, unresolvedTokenIndex);
1147template <
typename T>
1149 return pointer.Get(root, unresolvedTokenIndex);
1152template <
typename T,
typename CharType,
size_t N>
1153typename T::ValueType* GetValueByPointer(T& root,
const CharType (&source)[N],
size_t* unresolvedTokenIndex = 0) {
1157template <
typename T,
typename CharType,
size_t N>
1158const typename T::ValueType* GetValueByPointer(
const T& root,
const CharType(&source)[N],
size_t* unresolvedTokenIndex = 0) {
1164template <
typename T>
1165typename T::ValueType& GetValueByPointerWithDefault(T& root,
const GenericPointer<typename T::ValueType>& pointer,
const typename T::ValueType& defaultValue,
typename T::AllocatorType& a) {
1166 return pointer.GetWithDefault(root, defaultValue, a);
1169template <
typename T>
1170typename T::ValueType& GetValueByPointerWithDefault(T& root,
const GenericPointer<typename T::ValueType>& pointer,
const typename T::Ch* defaultValue,
typename T::AllocatorType& a) {
1171 return pointer.GetWithDefault(root, defaultValue, a);
1174#if RAPIDJSON_HAS_STDSTRING
1175template <
typename T>
1176typename T::ValueType& GetValueByPointerWithDefault(T& root,
const GenericPointer<typename T::ValueType>& pointer,
const std::basic_string<typename T::Ch>& defaultValue,
typename T::AllocatorType& a) {
1177 return pointer.GetWithDefault(root, defaultValue, a);
1181template <
typename T,
typename T2>
1184 return pointer.GetWithDefault(root, defaultValue, a);
1187template <
typename T,
typename CharType,
size_t N>
1188typename T::ValueType& GetValueByPointerWithDefault(T& root,
const CharType(&source)[N],
const typename T::ValueType& defaultValue,
typename T::AllocatorType& a) {
1192template <
typename T,
typename CharType,
size_t N>
1193typename T::ValueType& GetValueByPointerWithDefault(T& root,
const CharType(&source)[N],
const typename T::Ch* defaultValue,
typename T::AllocatorType& a) {
1197#if RAPIDJSON_HAS_STDSTRING
1198template <
typename T,
typename CharType,
size_t N>
1199typename T::ValueType& GetValueByPointerWithDefault(T& root,
const CharType(&source)[N],
const std::basic_string<typename T::Ch>& defaultValue,
typename T::AllocatorType& a) {
1204template <
typename T,
typename CharType,
size_t N,
typename T2>
1206GetValueByPointerWithDefault(T& root,
const CharType(&source)[N], T2 defaultValue,
typename T::AllocatorType& a) {
1212template <
typename DocumentType>
1214 return pointer.GetWithDefault(document, defaultValue);
1217template <
typename DocumentType>
1219 return pointer.GetWithDefault(document, defaultValue);
1222#if RAPIDJSON_HAS_STDSTRING
1223template <
typename DocumentType>
1225 return pointer.GetWithDefault(document, defaultValue);
1229template <
typename DocumentType,
typename T2>
1230RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>,
internal::IsGenericValue<T2> >), (
typename DocumentType::ValueType&))
1232 return pointer.GetWithDefault(document, defaultValue);
1235template <
typename DocumentType,
typename CharType,
size_t N>
1236typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document,
const CharType(&source)[N],
const typename DocumentType::ValueType& defaultValue) {
1240template <
typename DocumentType,
typename CharType,
size_t N>
1241typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document,
const CharType(&source)[N],
const typename DocumentType::Ch* defaultValue) {
1245#if RAPIDJSON_HAS_STDSTRING
1246template <
typename DocumentType,
typename CharType,
size_t N>
1247typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document,
const CharType(&source)[N],
const std::basic_string<typename DocumentType::Ch>& defaultValue) {
1252template <
typename DocumentType,
typename CharType,
size_t N,
typename T2>
1253RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>,
internal::IsGenericValue<T2> >), (
typename DocumentType::ValueType&))
1254GetValueByPointerWithDefault(DocumentType& document,
const CharType(&source)[N], T2 defaultValue) {
1260template <
typename T>
1262 return pointer.Set(root, value, a);
1265template <
typename T>
1267 return pointer.Set(root, value, a);
1270template <
typename T>
1272 return pointer.Set(root, value, a);
1275#if RAPIDJSON_HAS_STDSTRING
1276template <
typename T>
1277typename T::ValueType& SetValueByPointer(T& root,
const GenericPointer<typename T::ValueType>& pointer,
const std::basic_string<typename T::Ch>& value,
typename T::AllocatorType& a) {
1278 return pointer.Set(root, value, a);
1282template <
typename T,
typename T2>
1285 return pointer.Set(root, value, a);
1288template <
typename T,
typename CharType,
size_t N>
1289typename T::ValueType& SetValueByPointer(T& root,
const CharType(&source)[N],
typename T::ValueType& value,
typename T::AllocatorType& a) {
1293template <
typename T,
typename CharType,
size_t N>
1294typename T::ValueType& SetValueByPointer(T& root,
const CharType(&source)[N],
const typename T::ValueType& value,
typename T::AllocatorType& a) {
1298template <
typename T,
typename CharType,
size_t N>
1299typename T::ValueType& SetValueByPointer(T& root,
const CharType(&source)[N],
const typename T::Ch* value,
typename T::AllocatorType& a) {
1303#if RAPIDJSON_HAS_STDSTRING
1304template <
typename T,
typename CharType,
size_t N>
1305typename T::ValueType& SetValueByPointer(T& root,
const CharType(&source)[N],
const std::basic_string<typename T::Ch>& value,
typename T::AllocatorType& a) {
1310template <
typename T,
typename CharType,
size_t N,
typename T2>
1312SetValueByPointer(T& root,
const CharType(&source)[N], T2 value,
typename T::AllocatorType& a) {
1318template <
typename DocumentType>
1320 return pointer.Set(document, value);
1323template <
typename DocumentType>
1325 return pointer.Set(document, value);
1328template <
typename DocumentType>
1330 return pointer.Set(document, value);
1333#if RAPIDJSON_HAS_STDSTRING
1334template <
typename DocumentType>
1336 return pointer.Set(document, value);
1340template <
typename DocumentType,
typename T2>
1341RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>,
internal::IsGenericValue<T2> >), (
typename DocumentType::ValueType&))
1343 return pointer.Set(document, value);
1346template <
typename DocumentType,
typename CharType,
size_t N>
1347typename DocumentType::ValueType& SetValueByPointer(DocumentType& document,
const CharType(&source)[N],
typename DocumentType::ValueType& value) {
1351template <
typename DocumentType,
typename CharType,
size_t N>
1352typename DocumentType::ValueType& SetValueByPointer(DocumentType& document,
const CharType(&source)[N],
const typename DocumentType::ValueType& value) {
1356template <
typename DocumentType,
typename CharType,
size_t N>
1357typename DocumentType::ValueType& SetValueByPointer(DocumentType& document,
const CharType(&source)[N],
const typename DocumentType::Ch* value) {
1361#if RAPIDJSON_HAS_STDSTRING
1362template <
typename DocumentType,
typename CharType,
size_t N>
1363typename DocumentType::ValueType& SetValueByPointer(DocumentType& document,
const CharType(&source)[N],
const std::basic_string<typename DocumentType::Ch>& value) {
1368template <
typename DocumentType,
typename CharType,
size_t N,
typename T2>
1369RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>,
internal::IsGenericValue<T2> >), (
typename DocumentType::ValueType&))
1370SetValueByPointer(DocumentType& document,
const CharType(&source)[N], T2 value) {
1376template <
typename T>
1378 return pointer.Swap(root, value, a);
1381template <
typename T,
typename CharType,
size_t N>
1382typename T::ValueType& SwapValueByPointer(T& root,
const CharType(&source)[N],
typename T::ValueType& value,
typename T::AllocatorType& a) {
1386template <
typename DocumentType>
1388 return pointer.Swap(document, value);
1391template <
typename DocumentType,
typename CharType,
size_t N>
1392typename DocumentType::ValueType& SwapValueByPointer(DocumentType& document,
const CharType(&source)[N],
typename DocumentType::ValueType& value) {
1398template <
typename T>
1400 return pointer.Erase(root);
1403template <
typename T,
typename CharType,
size_t N>
1404bool EraseValueByPointer(T& root,
const CharType(&source)[N]) {
1412#if defined(__clang__) || defined(_MSC_VER)
A document for parsing JSON text as DOM.
Allocator & GetAllocator()
Get the allocator of this document.
A helper stream to encode character (UTF-8 code unit) into percent-encoded sequence.
Represents a JSON Pointer. Use Pointer for UTF8 encoding and default allocator.
friend void swap(GenericPointer &a, GenericPointer &b) RAPIDJSON_NOEXCEPT
free-standing swap function helper
Ch * nameBuffer_
A buffer containing all names in tokens.
Allocator * allocator_
The current allocator. It is either user-supplied or equal to ownAllocator_.
GenericPointer(const GenericPointer &rhs, Allocator *allocator)
Copy constructor.
GenericPointer(const Ch *source, Allocator *allocator=0)
Constructor that parses a string or URI fragment representation.
ValueType::EncodingType EncodingType
Encoding type from Value.
GenericPointer(const Token *tokens, size_t tokenCount)
Constructor with user-supplied tokens.
GenericPointer(Allocator *allocator=0)
Default constructor.
size_t tokenCount_
Number of tokens in tokens_.
GenericPointer(const GenericPointer &rhs)
Copy constructor.
PointerParseErrorCode parseErrorCode_
Parsing error code.
Token * tokens_
A list of tokens.
Allocator * ownAllocator_
Allocator owned by this Pointer.
GenericPointer(const Ch *source, size_t length, Allocator *allocator=0)
Constructor that parses a string or URI fragment representation, with length of the source string.
GenericPointer Append(const Ch *name, SizeType length, Allocator *allocator=0) const
Append a name token with length, and return a new Pointer.
GenericPointer Append(const Token &token, Allocator *allocator=0) const
Append a token and return a new Pointer.
RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr< internal::IsSame< typename internal::RemoveConst< T >::Type, Ch > >),(GenericPointer)) Append(T *name
Append a name token without length, and return a new Pointer.
ValueType::Ch Ch
Character type from Value.
~GenericPointer()
Destructor.
size_t parseErrorOffset_
Offset in code unit when parsing fail.
GenericPointer & operator=(const GenericPointer &rhs)
Assignment operator.
GenericPointer & Swap(GenericPointer &other) RAPIDJSON_NOEXCEPT
Swap the content of this pointer with an other.
Represents a JSON value. Use Value for UTF8 encoding and default allocator.
Concept for allocating, resizing and freeing memory block.
#define RAPIDJSON_ASSERT(x)
Assertion.
#define RAPIDJSON_NAMESPACE_BEGIN
provide custom rapidjson namespace (opening expression)
#define RAPIDJSON_NAMESPACE_END
provide custom rapidjson namespace (closing expression)
PointerParseErrorCode
Error code of parsing.
@ kPointerParseErrorInvalidEscape
Invalid escape.
@ kPointerParseErrorTokenMustBeginWithSolidus
A token must begin with a '/'.
@ kPointerParseErrorNone
The parse is successful.
@ kPointerParseErrorCharacterMustPercentEncode
A character must percent encoded in URI fragment.
@ kPointerParseErrorInvalidPercentEncoding
Invalid percent encoding in URI fragment.
Integer len(const char *s)
Retourne la longueur de la chaîne s.
bool operator<(const Item &item1, const Item &item2)
Compare deux entités.
#define RAPIDJSON_DELETE(x)
! customization point for global delete
RAPIDJSON_NAMESPACE_BEGIN typedef unsigned SizeType
Size type (for string lengths, array sizes, etc.)
#define RAPIDJSON_NEW(TypeName)
! customization point for global new
A read-write string stream.
A token is the basic units of internal representation.
SizeType index
A valid array index, if it is not equal to kPointerInvalidIndex.
SizeType length
Length of the name.
const Ch * name
Name of the token. It has null character at the end but it can contain null character.
Reference to a constant string (not taking a copy)