bes Updated for version 3.21.1
The Backend Server (BES) is the lower two tiers of the Hyrax data server
pointer.h
1// Tencent is pleased to support the open source community by making RapidJSON available.
2//
3// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
4//
5// Licensed under the MIT License (the "License"); you may not use this file except
6// in compliance with the License. You may obtain a copy of the License at
7//
8// http://opensource.org/licenses/MIT
9//
10// Unless required by applicable law or agreed to in writing, software distributed
11// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
12// CONDITIONS OF ANY KIND, either express or implied. See the License for the
13// specific language governing permissions and limitations under the License.
14
15#ifndef RAPIDJSON_POINTER_H_
16#define RAPIDJSON_POINTER_H_
17
18#include "document.h"
19#include "internal/itoa.h"
20
21#ifdef __clang__
22RAPIDJSON_DIAG_PUSH
23RAPIDJSON_DIAG_OFF(switch-enum)
24#elif defined(_MSC_VER)
25RAPIDJSON_DIAG_PUSH
26RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated
27#endif
28
30
31static const SizeType kPointerInvalidIndex = ~SizeType(0);
32
34
45
47// GenericPointer
48
50
78template <typename ValueType, typename Allocator = CrtAllocator>
80public:
81 typedef typename ValueType::EncodingType EncodingType;
82 typedef typename ValueType::Ch Ch;
83
85
97 struct Token {
98 const Ch* name;
101 };
102
104
105
108
110
115 Parse(source, internal::StrLen(source));
116 }
117
118#if RAPIDJSON_HAS_STDSTRING
120
125 explicit GenericPointer(const std::basic_string<Ch>& source, Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {
126 Parse(source.c_str(), source.size());
127 }
128#endif
129
131
138 Parse(source, length);
139 }
140
142
163 GenericPointer(const Token* tokens, size_t tokenCount) : allocator_(), ownAllocator_(), nameBuffer_(), tokens_(const_cast<Token*>(tokens)), tokenCount_(tokenCount), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {}
164
169
174
177 if (nameBuffer_) // If user-supplied tokens constructor is used, nameBuffer_ is nullptr and tokens_ are not deallocated.
178 Allocator::Free(tokens_);
180 }
181
184 if (this != &rhs) {
185 // Do not delete ownAllcator
186 if (nameBuffer_)
187 Allocator::Free(tokens_);
188
192
193 if (rhs.nameBuffer_)
194 CopyFromRaw(rhs); // Normally parsed tokens.
195 else {
196 tokens_ = rhs.tokens_; // User supplied const tokens.
197 nameBuffer_ = 0;
198 }
199 }
200 return *this;
201 }
202
204
208 GenericPointer& Swap(GenericPointer& other) RAPIDJSON_NOEXCEPT {
209 internal::Swap(allocator_, other.allocator_);
210 internal::Swap(ownAllocator_, other.ownAllocator_);
211 internal::Swap(nameBuffer_, other.nameBuffer_);
212 internal::Swap(tokens_, other.tokens_);
213 internal::Swap(tokenCount_, other.tokenCount_);
214 internal::Swap(parseErrorOffset_, other.parseErrorOffset_);
215 internal::Swap(parseErrorCode_, other.parseErrorCode_);
216 return *this;
217 }
218
220
231 friend inline void swap(GenericPointer& a, GenericPointer& b) RAPIDJSON_NOEXCEPT { a.Swap(b); }
232
234
236
237
239
244 GenericPointer Append(const Token& token, Allocator* allocator = 0) const {
246 r.allocator_ = allocator;
247 Ch *p = r.CopyFromRaw(*this, 1, token.length + 1);
248 std::memcpy(p, token.name, (token.length + 1) * sizeof(Ch));
249 r.tokens_[tokenCount_].name = p;
250 r.tokens_[tokenCount_].length = token.length;
251 r.tokens_[tokenCount_].index = token.index;
252 return r;
253 }
254
256
262 GenericPointer Append(const Ch* name, SizeType length, Allocator* allocator = 0) const {
263 Token token = { name, length, kPointerInvalidIndex };
264 return Append(token, allocator);
265 }
266
268
273 template <typename T>
274 RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr<internal::IsSame<typename internal::RemoveConst<T>::Type, Ch> >), (GenericPointer))
275 Append(T* name, Allocator* allocator = 0) const {
276 return Append(name, internal::StrLen(name), allocator);
277 }
278
279#if RAPIDJSON_HAS_STDSTRING
281
286 GenericPointer Append(const std::basic_string<Ch>& name, Allocator* allocator = 0) const {
287 return Append(name.c_str(), static_cast<SizeType>(name.size()), allocator);
288 }
289#endif
290
292
297 GenericPointer Append(SizeType index, Allocator* allocator = 0) const {
298 char buffer[21];
299 char* end = sizeof(SizeType) == 4 ? internal::u32toa(index, buffer) : internal::u64toa(index, buffer);
300 SizeType length = static_cast<SizeType>(end - buffer);
301 buffer[length] = '\0';
302
303 if (sizeof(Ch) == 1) {
304 Token token = { reinterpret_cast<Ch*>(buffer), length, index };
305 return Append(token, allocator);
306 }
307 else {
308 Ch name[21];
309 for (size_t i = 0; i <= length; i++)
310 name[i] = static_cast<Ch>(buffer[i]);
311 Token token = { name, length, index };
312 return Append(token, allocator);
313 }
314 }
315
317
322 GenericPointer Append(const ValueType& token, Allocator* allocator = 0) const {
323 if (token.IsString())
324 return Append(token.GetString(), token.GetStringLength(), allocator);
325 else {
326 RAPIDJSON_ASSERT(token.IsUint64());
327 RAPIDJSON_ASSERT(token.GetUint64() <= SizeType(~0));
328 return Append(static_cast<SizeType>(token.GetUint64()), allocator);
329 }
330 }
331
333
334
336 bool IsValid() const { return parseErrorCode_ == kPointerParseErrorNone; }
337
339 size_t GetParseErrorOffset() const { return parseErrorOffset_; }
340
342 PointerParseErrorCode GetParseErrorCode() const { return parseErrorCode_; }
343
345
347 Allocator& GetAllocator() { return *allocator_; }
348
350
351
353 const Token* GetTokens() const { return tokens_; }
354
356 size_t GetTokenCount() const { return tokenCount_; }
357
359
361
362
364
367 bool operator==(const GenericPointer& rhs) const {
368 if (!IsValid() || !rhs.IsValid() || tokenCount_ != rhs.tokenCount_)
369 return false;
370
371 for (size_t i = 0; i < tokenCount_; i++) {
372 if (tokens_[i].index != rhs.tokens_[i].index ||
373 tokens_[i].length != rhs.tokens_[i].length ||
374 (tokens_[i].length != 0 && std::memcmp(tokens_[i].name, rhs.tokens_[i].name, sizeof(Ch)* tokens_[i].length) != 0))
375 {
376 return false;
377 }
378 }
379
380 return true;
381 }
382
384
387 bool operator!=(const GenericPointer& rhs) const { return !(*this == rhs); }
388
390
393 bool operator<(const GenericPointer& rhs) const {
394 if (!IsValid())
395 return false;
396 if (!rhs.IsValid())
397 return true;
398
399 if (tokenCount_ != rhs.tokenCount_)
400 return tokenCount_ < rhs.tokenCount_;
401
402 for (size_t i = 0; i < tokenCount_; i++) {
403 if (tokens_[i].index != rhs.tokens_[i].index)
404 return tokens_[i].index < rhs.tokens_[i].index;
405
406 if (tokens_[i].length != rhs.tokens_[i].length)
407 return tokens_[i].length < rhs.tokens_[i].length;
408
409 if (int cmp = std::memcmp(tokens_[i].name, rhs.tokens_[i].name, sizeof(Ch) * tokens_[i].length))
410 return cmp < 0;
411 }
412
413 return false;
414 }
415
417
419
420
422
426 template<typename OutputStream>
427 bool Stringify(OutputStream& os) const {
428 return Stringify<false, OutputStream>(os);
429 }
430
432
436 template<typename OutputStream>
437 bool StringifyUriFragment(OutputStream& os) const {
438 return Stringify<true, OutputStream>(os);
439 }
440
442
444
445
447
461 ValueType& Create(ValueType& root, typename ValueType::AllocatorType& allocator, bool* alreadyExist = 0) const {
462 RAPIDJSON_ASSERT(IsValid());
463 ValueType* v = &root;
464 bool exist = true;
465 for (const Token *t = tokens_; t != tokens_ + tokenCount_; ++t) {
466 if (v->IsArray() && t->name[0] == '-' && t->length == 1) {
467 v->PushBack(ValueType().Move(), allocator);
468 v = &((*v)[v->Size() - 1]);
469 exist = false;
470 }
471 else {
472 if (t->index == kPointerInvalidIndex) { // must be object name
473 if (!v->IsObject())
474 v->SetObject(); // Change to Object
475 }
476 else { // object name or array index
477 if (!v->IsArray() && !v->IsObject())
478 v->SetArray(); // Change to Array
479 }
480
481 if (v->IsArray()) {
482 if (t->index >= v->Size()) {
483 v->Reserve(t->index + 1, allocator);
484 while (t->index >= v->Size())
485 v->PushBack(ValueType().Move(), allocator);
486 exist = false;
487 }
488 v = &((*v)[t->index]);
489 }
490 else {
491 typename ValueType::MemberIterator m = v->FindMember(GenericValue<EncodingType>(GenericStringRef<Ch>(t->name, t->length)));
492 if (m == v->MemberEnd()) {
493 v->AddMember(ValueType(t->name, t->length, allocator).Move(), ValueType().Move(), allocator);
494 m = v->MemberEnd();
495 v = &(--m)->value; // Assumes AddMember() appends at the end
496 exist = false;
497 }
498 else
499 v = &m->value;
500 }
501 }
502 }
503
504 if (alreadyExist)
505 *alreadyExist = exist;
506
507 return *v;
508 }
509
511
516 template <typename stackAllocator>
517 ValueType& Create(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, bool* alreadyExist = 0) const {
518 return Create(document, document.GetAllocator(), alreadyExist);
519 }
520
522
524
525
527
540 ValueType* Get(ValueType& root, size_t* unresolvedTokenIndex = 0) const {
541 RAPIDJSON_ASSERT(IsValid());
542 ValueType* v = &root;
543 for (const Token *t = tokens_; t != tokens_ + tokenCount_; ++t) {
544 switch (v->GetType()) {
545 case kObjectType:
546 {
547 typename ValueType::MemberIterator m = v->FindMember(GenericValue<EncodingType>(GenericStringRef<Ch>(t->name, t->length)));
548 if (m == v->MemberEnd())
549 break;
550 v = &m->value;
551 }
552 continue;
553 case kArrayType:
554 if (t->index == kPointerInvalidIndex || t->index >= v->Size())
555 break;
556 v = &((*v)[t->index]);
557 continue;
558 default:
559 break;
560 }
561
562 // Error: unresolved token
563 if (unresolvedTokenIndex)
564 *unresolvedTokenIndex = static_cast<size_t>(t - tokens_);
565 return 0;
566 }
567 return v;
568 }
569
571
575 const ValueType* Get(const ValueType& root, size_t* unresolvedTokenIndex = 0) const {
576 return Get(const_cast<ValueType&>(root), unresolvedTokenIndex);
577 }
578
580
582
583
585
594 ValueType& GetWithDefault(ValueType& root, const ValueType& defaultValue, typename ValueType::AllocatorType& allocator) const {
595 bool alreadyExist;
596 ValueType& v = Create(root, allocator, &alreadyExist);
597 return alreadyExist ? v : v.CopyFrom(defaultValue, allocator);
598 }
599
601 ValueType& GetWithDefault(ValueType& root, const Ch* defaultValue, typename ValueType::AllocatorType& allocator) const {
602 bool alreadyExist;
603 ValueType& v = Create(root, allocator, &alreadyExist);
604 return alreadyExist ? v : v.SetString(defaultValue, allocator);
605 }
606
607#if RAPIDJSON_HAS_STDSTRING
609 ValueType& GetWithDefault(ValueType& root, const std::basic_string<Ch>& defaultValue, typename ValueType::AllocatorType& allocator) const {
610 bool alreadyExist;
611 ValueType& v = Create(root, allocator, &alreadyExist);
612 return alreadyExist ? v : v.SetString(defaultValue, allocator);
613 }
614#endif
615
617
620 template <typename T>
621 RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (ValueType&))
622 GetWithDefault(ValueType& root, T defaultValue, typename ValueType::AllocatorType& allocator) const {
623 return GetWithDefault(root, ValueType(defaultValue).Move(), allocator);
624 }
625
627 template <typename stackAllocator>
628 ValueType& GetWithDefault(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, const ValueType& defaultValue) const {
629 return GetWithDefault(document, defaultValue, document.GetAllocator());
630 }
631
633 template <typename stackAllocator>
634 ValueType& GetWithDefault(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, const Ch* defaultValue) const {
635 return GetWithDefault(document, defaultValue, document.GetAllocator());
636 }
637
638#if RAPIDJSON_HAS_STDSTRING
640 template <typename stackAllocator>
641 ValueType& GetWithDefault(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, const std::basic_string<Ch>& defaultValue) const {
642 return GetWithDefault(document, defaultValue, document.GetAllocator());
643 }
644#endif
645
647
650 template <typename T, typename stackAllocator>
651 RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (ValueType&))
652 GetWithDefault(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, T defaultValue) const {
653 return GetWithDefault(document, defaultValue, document.GetAllocator());
654 }
655
657
659
660
662
671 ValueType& Set(ValueType& root, ValueType& value, typename ValueType::AllocatorType& allocator) const {
672 return Create(root, allocator) = value;
673 }
674
676 ValueType& Set(ValueType& root, const ValueType& value, typename ValueType::AllocatorType& allocator) const {
677 return Create(root, allocator).CopyFrom(value, allocator);
678 }
679
681 ValueType& Set(ValueType& root, const Ch* value, typename ValueType::AllocatorType& allocator) const {
682 return Create(root, allocator) = ValueType(value, allocator).Move();
683 }
684
685#if RAPIDJSON_HAS_STDSTRING
687 ValueType& Set(ValueType& root, const std::basic_string<Ch>& value, typename ValueType::AllocatorType& allocator) const {
688 return Create(root, allocator) = ValueType(value, allocator).Move();
689 }
690#endif
691
693
696 template <typename T>
697 RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (ValueType&))
698 Set(ValueType& root, T value, typename ValueType::AllocatorType& allocator) const {
699 return Create(root, allocator) = ValueType(value).Move();
700 }
701
703 template <typename stackAllocator>
704 ValueType& Set(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, ValueType& value) const {
705 return Create(document) = value;
706 }
707
709 template <typename stackAllocator>
710 ValueType& Set(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, const ValueType& value) const {
711 return Create(document).CopyFrom(value, document.GetAllocator());
712 }
713
715 template <typename stackAllocator>
716 ValueType& Set(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, const Ch* value) const {
717 return Create(document) = ValueType(value, document.GetAllocator()).Move();
718 }
719
720#if RAPIDJSON_HAS_STDSTRING
722 template <typename stackAllocator>
723 ValueType& Set(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, const std::basic_string<Ch>& value) const {
724 return Create(document) = ValueType(value, document.GetAllocator()).Move();
725 }
726#endif
727
729
732 template <typename T, typename stackAllocator>
733 RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (ValueType&))
734 Set(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, T value) const {
735 return Create(document) = value;
736 }
737
739
741
742
744
753 ValueType& Swap(ValueType& root, ValueType& value, typename ValueType::AllocatorType& allocator) const {
754 return Create(root, allocator).Swap(value);
755 }
756
758 template <typename stackAllocator>
759 ValueType& Swap(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, ValueType& value) const {
760 return Create(document).Swap(value);
761 }
762
764
766
772 bool Erase(ValueType& root) const {
773 RAPIDJSON_ASSERT(IsValid());
774 if (tokenCount_ == 0) // Cannot erase the root
775 return false;
776
777 ValueType* v = &root;
778 const Token* last = tokens_ + (tokenCount_ - 1);
779 for (const Token *t = tokens_; t != last; ++t) {
780 switch (v->GetType()) {
781 case kObjectType:
782 {
783 typename ValueType::MemberIterator m = v->FindMember(GenericValue<EncodingType>(GenericStringRef<Ch>(t->name, t->length)));
784 if (m == v->MemberEnd())
785 return false;
786 v = &m->value;
787 }
788 break;
789 case kArrayType:
790 if (t->index == kPointerInvalidIndex || t->index >= v->Size())
791 return false;
792 v = &((*v)[t->index]);
793 break;
794 default:
795 return false;
796 }
797 }
798
799 switch (v->GetType()) {
800 case kObjectType:
801 return v->EraseMember(GenericStringRef<Ch>(last->name, last->length));
802 case kArrayType:
803 if (last->index == kPointerInvalidIndex || last->index >= v->Size())
804 return false;
805 v->Erase(v->Begin() + last->index);
806 return true;
807 default:
808 return false;
809 }
810 }
811
812private:
814
820 Ch* CopyFromRaw(const GenericPointer& rhs, size_t extraToken = 0, size_t extraNameBufferSize = 0) {
821 if (!allocator_) // allocator is independently owned.
822 ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)();
823
824 size_t nameBufferSize = rhs.tokenCount_; // null terminators for tokens
825 for (Token *t = rhs.tokens_; t != rhs.tokens_ + rhs.tokenCount_; ++t)
826 nameBufferSize += t->length;
827
828 tokenCount_ = rhs.tokenCount_ + extraToken;
829 tokens_ = static_cast<Token *>(allocator_->Malloc(tokenCount_ * sizeof(Token) + (nameBufferSize + extraNameBufferSize) * sizeof(Ch)));
830 nameBuffer_ = reinterpret_cast<Ch *>(tokens_ + tokenCount_);
831 if (rhs.tokenCount_ > 0) {
832 std::memcpy(tokens_, rhs.tokens_, rhs.tokenCount_ * sizeof(Token));
833 }
834 if (nameBufferSize > 0) {
835 std::memcpy(nameBuffer_, rhs.nameBuffer_, nameBufferSize * sizeof(Ch));
836 }
837
838 // Adjust pointers to name buffer
839 std::ptrdiff_t diff = nameBuffer_ - rhs.nameBuffer_;
840 for (Token *t = tokens_; t != tokens_ + rhs.tokenCount_; ++t)
841 t->name += diff;
842
843 return nameBuffer_ + nameBufferSize;
844 }
845
847
851 bool NeedPercentEncode(Ch c) const {
852 return !((c >= '0' && c <= '9') || (c >= 'A' && c <='Z') || (c >= 'a' && c <= 'z') || c == '-' || c == '.' || c == '_' || c =='~');
853 }
854
856#ifndef __clang__ // -Wdocumentation
862#endif
863 void Parse(const Ch* source, size_t length) {
864 RAPIDJSON_ASSERT(source != NULL);
867
868 // Create own allocator if user did not supply.
869 if (!allocator_)
870 ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)();
871
872 // Count number of '/' as tokenCount
873 tokenCount_ = 0;
874 for (const Ch* s = source; s != source + length; s++)
875 if (*s == '/')
876 tokenCount_++;
877
878 Token* token = tokens_ = static_cast<Token *>(allocator_->Malloc(tokenCount_ * sizeof(Token) + length * sizeof(Ch)));
879 Ch* name = nameBuffer_ = reinterpret_cast<Ch *>(tokens_ + tokenCount_);
880 size_t i = 0;
881
882 // Detect if it is a URI fragment
883 bool uriFragment = false;
884 if (source[i] == '#') {
885 uriFragment = true;
886 i++;
887 }
888
889 if (i != length && source[i] != '/') {
891 goto error;
892 }
893
894 while (i < length) {
895 RAPIDJSON_ASSERT(source[i] == '/');
896 i++; // consumes '/'
897
898 token->name = name;
899 bool isNumber = true;
900
901 while (i < length && source[i] != '/') {
902 Ch c = source[i];
903 if (uriFragment) {
904 // Decoding percent-encoding for URI fragment
905 if (c == '%') {
906 PercentDecodeStream is(&source[i], source + length);
907 GenericInsituStringStream<EncodingType> os(name);
908 Ch* begin = os.PutBegin();
909 if (!Transcoder<UTF8<>, EncodingType>().Validate(is, os) || !is.IsValid()) {
911 goto error;
912 }
913 size_t len = os.PutEnd(begin);
914 i += is.Tell() - 1;
915 if (len == 1)
916 c = *name;
917 else {
918 name += len;
919 isNumber = false;
920 i++;
921 continue;
922 }
923 }
924 else if (NeedPercentEncode(c)) {
926 goto error;
927 }
928 }
929
930 i++;
931
932 // Escaping "~0" -> '~', "~1" -> '/'
933 if (c == '~') {
934 if (i < length) {
935 c = source[i];
936 if (c == '0') c = '~';
937 else if (c == '1') c = '/';
938 else {
940 goto error;
941 }
942 i++;
943 }
944 else {
946 goto error;
947 }
948 }
949
950 // First check for index: all of characters are digit
951 if (c < '0' || c > '9')
952 isNumber = false;
953
954 *name++ = c;
955 }
956 token->length = static_cast<SizeType>(name - token->name);
957 if (token->length == 0)
958 isNumber = false;
959 *name++ = '\0'; // Null terminator
960
961 // Second check for index: more than one digit cannot have leading zero
962 if (isNumber && token->length > 1 && token->name[0] == '0')
963 isNumber = false;
964
965 // String to SizeType conversion
966 SizeType n = 0;
967 if (isNumber) {
968 for (size_t j = 0; j < token->length; j++) {
969 SizeType m = n * 10 + static_cast<SizeType>(token->name[j] - '0');
970 if (m < n) { // overflow detection
971 isNumber = false;
972 break;
973 }
974 n = m;
975 }
976 }
977
978 token->index = isNumber ? n : kPointerInvalidIndex;
979 token++;
980 }
981
982 RAPIDJSON_ASSERT(name <= nameBuffer_ + length); // Should not overflow buffer
984 return;
985
986 error:
987 Allocator::Free(tokens_);
988 nameBuffer_ = 0;
989 tokens_ = 0;
990 tokenCount_ = 0;
992 return;
993 }
994
996
1001 template<bool uriFragment, typename OutputStream>
1002 bool Stringify(OutputStream& os) const {
1003 RAPIDJSON_ASSERT(IsValid());
1004
1005 if (uriFragment)
1006 os.Put('#');
1007
1008 for (Token *t = tokens_; t != tokens_ + tokenCount_; ++t) {
1009 os.Put('/');
1010 for (size_t j = 0; j < t->length; j++) {
1011 Ch c = t->name[j];
1012 if (c == '~') {
1013 os.Put('~');
1014 os.Put('0');
1015 }
1016 else if (c == '/') {
1017 os.Put('~');
1018 os.Put('1');
1019 }
1020 else if (uriFragment && NeedPercentEncode(c)) {
1021 // Transcode to UTF8 sequence
1022 GenericStringStream<typename ValueType::EncodingType> source(&t->name[j]);
1024 if (!Transcoder<EncodingType, UTF8<> >().Validate(source, target))
1025 return false;
1026 j += source.Tell() - 1;
1027 }
1028 else
1029 os.Put(c);
1030 }
1031 }
1032 return true;
1033 }
1034
1036
1041 class PercentDecodeStream {
1042 public:
1043 typedef typename ValueType::Ch Ch;
1044
1046
1050 PercentDecodeStream(const Ch* source, const Ch* end) : src_(source), head_(source), end_(end), valid_(true) {}
1051
1052 Ch Take() {
1053 if (*src_ != '%' || src_ + 3 > end_) { // %XY triplet
1054 valid_ = false;
1055 return 0;
1056 }
1057 src_++;
1058 Ch c = 0;
1059 for (int j = 0; j < 2; j++) {
1060 c = static_cast<Ch>(c << 4);
1061 Ch h = *src_;
1062 if (h >= '0' && h <= '9') c = static_cast<Ch>(c + h - '0');
1063 else if (h >= 'A' && h <= 'F') c = static_cast<Ch>(c + h - 'A' + 10);
1064 else if (h >= 'a' && h <= 'f') c = static_cast<Ch>(c + h - 'a' + 10);
1065 else {
1066 valid_ = false;
1067 return 0;
1068 }
1069 src_++;
1070 }
1071 return c;
1072 }
1073
1074 size_t Tell() const { return static_cast<size_t>(src_ - head_); }
1075 bool IsValid() const { return valid_; }
1076
1077 private:
1078 const Ch* src_;
1079 const Ch* head_;
1080 const Ch* end_;
1081 bool valid_;
1082 };
1083
1085 template <typename OutputStream>
1086 class PercentEncodeStream {
1087 public:
1088 PercentEncodeStream(OutputStream& os) : os_(os) {}
1089 void Put(char c) { // UTF-8 must be byte
1090 unsigned char u = static_cast<unsigned char>(c);
1091 static const char hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
1092 os_.Put('%');
1093 os_.Put(static_cast<typename OutputStream::Ch>(hexDigits[u >> 4]));
1094 os_.Put(static_cast<typename OutputStream::Ch>(hexDigits[u & 15]));
1095 }
1096 private:
1097 OutputStream& os_;
1098 };
1099
1103 Token* tokens_;
1107};
1108
1110typedef GenericPointer<Value> Pointer;
1111
1113
1114
1116
1117template <typename T>
1118typename T::ValueType& CreateValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, typename T::AllocatorType& a) {
1119 return pointer.Create(root, a);
1120}
1121
1122template <typename T, typename CharType, size_t N>
1123typename T::ValueType& CreateValueByPointer(T& root, const CharType(&source)[N], typename T::AllocatorType& a) {
1124 return GenericPointer<typename T::ValueType>(source, N - 1).Create(root, a);
1125}
1126
1127// No allocator parameter
1128
1129template <typename DocumentType>
1130typename DocumentType::ValueType& CreateValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer) {
1131 return pointer.Create(document);
1132}
1133
1134template <typename DocumentType, typename CharType, size_t N>
1135typename DocumentType::ValueType& CreateValueByPointer(DocumentType& document, const CharType(&source)[N]) {
1136 return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Create(document);
1137}
1138
1140
1141template <typename T>
1142typename T::ValueType* GetValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, size_t* unresolvedTokenIndex = 0) {
1143 return pointer.Get(root, unresolvedTokenIndex);
1144}
1145
1146template <typename T>
1147const typename T::ValueType* GetValueByPointer(const T& root, const GenericPointer<typename T::ValueType>& pointer, size_t* unresolvedTokenIndex = 0) {
1148 return pointer.Get(root, unresolvedTokenIndex);
1149}
1150
1151template <typename T, typename CharType, size_t N>
1152typename T::ValueType* GetValueByPointer(T& root, const CharType (&source)[N], size_t* unresolvedTokenIndex = 0) {
1153 return GenericPointer<typename T::ValueType>(source, N - 1).Get(root, unresolvedTokenIndex);
1154}
1155
1156template <typename T, typename CharType, size_t N>
1157const typename T::ValueType* GetValueByPointer(const T& root, const CharType(&source)[N], size_t* unresolvedTokenIndex = 0) {
1158 return GenericPointer<typename T::ValueType>(source, N - 1).Get(root, unresolvedTokenIndex);
1159}
1160
1162
1163template <typename T>
1164typename T::ValueType& GetValueByPointerWithDefault(T& root, const GenericPointer<typename T::ValueType>& pointer, const typename T::ValueType& defaultValue, typename T::AllocatorType& a) {
1165 return pointer.GetWithDefault(root, defaultValue, a);
1166}
1167
1168template <typename T>
1169typename T::ValueType& GetValueByPointerWithDefault(T& root, const GenericPointer<typename T::ValueType>& pointer, const typename T::Ch* defaultValue, typename T::AllocatorType& a) {
1170 return pointer.GetWithDefault(root, defaultValue, a);
1171}
1172
1173#if RAPIDJSON_HAS_STDSTRING
1174template <typename T>
1175typename T::ValueType& GetValueByPointerWithDefault(T& root, const GenericPointer<typename T::ValueType>& pointer, const std::basic_string<typename T::Ch>& defaultValue, typename T::AllocatorType& a) {
1176 return pointer.GetWithDefault(root, defaultValue, a);
1177}
1178#endif
1179
1180template <typename T, typename T2>
1181RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename T::ValueType&))
1182GetValueByPointerWithDefault(T& root, const GenericPointer<typename T::ValueType>& pointer, T2 defaultValue, typename T::AllocatorType& a) {
1183 return pointer.GetWithDefault(root, defaultValue, a);
1184}
1185
1186template <typename T, typename CharType, size_t N>
1187typename T::ValueType& GetValueByPointerWithDefault(T& root, const CharType(&source)[N], const typename T::ValueType& defaultValue, typename T::AllocatorType& a) {
1188 return GenericPointer<typename T::ValueType>(source, N - 1).GetWithDefault(root, defaultValue, a);
1189}
1190
1191template <typename T, typename CharType, size_t N>
1192typename T::ValueType& GetValueByPointerWithDefault(T& root, const CharType(&source)[N], const typename T::Ch* defaultValue, typename T::AllocatorType& a) {
1193 return GenericPointer<typename T::ValueType>(source, N - 1).GetWithDefault(root, defaultValue, a);
1194}
1195
1196#if RAPIDJSON_HAS_STDSTRING
1197template <typename T, typename CharType, size_t N>
1198typename T::ValueType& GetValueByPointerWithDefault(T& root, const CharType(&source)[N], const std::basic_string<typename T::Ch>& defaultValue, typename T::AllocatorType& a) {
1199 return GenericPointer<typename T::ValueType>(source, N - 1).GetWithDefault(root, defaultValue, a);
1200}
1201#endif
1202
1203template <typename T, typename CharType, size_t N, typename T2>
1204RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename T::ValueType&))
1205GetValueByPointerWithDefault(T& root, const CharType(&source)[N], T2 defaultValue, typename T::AllocatorType& a) {
1206 return GenericPointer<typename T::ValueType>(source, N - 1).GetWithDefault(root, defaultValue, a);
1207}
1208
1209// No allocator parameter
1210
1211template <typename DocumentType>
1212typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, const typename DocumentType::ValueType& defaultValue) {
1213 return pointer.GetWithDefault(document, defaultValue);
1214}
1215
1216template <typename DocumentType>
1217typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, const typename DocumentType::Ch* defaultValue) {
1218 return pointer.GetWithDefault(document, defaultValue);
1219}
1220
1221#if RAPIDJSON_HAS_STDSTRING
1222template <typename DocumentType>
1223typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, const std::basic_string<typename DocumentType::Ch>& defaultValue) {
1224 return pointer.GetWithDefault(document, defaultValue);
1225}
1226#endif
1227
1228template <typename DocumentType, typename T2>
1229RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename DocumentType::ValueType&))
1230GetValueByPointerWithDefault(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, T2 defaultValue) {
1231 return pointer.GetWithDefault(document, defaultValue);
1232}
1233
1234template <typename DocumentType, typename CharType, size_t N>
1235typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], const typename DocumentType::ValueType& defaultValue) {
1236 return GenericPointer<typename DocumentType::ValueType>(source, N - 1).GetWithDefault(document, defaultValue);
1237}
1238
1239template <typename DocumentType, typename CharType, size_t N>
1240typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], const typename DocumentType::Ch* defaultValue) {
1241 return GenericPointer<typename DocumentType::ValueType>(source, N - 1).GetWithDefault(document, defaultValue);
1242}
1243
1244#if RAPIDJSON_HAS_STDSTRING
1245template <typename DocumentType, typename CharType, size_t N>
1246typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], const std::basic_string<typename DocumentType::Ch>& defaultValue) {
1247 return GenericPointer<typename DocumentType::ValueType>(source, N - 1).GetWithDefault(document, defaultValue);
1248}
1249#endif
1250
1251template <typename DocumentType, typename CharType, size_t N, typename T2>
1252RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename DocumentType::ValueType&))
1253GetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], T2 defaultValue) {
1254 return GenericPointer<typename DocumentType::ValueType>(source, N - 1).GetWithDefault(document, defaultValue);
1255}
1256
1258
1259template <typename T>
1260typename T::ValueType& SetValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, typename T::ValueType& value, typename T::AllocatorType& a) {
1261 return pointer.Set(root, value, a);
1262}
1263
1264template <typename T>
1265typename T::ValueType& SetValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, const typename T::ValueType& value, typename T::AllocatorType& a) {
1266 return pointer.Set(root, value, a);
1267}
1268
1269template <typename T>
1270typename T::ValueType& SetValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, const typename T::Ch* value, typename T::AllocatorType& a) {
1271 return pointer.Set(root, value, a);
1272}
1273
1274#if RAPIDJSON_HAS_STDSTRING
1275template <typename T>
1276typename T::ValueType& SetValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, const std::basic_string<typename T::Ch>& value, typename T::AllocatorType& a) {
1277 return pointer.Set(root, value, a);
1278}
1279#endif
1280
1281template <typename T, typename T2>
1282RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename T::ValueType&))
1283SetValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, T2 value, typename T::AllocatorType& a) {
1284 return pointer.Set(root, value, a);
1285}
1286
1287template <typename T, typename CharType, size_t N>
1288typename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], typename T::ValueType& value, typename T::AllocatorType& a) {
1289 return GenericPointer<typename T::ValueType>(source, N - 1).Set(root, value, a);
1290}
1291
1292template <typename T, typename CharType, size_t N>
1293typename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], const typename T::ValueType& value, typename T::AllocatorType& a) {
1294 return GenericPointer<typename T::ValueType>(source, N - 1).Set(root, value, a);
1295}
1296
1297template <typename T, typename CharType, size_t N>
1298typename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], const typename T::Ch* value, typename T::AllocatorType& a) {
1299 return GenericPointer<typename T::ValueType>(source, N - 1).Set(root, value, a);
1300}
1301
1302#if RAPIDJSON_HAS_STDSTRING
1303template <typename T, typename CharType, size_t N>
1304typename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], const std::basic_string<typename T::Ch>& value, typename T::AllocatorType& a) {
1305 return GenericPointer<typename T::ValueType>(source, N - 1).Set(root, value, a);
1306}
1307#endif
1308
1309template <typename T, typename CharType, size_t N, typename T2>
1310RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename T::ValueType&))
1311SetValueByPointer(T& root, const CharType(&source)[N], T2 value, typename T::AllocatorType& a) {
1312 return GenericPointer<typename T::ValueType>(source, N - 1).Set(root, value, a);
1313}
1314
1315// No allocator parameter
1316
1317template <typename DocumentType>
1318typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, typename DocumentType::ValueType& value) {
1319 return pointer.Set(document, value);
1320}
1321
1322template <typename DocumentType>
1323typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, const typename DocumentType::ValueType& value) {
1324 return pointer.Set(document, value);
1325}
1326
1327template <typename DocumentType>
1328typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, const typename DocumentType::Ch* value) {
1329 return pointer.Set(document, value);
1330}
1331
1332#if RAPIDJSON_HAS_STDSTRING
1333template <typename DocumentType>
1334typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, const std::basic_string<typename DocumentType::Ch>& value) {
1335 return pointer.Set(document, value);
1336}
1337#endif
1338
1339template <typename DocumentType, typename T2>
1340RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename DocumentType::ValueType&))
1341SetValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, T2 value) {
1342 return pointer.Set(document, value);
1343}
1344
1345template <typename DocumentType, typename CharType, size_t N>
1346typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType(&source)[N], typename DocumentType::ValueType& value) {
1347 return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Set(document, value);
1348}
1349
1350template <typename DocumentType, typename CharType, size_t N>
1351typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType(&source)[N], const typename DocumentType::ValueType& value) {
1352 return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Set(document, value);
1353}
1354
1355template <typename DocumentType, typename CharType, size_t N>
1356typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType(&source)[N], const typename DocumentType::Ch* value) {
1357 return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Set(document, value);
1358}
1359
1360#if RAPIDJSON_HAS_STDSTRING
1361template <typename DocumentType, typename CharType, size_t N>
1362typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType(&source)[N], const std::basic_string<typename DocumentType::Ch>& value) {
1363 return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Set(document, value);
1364}
1365#endif
1366
1367template <typename DocumentType, typename CharType, size_t N, typename T2>
1368RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename DocumentType::ValueType&))
1369SetValueByPointer(DocumentType& document, const CharType(&source)[N], T2 value) {
1370 return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Set(document, value);
1371}
1372
1374
1375template <typename T>
1376typename T::ValueType& SwapValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, typename T::ValueType& value, typename T::AllocatorType& a) {
1377 return pointer.Swap(root, value, a);
1378}
1379
1380template <typename T, typename CharType, size_t N>
1381typename T::ValueType& SwapValueByPointer(T& root, const CharType(&source)[N], typename T::ValueType& value, typename T::AllocatorType& a) {
1382 return GenericPointer<typename T::ValueType>(source, N - 1).Swap(root, value, a);
1383}
1384
1385template <typename DocumentType>
1386typename DocumentType::ValueType& SwapValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, typename DocumentType::ValueType& value) {
1387 return pointer.Swap(document, value);
1388}
1389
1390template <typename DocumentType, typename CharType, size_t N>
1391typename DocumentType::ValueType& SwapValueByPointer(DocumentType& document, const CharType(&source)[N], typename DocumentType::ValueType& value) {
1392 return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Swap(document, value);
1393}
1394
1396
1397template <typename T>
1398bool EraseValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer) {
1399 return pointer.Erase(root);
1400}
1401
1402template <typename T, typename CharType, size_t N>
1403bool EraseValueByPointer(T& root, const CharType(&source)[N]) {
1404 return GenericPointer<typename T::ValueType>(source, N - 1).Erase(root);
1405}
1406
1408
1410
1411#if defined(__clang__) || defined(_MSC_VER)
1412RAPIDJSON_DIAG_POP
1413#endif
1414
1415#endif // RAPIDJSON_POINTER_H_
Allocator & GetAllocator()
Get the allocator of this document.
Definition document.h:2491
A helper stream to encode character (UTF-8 code unit) into percent-encoded sequence.
Definition pointer.h:1086
Represents a JSON Pointer. Use Pointer for UTF8 encoding and default allocator.
Definition pointer.h:79
friend void swap(GenericPointer &a, GenericPointer &b) RAPIDJSON_NOEXCEPT
free-standing swap function helper
Definition pointer.h:231
GenericPointer(const GenericPointer &rhs, Allocator *allocator)
Copy constructor.
Definition pointer.h:171
GenericPointer(const Ch *source, Allocator *allocator=0)
Constructor that parses a string or URI fragment representation.
Definition pointer.h:114
Value::EncodingType EncodingType
Definition pointer.h:81
GenericPointer(const Token *tokens, size_t tokenCount)
Constructor with user-supplied tokens.
Definition pointer.h:163
GenericPointer(Allocator *allocator=0)
Default constructor.
Definition pointer.h:107
GenericPointer(const GenericPointer &rhs)
Copy constructor.
Definition pointer.h:166
PointerParseErrorCode parseErrorCode_
Definition pointer.h:1106
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.
Definition pointer.h:137
GenericPointer Append(const Ch *name, SizeType length, Allocator *allocator=0) const
Append a name token with length, and return a new Pointer.
Definition pointer.h:262
GenericPointer Append(const Token &token, Allocator *allocator=0) const
Append a token and return a new Pointer.
Definition pointer.h:244
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.
~GenericPointer()
Destructor.
Definition pointer.h:176
GenericPointer & operator=(const GenericPointer &rhs)
Assignment operator.
Definition pointer.h:183
GenericPointer & Swap(GenericPointer &other) RAPIDJSON_NOEXCEPT
Swap the content of this pointer with an other.
Definition pointer.h:208
Concept for allocating, resizing and freeing memory block.
#define RAPIDJSON_ASSERT(x)
Assertion.
Definition rapidjson.h:406
#define RAPIDJSON_NAMESPACE_BEGIN
provide custom rapidjson namespace (opening expression)
Definition rapidjson.h:121
#define RAPIDJSON_NAMESPACE_END
provide custom rapidjson namespace (closing expression)
Definition rapidjson.h:124
PointerParseErrorCode
Error code of parsing.
Definition pointer.h:37
@ kPointerParseErrorInvalidEscape
Invalid escape.
Definition pointer.h:41
@ kPointerParseErrorTokenMustBeginWithSolidus
A token must begin with a '/'.
Definition pointer.h:40
@ kPointerParseErrorNone
The parse is successful.
Definition pointer.h:38
@ kPointerParseErrorCharacterMustPercentEncode
A character must percent encoded in URI fragment.
Definition pointer.h:43
@ kPointerParseErrorInvalidPercentEncoding
Invalid percent encoding in URI fragment.
Definition pointer.h:42
@ kObjectType
object
Definition rapidjson.h:668
@ kArrayType
array
Definition rapidjson.h:669
#define RAPIDJSON_DELETE(x)
! customization point for global delete
Definition rapidjson.h:651
RAPIDJSON_NAMESPACE_BEGIN typedef unsigned SizeType
Size type (for string lengths, array sizes, etc.)
Definition rapidjson.h:384
#define RAPIDJSON_NEW(TypeName)
! customization point for global new
Definition rapidjson.h:647
A token is the basic units of internal representation.
Definition pointer.h:97
SizeType index
A valid array index, if it is not equal to kPointerInvalidIndex.
Definition pointer.h:100
SizeType length
Length of the name.
Definition pointer.h:99
const Ch * name
Name of the token. It has null character at the end but it can contain null character.
Definition pointer.h:98