]> git.proxmox.com Git - ceph.git/blob - ceph/src/rocksdb/third-party/fbson/FbsonDocument.h
build: use dgit for download target
[ceph.git] / ceph / src / rocksdb / third-party / fbson / FbsonDocument.h
1 // Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
2 // This source code is licensed under both the GPLv2 (found in the
3 // COPYING file in the root directory) and Apache 2.0 License
4 // (found in the LICENSE.Apache file in the root directory).
5
6 /*
7 * This header defines FbsonDocument, FbsonKeyValue, and various value classes
8 * which are derived from FbsonValue, and a forward iterator for container
9 * values - essentially everything that is related to FBSON binary data
10 * structures.
11 *
12 * Implementation notes:
13 *
14 * None of the classes in this header file can be instantiated directly (i.e.
15 * you cannot create a FbsonKeyValue or FbsonValue object - all constructors
16 * are declared non-public). We use the classes as wrappers on the packed FBSON
17 * bytes (serialized), and cast the classes (types) to the underlying packed
18 * byte array.
19 *
20 * For the same reason, we cannot define any FBSON value class to be virtual,
21 * since we never call constructors, and will not instantiate vtbl and vptrs.
22 *
23 * Therefore, the classes are defined as packed structures (i.e. no data
24 * alignment and padding), and the private member variables of the classes are
25 * defined precisely in the same order as the FBSON spec. This ensures we
26 * access the packed FBSON bytes correctly.
27 *
28 * The packed structures are highly optimized for in-place operations with low
29 * overhead. The reads (and in-place writes) are performed directly on packed
30 * bytes. There is no memory allocation at all at runtime.
31 *
32 * For updates/writes of values that will expand the original FBSON size, the
33 * write will fail, and the caller needs to handle buffer increase.
34 *
35 * ** Iterator **
36 * Both ObjectVal class and ArrayVal class have iterator type that you can use
37 * to declare an iterator on a container object to go through the key-value
38 * pairs or value list. The iterator has both non-const and const types.
39 *
40 * Note: iterators are forward direction only.
41 *
42 * ** Query **
43 * Querying into containers is through the member functions find (for key/value
44 * pairs) and get (for array elements), and is in streaming style. We don't
45 * need to read/scan the whole FBSON packed bytes in order to return results.
46 * Once the key/index is found, we will stop search. You can use text to query
47 * both objects and array (for array, text will be converted to integer index),
48 * and use index to retrieve from array. Array index is 0-based.
49 *
50 * ** External dictionary **
51 * During query processing, you can also pass a callback function, so the
52 * search will first try to check if the key string exists in the dictionary.
53 * If so, search will be based on the id instead of the key string.
54 *
55 * @author Tian Xia <tianx@fb.com>
56 */
57
58 #pragma once
59
60 #include <stdlib.h>
61 #include <string.h>
62 #include <assert.h>
63
64 namespace fbson {
65
66 #pragma pack(push, 1)
67
68 #define FBSON_VER 1
69
70 // forward declaration
71 class FbsonValue;
72 class ObjectVal;
73
74 /*
75 * FbsonDocument is the main object that accesses and queries FBSON packed
76 * bytes. NOTE: FbsonDocument only allows object container as the top level
77 * FBSON value. However, you can use the static method "createValue" to get any
78 * FbsonValue object from the packed bytes.
79 *
80 * FbsonDocument object also dereferences to an object container value
81 * (ObjectVal) once FBSON is loaded.
82 *
83 * ** Load **
84 * FbsonDocument is usable after loading packed bytes (memory location) into
85 * the object. We only need the header and first few bytes of the payload after
86 * header to verify the FBSON.
87 *
88 * Note: creating an FbsonDocument (through createDocument) does not allocate
89 * any memory. The document object is an efficient wrapper on the packed bytes
90 * which is accessed directly.
91 *
92 * ** Query **
93 * Query is through dereferencing into ObjectVal.
94 */
95 class FbsonDocument {
96 public:
97 // create an FbsonDocument object from FBSON packed bytes
98 static FbsonDocument* createDocument(const char* pb, uint32_t size);
99
100 // create an FbsonValue from FBSON packed bytes
101 static FbsonValue* createValue(const char* pb, uint32_t size);
102
103 uint8_t version() { return header_.ver_; }
104
105 FbsonValue* getValue() { return ((FbsonValue*)payload_); }
106
107 ObjectVal* operator->() { return ((ObjectVal*)payload_); }
108
109 const ObjectVal* operator->() const { return ((const ObjectVal*)payload_); }
110
111 private:
112 /*
113 * FbsonHeader class defines FBSON header (internal to FbsonDocument).
114 *
115 * Currently it only contains version information (1-byte). We may expand the
116 * header to include checksum of the FBSON binary for more security.
117 */
118 struct FbsonHeader {
119 uint8_t ver_;
120 } header_;
121
122 char payload_[1];
123
124 FbsonDocument();
125
126 FbsonDocument(const FbsonDocument&) = delete;
127 FbsonDocument& operator=(const FbsonDocument&) = delete;
128 };
129
130 /*
131 * FbsonFwdIteratorT implements FBSON's iterator template.
132 *
133 * Note: it is an FORWARD iterator only due to the design of FBSON format.
134 */
135 template <class Iter_Type, class Cont_Type>
136 class FbsonFwdIteratorT {
137 typedef Iter_Type iterator;
138 typedef typename std::iterator_traits<Iter_Type>::pointer pointer;
139 typedef typename std::iterator_traits<Iter_Type>::reference reference;
140
141 public:
142 explicit FbsonFwdIteratorT(const iterator& i) : current_(i) {}
143
144 // allow non-const to const iterator conversion (same container type)
145 template <class Iter_Ty>
146 FbsonFwdIteratorT(const FbsonFwdIteratorT<Iter_Ty, Cont_Type>& rhs)
147 : current_(rhs.base()) {}
148
149 bool operator==(const FbsonFwdIteratorT& rhs) const {
150 return (current_ == rhs.current_);
151 }
152
153 bool operator!=(const FbsonFwdIteratorT& rhs) const {
154 return !operator==(rhs);
155 }
156
157 bool operator<(const FbsonFwdIteratorT& rhs) const {
158 return (current_ < rhs.current_);
159 }
160
161 bool operator>(const FbsonFwdIteratorT& rhs) const { return !operator<(rhs); }
162
163 FbsonFwdIteratorT& operator++() {
164 current_ = (iterator)(((char*)current_) + current_->numPackedBytes());
165 return *this;
166 }
167
168 FbsonFwdIteratorT operator++(int) {
169 auto tmp = *this;
170 current_ = (iterator)(((char*)current_) + current_->numPackedBytes());
171 return tmp;
172 }
173
174 explicit operator pointer() { return current_; }
175
176 reference operator*() const { return *current_; }
177
178 pointer operator->() const { return current_; }
179
180 iterator base() const { return current_; }
181
182 private:
183 iterator current_;
184 };
185
186 typedef int (*hDictInsert)(const char* key, unsigned len);
187 typedef int (*hDictFind)(const char* key, unsigned len);
188
189 /*
190 * FbsonType defines 10 primitive types and 2 container types, as described
191 * below.
192 *
193 * primitive_value ::=
194 * 0x00 //null value (0 byte)
195 * | 0x01 //boolean true (0 byte)
196 * | 0x02 //boolean false (0 byte)
197 * | 0x03 int8 //char/int8 (1 byte)
198 * | 0x04 int16 //int16 (2 bytes)
199 * | 0x05 int32 //int32 (4 bytes)
200 * | 0x06 int64 //int64 (8 bytes)
201 * | 0x07 double //floating point (8 bytes)
202 * | 0x08 string //variable length string
203 * | 0x09 binary //variable length binary
204 *
205 * container ::=
206 * 0x0A int32 key_value_list //object, int32 is the total bytes of the object
207 * | 0x0B int32 value_list //array, int32 is the total bytes of the array
208 */
209 enum class FbsonType : char {
210 T_Null = 0x00,
211 T_True = 0x01,
212 T_False = 0x02,
213 T_Int8 = 0x03,
214 T_Int16 = 0x04,
215 T_Int32 = 0x05,
216 T_Int64 = 0x06,
217 T_Double = 0x07,
218 T_String = 0x08,
219 T_Binary = 0x09,
220 T_Object = 0x0A,
221 T_Array = 0x0B,
222 NUM_TYPES,
223 };
224
225 typedef std::underlying_type<FbsonType>::type FbsonTypeUnder;
226
227 /*
228 * FbsonKeyValue class defines FBSON key type, as described below.
229 *
230 * key ::=
231 * 0x00 int8 //1-byte dictionary id
232 * | int8 (byte*) //int8 (>0) is the size of the key string
233 *
234 * value ::= primitive_value | container
235 *
236 * FbsonKeyValue can be either an id mapping to the key string in an external
237 * dictionary, or it is the original key string. Whether to read an id or a
238 * string is decided by the first byte (size_).
239 *
240 * Note: a key object must be followed by a value object. Therefore, a key
241 * object implicitly refers to a key-value pair, and you can get the value
242 * object right after the key object. The function numPackedBytes hence
243 * indicates the total size of the key-value pair, so that we will be able go
244 * to next pair from the key.
245 *
246 * ** Dictionary size **
247 * By default, the dictionary size is 255 (1-byte). Users can define
248 * "USE_LARGE_DICT" to increase the dictionary size to 655535 (2-byte).
249 */
250 class FbsonKeyValue {
251 public:
252 #ifdef USE_LARGE_DICT
253 static const int sMaxKeyId = 65535;
254 typedef uint16_t keyid_type;
255 #else
256 static const int sMaxKeyId = 255;
257 typedef uint8_t keyid_type;
258 #endif // #ifdef USE_LARGE_DICT
259
260 static const uint8_t sMaxKeyLen = 64;
261
262 // size of the key. 0 indicates it is stored as id
263 uint8_t klen() const { return size_; }
264
265 // get the key string. Note the string may not be null terminated.
266 const char* getKeyStr() const { return key_.str_; }
267
268 keyid_type getKeyId() const { return key_.id_; }
269
270 unsigned int keyPackedBytes() const {
271 return size_ ? (sizeof(size_) + size_)
272 : (sizeof(size_) + sizeof(keyid_type));
273 }
274
275 FbsonValue* value() const {
276 return (FbsonValue*)(((char*)this) + keyPackedBytes());
277 }
278
279 // size of the total packed bytes (key+value)
280 unsigned int numPackedBytes() const;
281
282 private:
283 uint8_t size_;
284
285 union key_ {
286 keyid_type id_;
287 char str_[1];
288 } key_;
289
290 FbsonKeyValue();
291 };
292
293 /*
294 * FbsonValue is the base class of all FBSON types. It contains only one member
295 * variable - type info, which can be retrieved by member functions is[Type]()
296 * or type().
297 */
298 class FbsonValue {
299 public:
300 static const uint32_t sMaxValueLen = 1 << 24; // 16M
301
302 bool isNull() const { return (type_ == FbsonType::T_Null); }
303 bool isTrue() const { return (type_ == FbsonType::T_True); }
304 bool isFalse() const { return (type_ == FbsonType::T_False); }
305 bool isInt8() const { return (type_ == FbsonType::T_Int8); }
306 bool isInt16() const { return (type_ == FbsonType::T_Int16); }
307 bool isInt32() const { return (type_ == FbsonType::T_Int32); }
308 bool isInt64() const { return (type_ == FbsonType::T_Int64); }
309 bool isDouble() const { return (type_ == FbsonType::T_Double); }
310 bool isString() const { return (type_ == FbsonType::T_String); }
311 bool isBinary() const { return (type_ == FbsonType::T_Binary); }
312 bool isObject() const { return (type_ == FbsonType::T_Object); }
313 bool isArray() const { return (type_ == FbsonType::T_Array); }
314
315 FbsonType type() const { return type_; }
316
317 // size of the total packed bytes
318 unsigned int numPackedBytes() const;
319
320 // size of the value in bytes
321 unsigned int size() const;
322
323 // get the raw byte array of the value
324 const char* getValuePtr() const;
325
326 // find the FBSON value by a key path string (null terminated)
327 FbsonValue* findPath(const char* key_path,
328 const char* delim = ".",
329 hDictFind handler = nullptr) {
330 return findPath(key_path, (unsigned int)strlen(key_path), delim, handler);
331 }
332
333 // find the FBSON value by a key path string (with length)
334 FbsonValue* findPath(const char* key_path,
335 unsigned int len,
336 const char* delim,
337 hDictFind handler);
338
339 protected:
340 FbsonType type_; // type info
341
342 FbsonValue();
343 };
344
345 /*
346 * NumerValT is the template class (derived from FbsonValue) of all number
347 * types (integers and double).
348 */
349 template <class T>
350 class NumberValT : public FbsonValue {
351 public:
352 T val() const { return num_; }
353
354 unsigned int numPackedBytes() const { return sizeof(FbsonValue) + sizeof(T); }
355
356 // catch all unknow specialization of the template class
357 bool setVal(T /*value*/) { return false; }
358
359 private:
360 T num_;
361
362 NumberValT();
363 };
364
365 typedef NumberValT<int8_t> Int8Val;
366
367 // override setVal for Int8Val
368 template <>
369 inline bool Int8Val::setVal(int8_t value) {
370 if (!isInt8()) {
371 return false;
372 }
373
374 num_ = value;
375 return true;
376 }
377
378 typedef NumberValT<int16_t> Int16Val;
379
380 // override setVal for Int16Val
381 template <>
382 inline bool Int16Val::setVal(int16_t value) {
383 if (!isInt16()) {
384 return false;
385 }
386
387 num_ = value;
388 return true;
389 }
390
391 typedef NumberValT<int32_t> Int32Val;
392
393 // override setVal for Int32Val
394 template <>
395 inline bool Int32Val::setVal(int32_t value) {
396 if (!isInt32()) {
397 return false;
398 }
399
400 num_ = value;
401 return true;
402 }
403
404 typedef NumberValT<int64_t> Int64Val;
405
406 // override setVal for Int64Val
407 template <>
408 inline bool Int64Val::setVal(int64_t value) {
409 if (!isInt64()) {
410 return false;
411 }
412
413 num_ = value;
414 return true;
415 }
416
417 typedef NumberValT<double> DoubleVal;
418
419 // override setVal for DoubleVal
420 template <>
421 inline bool DoubleVal::setVal(double value) {
422 if (!isDouble()) {
423 return false;
424 }
425
426 num_ = value;
427 return true;
428 }
429
430 /*
431 * BlobVal is the base class (derived from FbsonValue) for string and binary
432 * types. The size_ indicates the total bytes of the payload_.
433 */
434 class BlobVal : public FbsonValue {
435 public:
436 // size of the blob payload only
437 unsigned int getBlobLen() const { return size_; }
438
439 // return the blob as byte array
440 const char* getBlob() const { return payload_; }
441
442 // size of the total packed bytes
443 unsigned int numPackedBytes() const {
444 return sizeof(FbsonValue) + sizeof(size_) + size_;
445 }
446
447 protected:
448 uint32_t size_;
449 char payload_[1];
450
451 // set new blob bytes
452 bool internalSetVal(const char* blob, uint32_t blobSize) {
453 // if we cannot fit the new blob, fail the operation
454 if (blobSize > size_) {
455 return false;
456 }
457
458 memcpy(payload_, blob, blobSize);
459
460 // Set the reset of the bytes to 0. Note we cannot change the size_ of the
461 // current payload, as all values are packed.
462 memset(payload_ + blobSize, 0, size_ - blobSize);
463
464 return true;
465 }
466
467 BlobVal();
468
469 private:
470 // Disable as this class can only be allocated dynamically
471 BlobVal(const BlobVal&) = delete;
472 BlobVal& operator=(const BlobVal&) = delete;
473 };
474
475 /*
476 * Binary type
477 */
478 class BinaryVal : public BlobVal {
479 public:
480 bool setVal(const char* blob, uint32_t blobSize) {
481 if (!isBinary()) {
482 return false;
483 }
484
485 return internalSetVal(blob, blobSize);
486 }
487
488 private:
489 BinaryVal();
490 };
491
492 /*
493 * String type
494 * Note: FBSON string may not be a c-string (NULL-terminated)
495 */
496 class StringVal : public BlobVal {
497 public:
498 bool setVal(const char* str, uint32_t blobSize) {
499 if (!isString()) {
500 return false;
501 }
502
503 return internalSetVal(str, blobSize);
504 }
505
506 private:
507 StringVal();
508 };
509
510 /*
511 * ContainerVal is the base class (derived from FbsonValue) for object and
512 * array types. The size_ indicates the total bytes of the payload_.
513 */
514 class ContainerVal : public FbsonValue {
515 public:
516 // size of the container payload only
517 unsigned int getContainerSize() const { return size_; }
518
519 // return the container payload as byte array
520 const char* getPayload() const { return payload_; }
521
522 // size of the total packed bytes
523 unsigned int numPackedBytes() const {
524 return sizeof(FbsonValue) + sizeof(size_) + size_;
525 }
526
527 protected:
528 uint32_t size_;
529 char payload_[1];
530
531 ContainerVal();
532
533 ContainerVal(const ContainerVal&) = delete;
534 ContainerVal& operator=(const ContainerVal&) = delete;
535 };
536
537 /*
538 * Object type
539 */
540 class ObjectVal : public ContainerVal {
541 public:
542 // find the FBSON value by a key string (null terminated)
543 FbsonValue* find(const char* key, hDictFind handler = nullptr) const {
544 if (!key)
545 return nullptr;
546
547 return find(key, (unsigned int)strlen(key), handler);
548 }
549
550 // find the FBSON value by a key string (with length)
551 FbsonValue* find(const char* key,
552 unsigned int klen,
553 hDictFind handler = nullptr) const {
554 if (!key || !klen)
555 return nullptr;
556
557 int key_id = -1;
558 if (handler && (key_id = handler(key, klen)) >= 0) {
559 return find(key_id);
560 }
561
562 return internalFind(key, klen);
563 }
564
565 // find the FBSON value by a key dictionary ID
566 FbsonValue* find(int key_id) const {
567 if (key_id < 0 || key_id > FbsonKeyValue::sMaxKeyId)
568 return nullptr;
569
570 const char* pch = payload_;
571 const char* fence = payload_ + size_;
572
573 while (pch < fence) {
574 FbsonKeyValue* pkey = (FbsonKeyValue*)(pch);
575 if (!pkey->klen() && key_id == pkey->getKeyId()) {
576 return pkey->value();
577 }
578 pch += pkey->numPackedBytes();
579 }
580
581 assert(pch == fence);
582
583 return nullptr;
584 }
585
586 typedef FbsonKeyValue value_type;
587 typedef value_type* pointer;
588 typedef const value_type* const_pointer;
589 typedef FbsonFwdIteratorT<pointer, ObjectVal> iterator;
590 typedef FbsonFwdIteratorT<const_pointer, ObjectVal> const_iterator;
591
592 iterator begin() { return iterator((pointer)payload_); }
593
594 const_iterator begin() const { return const_iterator((pointer)payload_); }
595
596 iterator end() { return iterator((pointer)(payload_ + size_)); }
597
598 const_iterator end() const {
599 return const_iterator((pointer)(payload_ + size_));
600 }
601
602 private:
603 FbsonValue* internalFind(const char* key, unsigned int klen) const {
604 const char* pch = payload_;
605 const char* fence = payload_ + size_;
606
607 while (pch < fence) {
608 FbsonKeyValue* pkey = (FbsonKeyValue*)(pch);
609 if (klen == pkey->klen() && strncmp(key, pkey->getKeyStr(), klen) == 0) {
610 return pkey->value();
611 }
612 pch += pkey->numPackedBytes();
613 }
614
615 assert(pch == fence);
616
617 return nullptr;
618 }
619
620 private:
621 ObjectVal();
622 };
623
624 /*
625 * Array type
626 */
627 class ArrayVal : public ContainerVal {
628 public:
629 // get the FBSON value at index
630 FbsonValue* get(int idx) const {
631 if (idx < 0)
632 return nullptr;
633
634 const char* pch = payload_;
635 const char* fence = payload_ + size_;
636
637 while (pch < fence && idx-- > 0)
638 pch += ((FbsonValue*)pch)->numPackedBytes();
639
640 if (idx == -1)
641 return (FbsonValue*)pch;
642 else {
643 assert(pch == fence);
644 return nullptr;
645 }
646 }
647
648 // Get number of elements in array
649 unsigned int numElem() const {
650 const char* pch = payload_;
651 const char* fence = payload_ + size_;
652
653 unsigned int num = 0;
654 while (pch < fence) {
655 ++num;
656 pch += ((FbsonValue*)pch)->numPackedBytes();
657 }
658
659 assert(pch == fence);
660
661 return num;
662 }
663
664 typedef FbsonValue value_type;
665 typedef value_type* pointer;
666 typedef const value_type* const_pointer;
667 typedef FbsonFwdIteratorT<pointer, ArrayVal> iterator;
668 typedef FbsonFwdIteratorT<const_pointer, ArrayVal> const_iterator;
669
670 iterator begin() { return iterator((pointer)payload_); }
671
672 const_iterator begin() const { return const_iterator((pointer)payload_); }
673
674 iterator end() { return iterator((pointer)(payload_ + size_)); }
675
676 const_iterator end() const {
677 return const_iterator((pointer)(payload_ + size_));
678 }
679
680 private:
681 ArrayVal();
682 };
683
684 inline FbsonDocument* FbsonDocument::createDocument(const char* pb,
685 uint32_t size) {
686 if (!pb || size < sizeof(FbsonHeader) + sizeof(FbsonValue)) {
687 return nullptr;
688 }
689
690 FbsonDocument* doc = (FbsonDocument*)pb;
691 if (doc->header_.ver_ != FBSON_VER) {
692 return nullptr;
693 }
694
695 FbsonValue* val = (FbsonValue*)doc->payload_;
696 if (!val->isObject() || size != sizeof(FbsonHeader) + val->numPackedBytes()) {
697 return nullptr;
698 }
699
700 return doc;
701 }
702
703 inline FbsonValue* FbsonDocument::createValue(const char* pb, uint32_t size) {
704 if (!pb || size < sizeof(FbsonHeader) + sizeof(FbsonValue)) {
705 return nullptr;
706 }
707
708 FbsonDocument* doc = (FbsonDocument*)pb;
709 if (doc->header_.ver_ != FBSON_VER) {
710 return nullptr;
711 }
712
713 FbsonValue* val = (FbsonValue*)doc->payload_;
714 if (size != sizeof(FbsonHeader) + val->numPackedBytes()) {
715 return nullptr;
716 }
717
718 return val;
719 }
720
721 inline unsigned int FbsonKeyValue::numPackedBytes() const {
722 unsigned int ks = keyPackedBytes();
723 FbsonValue* val = (FbsonValue*)(((char*)this) + ks);
724 return ks + val->numPackedBytes();
725 }
726
727 // Poor man's "virtual" function FbsonValue::numPackedBytes
728 inline unsigned int FbsonValue::numPackedBytes() const {
729 switch (type_) {
730 case FbsonType::T_Null:
731 case FbsonType::T_True:
732 case FbsonType::T_False: {
733 return sizeof(type_);
734 }
735
736 case FbsonType::T_Int8: {
737 return sizeof(type_) + sizeof(int8_t);
738 }
739 case FbsonType::T_Int16: {
740 return sizeof(type_) + sizeof(int16_t);
741 }
742 case FbsonType::T_Int32: {
743 return sizeof(type_) + sizeof(int32_t);
744 }
745 case FbsonType::T_Int64: {
746 return sizeof(type_) + sizeof(int64_t);
747 }
748 case FbsonType::T_Double: {
749 return sizeof(type_) + sizeof(double);
750 }
751 case FbsonType::T_String:
752 case FbsonType::T_Binary: {
753 return ((BlobVal*)(this))->numPackedBytes();
754 }
755
756 case FbsonType::T_Object:
757 case FbsonType::T_Array: {
758 return ((ContainerVal*)(this))->numPackedBytes();
759 }
760 default:
761 return 0;
762 }
763 }
764
765 inline unsigned int FbsonValue::size() const {
766 switch (type_) {
767 case FbsonType::T_Int8: {
768 return sizeof(int8_t);
769 }
770 case FbsonType::T_Int16: {
771 return sizeof(int16_t);
772 }
773 case FbsonType::T_Int32: {
774 return sizeof(int32_t);
775 }
776 case FbsonType::T_Int64: {
777 return sizeof(int64_t);
778 }
779 case FbsonType::T_Double: {
780 return sizeof(double);
781 }
782 case FbsonType::T_String:
783 case FbsonType::T_Binary: {
784 return ((BlobVal*)(this))->getBlobLen();
785 }
786
787 case FbsonType::T_Object:
788 case FbsonType::T_Array: {
789 return ((ContainerVal*)(this))->getContainerSize();
790 }
791 case FbsonType::T_Null:
792 case FbsonType::T_True:
793 case FbsonType::T_False:
794 default:
795 return 0;
796 }
797 }
798
799 inline const char* FbsonValue::getValuePtr() const {
800 switch (type_) {
801 case FbsonType::T_Int8:
802 case FbsonType::T_Int16:
803 case FbsonType::T_Int32:
804 case FbsonType::T_Int64:
805 case FbsonType::T_Double:
806 return ((char*)this) + sizeof(FbsonType);
807
808 case FbsonType::T_String:
809 case FbsonType::T_Binary:
810 return ((BlobVal*)(this))->getBlob();
811
812 case FbsonType::T_Object:
813 case FbsonType::T_Array:
814 return ((ContainerVal*)(this))->getPayload();
815
816 case FbsonType::T_Null:
817 case FbsonType::T_True:
818 case FbsonType::T_False:
819 default:
820 return nullptr;
821 }
822 }
823
824 inline FbsonValue* FbsonValue::findPath(const char* key_path,
825 unsigned int kp_len,
826 const char* delim = ".",
827 hDictFind handler = nullptr) {
828 if (!key_path || !kp_len)
829 return nullptr;
830
831 if (!delim)
832 delim = "."; // default delimiter
833
834 FbsonValue* pval = this;
835 const char* fence = key_path + kp_len;
836 char idx_buf[21]; // buffer to parse array index (integer value)
837
838 while (pval && key_path < fence) {
839 const char* key = key_path;
840 unsigned int klen = 0;
841 // find the current key
842 for (; key_path != fence && *key_path != *delim; ++key_path, ++klen)
843 ;
844
845 if (!klen)
846 return nullptr;
847
848 switch (pval->type_) {
849 case FbsonType::T_Object: {
850 pval = ((ObjectVal*)pval)->find(key, klen, handler);
851 break;
852 }
853
854 case FbsonType::T_Array: {
855 // parse string into an integer (array index)
856 if (klen >= sizeof(idx_buf))
857 return nullptr;
858
859 memcpy(idx_buf, key, klen);
860 idx_buf[klen] = 0;
861
862 char* end = nullptr;
863 int index = (int)strtol(idx_buf, &end, 10);
864 if (end && !*end)
865 pval = ((fbson::ArrayVal*)pval)->get(index);
866 else
867 // incorrect index string
868 return nullptr;
869 break;
870 }
871
872 default:
873 return nullptr;
874 }
875
876 // skip the delimiter
877 if (key_path < fence) {
878 ++key_path;
879 if (key_path == fence)
880 // we have a trailing delimiter at the end
881 return nullptr;
882 }
883 }
884
885 return pval;
886 }
887
888 #pragma pack(pop)
889
890 } // namespace fbson