1 // bsonelement.h
2
3
4 /**
5 * Copyright (C) 2018-present MongoDB, Inc.
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the Server Side Public License, version 1,
9 * as published by MongoDB, Inc.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * Server Side Public License for more details.
15 *
16 * You should have received a copy of the Server Side Public License
17 * along with this program. If not, see
18 * <http://www.mongodb.com/licensing/server-side-public-license>.
19 *
20 * As a special exception, the copyright holders give permission to link the
21 * code of portions of this program with the OpenSSL library under certain
22 * conditions as described in each individual source file and distribute
23 * linked combinations including the program with the OpenSSL library. You
24 * must comply with the Server Side Public License in all respects for
25 * all of the code used other than as permitted herein. If you modify file(s)
26 * with this exception, you may extend this exception to your version of the
27 * file(s), but you are not obligated to do so. If you do not wish to do so,
28 * delete this exception statement from your version. If you delete this
29 * exception statement from all source files in the program, then also delete
30 * it in the license file.
31 */
32
33 #pragma once
34
35 #include <cmath>
36 #include <cstdint>
37 #include <string.h> // strlen
38 #include <string>
39 #include <vector>
40
41 #include "mongo/base/data_range.h"
42 #include "mongo/base/data_type_endian.h"
43 #include "mongo/base/data_view.h"
44 #include "mongo/base/string_data_comparator_interface.h"
45 #include "mongo/bson/bson_comparator_interface_base.h"
46 #include "mongo/bson/bsontypes.h"
47 #include "mongo/bson/oid.h"
48 #include "mongo/bson/timestamp.h"
49 #include "mongo/config.h"
50 #include "mongo/platform/decimal128.h"
51 #include "mongo/platform/strnlen.h"
52
53 namespace mongo {
54 class BSONObj;
55 class BSONElement;
56 class BSONObjBuilder;
57 class Timestamp;
58
59 typedef BSONElement be;
60 typedef BSONObj bo;
61 typedef BSONObjBuilder bob;
62
63 /** BSONElement represents an "element" in a BSONObj. So for the object { a : 3, b : "abc" },
64 'a : 3' is the first element (key+value).
65
66 The BSONElement object points into the BSONObj's data. Thus the BSONObj must stay in scope
67 for the life of the BSONElement.
68
69 internals:
70 <type><fieldName ><value>
71 -------- size() ------------
72 -fieldNameSize-
73 value()
74 type()
75 */
76 class BSONElement {
77 public:
78 // Declared in bsonobj_comparator_interface.h.
79 class ComparatorInterface;
80
81 /**
82 * Operator overloads for relops return a DeferredComparison which can subsequently be evaluated
83 * by a BSONObj::ComparatorInterface.
84 */
85 using DeferredComparison = BSONComparatorInterfaceBase<BSONElement>::DeferredComparison;
86
87 /**
88 * Set of rules that dictate the behavior of the comparison APIs.
89 */
90 using ComparisonRules = BSONComparatorInterfaceBase<BSONElement>::ComparisonRules;
91 using ComparisonRulesSet = BSONComparatorInterfaceBase<BSONElement>::ComparisonRulesSet;
92
93 /**
94 * Compares two BSON elements of the same canonical type.
95 *
96 * Returns <0 if 'l' is less than the element 'r'.
97 * >0 if 'l' is greater than the element 'r'.
98 * 0 if 'l' is equal to the element 'r'.
99 */
100 static int compareElements(const BSONElement& l,
101 const BSONElement& r,
102 ComparisonRulesSet rules,
103 const StringData::ComparatorInterface* comparator);
104
105
106 /** These functions, which start with a capital letter, throw if the
107 element is not of the required type. Example:
108
109 std::string foo = obj["foo"].String(); // std::exception if not a std::string type or DNE
110 */
String()111 std::string String() const {
112 return chk(mongo::String).str();
113 }
checkAndGetStringData()114 const StringData checkAndGetStringData() const {
115 return chk(mongo::String).valueStringData();
116 }
Date()117 Date_t Date() const {
118 return chk(mongo::Date).date();
119 }
Number()120 double Number() const {
121 uassert(13118,
122 str::stream() << "expected " << fieldName()
123 << " to have a numeric type, but it is a "
124 << type(),
125 isNumber());
126 return number();
127 }
Decimal()128 Decimal128 Decimal() const {
129 return chk(NumberDecimal)._numberDecimal();
130 }
Double()131 double Double() const {
132 return chk(NumberDouble)._numberDouble();
133 }
Long()134 long long Long() const {
135 return chk(NumberLong)._numberLong();
136 }
Int()137 int Int() const {
138 return chk(NumberInt)._numberInt();
139 }
Bool()140 bool Bool() const {
141 return chk(mongo::Bool).boolean();
142 }
143 std::vector<BSONElement> Array() const; // see implementation for detailed comments
OID()144 mongo::OID OID() const {
145 return chk(jstOID).__oid();
146 }
147
148 /** @return the embedded object associated with this field.
149 Note the returned object is a reference to within the parent bson object. If that
150 object is out of scope, this pointer will no longer be valid. Call getOwned() on the
151 returned BSONObj if you need your own copy.
152 throws AssertionException if the element is not of type object.
153 */
154 BSONObj Obj() const;
155
156 /** populate v with the value of the element. If type does not match, throw exception.
157 useful in templates -- see also BSONObj::Vals().
158 */
Val(Date_t & v)159 void Val(Date_t& v) const {
160 v = Date();
161 }
Val(long long & v)162 void Val(long long& v) const {
163 v = Long();
164 }
Val(Decimal128 & v)165 void Val(Decimal128& v) const {
166 v = Decimal();
167 }
Val(bool & v)168 void Val(bool& v) const {
169 v = Bool();
170 }
171 void Val(BSONObj& v) const;
Val(mongo::OID & v)172 void Val(mongo::OID& v) const {
173 v = OID();
174 }
Val(int & v)175 void Val(int& v) const {
176 v = Int();
177 }
Val(double & v)178 void Val(double& v) const {
179 v = Double();
180 }
Val(std::string & v)181 void Val(std::string& v) const {
182 v = String();
183 }
184
185 /** Use ok() to check if a value is assigned:
186 if( myObj["foo"].ok() ) ...
187 */
ok()188 bool ok() const {
189 return !eoo();
190 }
191
192 /**
193 * True if this element has a value (ie not EOO).
194 *
195 * Makes it easier to check for a field's existence and use it:
196 * if (auto elem = myObj["foo"]) {
197 * // Use elem
198 * }
199 * else {
200 * // default behavior
201 * }
202 */
203 explicit operator bool() const {
204 return ok();
205 }
206
207 std::string toString(bool includeFieldName = true, bool full = false) const;
208 void toString(StringBuilder& s,
209 bool includeFieldName = true,
210 bool full = false,
211 bool redactValues = false,
212 int depth = 0) const;
213 std::string jsonString(JsonStringFormat format,
214 bool includeFieldNames = true,
215 int pretty = 0) const;
string()216 operator std::string() const {
217 return toString();
218 }
219
220 /** Returns the type of the element */
type()221 BSONType type() const {
222 const signed char typeByte = ConstDataView(data).read<signed char>();
223 return static_cast<BSONType>(typeByte);
224 }
225
226 /** retrieve a field within this element
227 throws exception if *this is not an embedded object
228 */
229 BSONElement operator[](StringData field) const;
230
231 /** See canonicalizeBSONType in bsontypes.h */
canonicalType()232 int canonicalType() const {
233 return canonicalizeBSONType(type());
234 }
235
236 /** Indicates if it is the end-of-object element, which is present at the end of
237 every BSON object.
238 */
eoo()239 bool eoo() const {
240 return type() == EOO;
241 }
242
243 /**
244 * Size of the element.
245 */
size()246 int size() const {
247 return totalSize;
248 }
249
250 /** Wrap this element up as a singleton object. */
251 BSONObj wrap() const;
252
253 /** Wrap this element up as a singleton object with a new name. */
254 BSONObj wrap(StringData newName) const;
255
256 /** field name of the element. e.g., for
257 name : "Joe"
258 "name" is the fieldname
259 */
fieldName()260 const char* fieldName() const {
261 if (eoo())
262 return ""; // no fieldname for it.
263 return data + 1;
264 }
265
266 /**
267 * NOTE: size includes the NULL terminator.
268 */
fieldNameSize()269 int fieldNameSize() const {
270 return fieldNameSize_;
271 }
272
fieldNameStringData()273 const StringData fieldNameStringData() const {
274 return StringData(fieldName(), eoo() ? 0 : fieldNameSize() - 1);
275 }
276
277 /** raw data of the element's value (so be careful). */
value()278 const char* value() const {
279 return (data + fieldNameSize() + 1);
280 }
281 /** size in bytes of the element's value (when applicable). */
valuesize()282 int valuesize() const {
283 return size() - fieldNameSize() - 1;
284 }
285
isBoolean()286 bool isBoolean() const {
287 return type() == mongo::Bool;
288 }
289
290 /** @return value of a boolean element.
291 You must assure element is a boolean before
292 calling. */
boolean()293 bool boolean() const {
294 return *value() ? true : false;
295 }
296
booleanSafe()297 bool booleanSafe() const {
298 return isBoolean() && boolean();
299 }
300
301 /** Retrieve a java style date value from the element.
302 Ensure element is of type Date before calling.
303 @see Bool(), trueValue()
304 */
date()305 Date_t date() const {
306 return Date_t::fromMillisSinceEpoch(ConstDataView(value()).read<LittleEndian<long long>>());
307 }
308
309 /** Convert the value to boolean, regardless of its type, in a javascript-like fashion
310 (i.e., treats zero and null and eoo as false).
311 */
312 bool trueValue() const;
313
314 /** True if element is of a numeric type. */
315 bool isNumber() const;
316
317 /** Return double value for this field. MUST be NumberDouble type. */
_numberDouble()318 double _numberDouble() const {
319 return ConstDataView(value()).read<LittleEndian<double>>();
320 }
321
322 /** Return int value for this field. MUST be NumberInt type. */
_numberInt()323 int _numberInt() const {
324 return ConstDataView(value()).read<LittleEndian<int>>();
325 }
326
327 /** Return decimal128 value for this field. MUST be NumberDecimal type. */
_numberDecimal()328 Decimal128 _numberDecimal() const {
329 uint64_t low = ConstDataView(value()).read<LittleEndian<long long>>();
330 uint64_t high = ConstDataView(value() + sizeof(long long)).read<LittleEndian<long long>>();
331 return Decimal128(Decimal128::Value({low, high}));
332 }
333
334 /** Return long long value for this field. MUST be NumberLong type. */
_numberLong()335 long long _numberLong() const {
336 return ConstDataView(value()).read<LittleEndian<long long>>();
337 }
338
339 /** Retrieve int value for the element safely. Zero returned if not a number. */
340 int numberInt() const;
341 /** Retrieve long value for the element safely. Zero returned if not a number.
342 * Behavior is not defined for double values that are NaNs, or too large/small
343 * to be represented by long longs */
344 long long numberLong() const;
345
346 /** Like numberLong() but with well-defined behavior for doubles that
347 * are NaNs, or too large/small to be represented as long longs.
348 * NaNs -> 0
349 * very large doubles -> LLONG_MAX
350 * very small doubles -> LLONG_MIN */
351 long long safeNumberLong() const;
352
353 /** Retrieve decimal value for the element safely. */
354 Decimal128 numberDecimal() const;
355
356 /** Retrieve the numeric value of the element. If not of a numeric type, returns 0.
357 Note: casts to double, data loss may occur with large (>52 bit) NumberLong values.
358 */
359 double numberDouble() const;
360 /** Retrieve the numeric value of the element. If not of a numeric type, returns 0.
361 Note: casts to double, data loss may occur with large (>52 bit) NumberLong values.
362 */
number()363 double number() const {
364 return numberDouble();
365 }
366
367 /** Retrieve the object ID stored in the object.
368 You must ensure the element is of type jstOID first. */
__oid()369 mongo::OID __oid() const {
370 return OID::from(value());
371 }
372
373 /** True if element is null. */
isNull()374 bool isNull() const {
375 return type() == jstNULL;
376 }
377
378 /** Size (length) of a std::string element.
379 You must assure of type std::string first.
380 @return std::string size including terminating null
381 */
valuestrsize()382 int valuestrsize() const {
383 return ConstDataView(value()).read<LittleEndian<int>>();
384 }
385
386 // for objects the size *includes* the size of the size field
objsize()387 size_t objsize() const {
388 return ConstDataView(value()).read<LittleEndian<uint32_t>>();
389 }
390
391 /** Get a string's value. Also gives you start of the real data for an embedded object.
392 You must assure data is of an appropriate type first -- see also valuestrsafe().
393 */
valuestr()394 const char* valuestr() const {
395 return value() + 4;
396 }
397
398 /** Get the std::string value of the element. If not a std::string returns "". */
valuestrsafe()399 const char* valuestrsafe() const {
400 return type() == mongo::String ? valuestr() : "";
401 }
402 /** Get the std::string value of the element. If not a std::string returns "". */
str()403 std::string str() const {
404 return type() == mongo::String ? std::string(valuestr(), valuestrsize() - 1)
405 : std::string();
406 }
407
408 /**
409 * Returns a StringData pointing into this element's data. Does not validate that the
410 * element is actually of type String.
411 */
valueStringData()412 const StringData valueStringData() const {
413 return StringData(valuestr(), valuestrsize() - 1);
414 }
415
416 /** Get javascript code of a CodeWScope data element. */
codeWScopeCode()417 const char* codeWScopeCode() const {
418 massert(16177, "not codeWScope", type() == CodeWScope);
419 return value() + 4 + 4; // two ints precede code (see BSON spec)
420 }
421
422 /** Get length of the code part of the CodeWScope object
423 * This INCLUDES the null char at the end */
codeWScopeCodeLen()424 int codeWScopeCodeLen() const {
425 massert(16178, "not codeWScope", type() == CodeWScope);
426 return ConstDataView(value() + 4).read<LittleEndian<int>>();
427 }
428
429 /** Get the scope SavedContext of a CodeWScope data element.
430 *
431 * This function is DEPRECATED, since it can error if there are
432 * null chars in the codeWScopeCode. However, some existing indexes
433 * may be based on an incorrect ordering derived from this function,
434 * so it may still need to be used in certain cases.
435 * */
codeWScopeScopeDataUnsafe()436 const char* codeWScopeScopeDataUnsafe() const {
437 // This can error if there are null chars in the codeWScopeCode
438 return codeWScopeCode() + strlen(codeWScopeCode()) + 1;
439 }
440
441 /* Get the scope SavedContext of a CodeWScope data element.
442 *
443 * This is the corrected version of codeWScopeScopeDataUnsafe(),
444 * but note that existing uses might rely on the behavior of
445 * that function so be careful in choosing which version to use.
446 */
codeWScopeScopeData()447 const char* codeWScopeScopeData() const {
448 return codeWScopeCode() + codeWScopeCodeLen();
449 }
450
451 /** Get the embedded object this element holds. */
452 BSONObj embeddedObject() const;
453
454 /* uasserts if not an object */
455 BSONObj embeddedObjectUserCheck() const;
456
457 BSONObj codeWScopeObject() const;
458
459 /** Get raw binary data. Element must be of type BinData. Doesn't handle type 2 specially */
binData(int & len)460 const char* binData(int& len) const {
461 // BinData: <int len> <byte subtype> <byte[len] data>
462 verify(type() == BinData);
463 len = valuestrsize();
464 return value() + 5;
465 }
466 /** Get binary data. Element must be of type BinData. Handles type 2 */
binDataClean(int & len)467 const char* binDataClean(int& len) const {
468 // BinData: <int len> <byte subtype> <byte[len] data>
469 if (binDataType() != ByteArrayDeprecated) {
470 return binData(len);
471 } else {
472 // Skip extra size
473 len = valuestrsize() - 4;
474 return value() + 5 + 4;
475 }
476 }
477
binDataType()478 BinDataType binDataType() const {
479 // BinData: <int len> <byte subtype> <byte[len] data>
480 verify(type() == BinData);
481 unsigned char c = (value() + 4)[0];
482 return (BinDataType)c;
483 }
484
_binDataVector()485 std::vector<uint8_t> _binDataVector() const {
486 if (binDataType() != ByteArrayDeprecated) {
487 return std::vector<uint8_t>(reinterpret_cast<const uint8_t*>(value()) + 5,
488 reinterpret_cast<const uint8_t*>(value()) + 5 +
489 valuestrsize());
490 } else {
491 // Skip the extra int32 size
492 return std::vector<uint8_t>(reinterpret_cast<const uint8_t*>(value()) + 4,
493 reinterpret_cast<const uint8_t*>(value()) + 4 +
494 valuestrsize() - 4);
495 }
496 }
497
498 /** Retrieve the regex std::string for a Regex element */
regex()499 const char* regex() const {
500 verify(type() == RegEx);
501 return value();
502 }
503
504 /** Retrieve the regex flags (options) for a Regex element */
regexFlags()505 const char* regexFlags() const {
506 const char* p = regex();
507 return p + strlen(p) + 1;
508 }
509
510 //
511 // Comparison API.
512 //
513 // BSONElement instances can be compared via a raw bytewise comparison or a logical comparison.
514 //
515 // Logical comparison can be done either using woCompare() or with operator overloads. Most
516 // callers should prefer operator overloads. Note that the operator overloads return a
517 // DeferredComparison, which must subsequently be evaluated by a
518 // BSONElement::ComparatorInterface. See bsonelement_comparator_interface.h for details.
519 //
520
521 /**
522 * Compares the raw bytes of the two BSONElements, including the field names. This will treat
523 * different types (e.g. integers and doubles) as distinct values, even if they have the same
524 * field name and bit pattern in the value portion of the BSON element.
525 */
526 bool binaryEqual(const BSONElement& rhs) const;
527
528 /**
529 * Compares the raw bytes of the two BSONElements, excluding the field names. This will treat
530 * different types (e.g integers and doubles) as distinct values, even if they have the same bit
531 * pattern in the value portion of the BSON element.
532 */
533 bool binaryEqualValues(const BSONElement& rhs) const;
534
535 /**
536 * Compares two BSON Elements using the rules specified by 'rules' and the 'comparator' for
537 * string comparisons.
538 *
539 * Returns <0 if 'this' is less than 'elem'.
540 * >0 if 'this' is greater than 'elem'.
541 * 0 if 'this' is equal to 'elem'.
542 */
543 int woCompare(const BSONElement& elem,
544 ComparisonRulesSet rules = ComparisonRules::kConsiderFieldName,
545 const StringData::ComparatorInterface* comparator = nullptr) const;
546
547 DeferredComparison operator<(const BSONElement& other) const {
548 return DeferredComparison(DeferredComparison::Type::kLT, *this, other);
549 }
550
551 DeferredComparison operator<=(const BSONElement& other) const {
552 return DeferredComparison(DeferredComparison::Type::kLTE, *this, other);
553 }
554
555 DeferredComparison operator>(const BSONElement& other) const {
556 return DeferredComparison(DeferredComparison::Type::kGT, *this, other);
557 }
558
559 DeferredComparison operator>=(const BSONElement& other) const {
560 return DeferredComparison(DeferredComparison::Type::kGTE, *this, other);
561 }
562
563 DeferredComparison operator==(const BSONElement& other) const {
564 return DeferredComparison(DeferredComparison::Type::kEQ, *this, other);
565 }
566
567 DeferredComparison operator!=(const BSONElement& other) const {
568 return DeferredComparison(DeferredComparison::Type::kNE, *this, other);
569 }
570
rawdata()571 const char* rawdata() const {
572 return data;
573 }
574
575 /** Constructs an empty element */
576 BSONElement();
577
578 /** True if this element may contain subobjects. */
mayEncapsulate()579 bool mayEncapsulate() const {
580 switch (type()) {
581 case Object:
582 case mongo::Array:
583 case CodeWScope:
584 return true;
585 default:
586 return false;
587 }
588 }
589
590 /** True if this element can be a BSONObj */
isABSONObj()591 bool isABSONObj() const {
592 switch (type()) {
593 case Object:
594 case mongo::Array:
595 return true;
596 default:
597 return false;
598 }
599 }
600
timestamp()601 Timestamp timestamp() const {
602 if (type() == mongo::Date || type() == bsonTimestamp) {
603 return Timestamp(ConstDataView(value()).read<LittleEndian<unsigned long long>>().value);
604 }
605 return Timestamp();
606 }
607
isBinData(BinDataType bdt)608 bool isBinData(BinDataType bdt) const {
609 return (type() == BinData) && (binDataType() == bdt);
610 }
611
uuid()612 const std::array<unsigned char, 16> uuid() const {
613 int len = 0;
614 const char* data = nullptr;
615 if (isBinData(BinDataType::newUUID)) {
616 data = binData(len);
617 }
618 uassert(ErrorCodes::InvalidUUID,
619 "uuid must be a 16-byte binary field with UUID (4) subtype",
620 len == 16);
621 std::array<unsigned char, 16> result;
622 memcpy(&result, data, len);
623 return result;
624 }
625
md5()626 const std::array<unsigned char, 16> md5() const {
627 int len = 0;
628 const char* data = nullptr;
629 if (isBinData(BinDataType::MD5Type)) {
630 data = binData(len);
631 }
632 uassert(40437, "md5 must be a 16-byte binary field with MD5 (5) subtype", len == 16);
633 std::array<unsigned char, 16> result;
634 memcpy(&result, data, len);
635 return result;
636 }
637
638
timestampTime()639 Date_t timestampTime() const {
640 unsigned long long t = ConstDataView(value() + 4).read<LittleEndian<unsigned int>>();
641 return Date_t::fromMillisSinceEpoch(t * 1000);
642 }
timestampInc()643 unsigned int timestampInc() const {
644 return ConstDataView(value()).read<LittleEndian<unsigned int>>();
645 }
646
timestampValue()647 unsigned long long timestampValue() const {
648 return ConstDataView(value()).read<LittleEndian<unsigned long long>>();
649 }
650
dbrefNS()651 const char* dbrefNS() const {
652 uassert(10063, "not a dbref", type() == DBRef);
653 return value() + 4;
654 }
655
dbrefOID()656 const mongo::OID dbrefOID() const {
657 uassert(10064, "not a dbref", type() == DBRef);
658 const char* start = value();
659 start += 4 + ConstDataView(start).read<LittleEndian<int>>();
660 return mongo::OID::from(start);
661 }
662
663 // @param maxLen don't scan more than maxLen bytes
BSONElement(const char * d)664 explicit BSONElement(const char* d) : data(d) {
665 if (eoo()) {
666 fieldNameSize_ = 0;
667 totalSize = 1;
668 } else {
669 fieldNameSize_ = strlen(d + 1 /*skip type*/) + 1 /*include NUL byte*/;
670 totalSize = computeSize();
671 }
672 }
673
674 struct CachedSizeTag {}; // Opts in to next constructor.
675
676 /**
677 * Construct a BSONElement where you already know the length of the name and/or the total size
678 * of the element. fieldNameSize includes the null terminator. You may pass -1 for either or
679 * both sizes to indicate that they are unknown and should be computed.
680 */
BSONElement(const char * d,int fieldNameSize,int totalSize,CachedSizeTag)681 BSONElement(const char* d, int fieldNameSize, int totalSize, CachedSizeTag) : data(d) {
682 if (eoo()) {
683 fieldNameSize_ = 0;
684 this->totalSize = 1;
685 } else {
686 if (fieldNameSize == -1) {
687 fieldNameSize_ = strlen(d + 1 /*skip type*/) + 1 /*include NUL byte*/;
688 } else {
689 fieldNameSize_ = fieldNameSize;
690 }
691 if (totalSize == -1) {
692 this->totalSize = computeSize();
693 } else {
694 this->totalSize = totalSize;
695 }
696 }
697 }
698
699 std::string _asCode() const;
700
701 template <typename T>
702 bool coerce(T* out) const;
703
704 private:
705 const char* data;
706 int fieldNameSize_; // internal size includes null terminator
707 int totalSize;
708
709 friend class BSONObjIterator;
710 friend class BSONObjStlIterator;
711 friend class BSONObj;
chk(BSONType t)712 const BSONElement& chk(BSONType t) const {
713 if (t != type()) {
714 StringBuilder ss;
715 if (eoo())
716 ss << "field not found, expected type " << t;
717 else
718 ss << "wrong type for field (" << fieldName() << ") " << type() << " != " << t;
719 uasserted(13111, ss.str());
720 }
721 return *this;
722 }
723
724 // Only called from constructors.
725 int computeSize() const;
726 };
727
trueValue()728 inline bool BSONElement::trueValue() const {
729 // NOTE Behavior changes must be replicated in Value::coerceToBool().
730 switch (type()) {
731 case NumberLong:
732 return _numberLong() != 0;
733 case NumberDouble:
734 return _numberDouble() != 0;
735 case NumberDecimal:
736 return _numberDecimal().isNotEqual(Decimal128(0));
737 case NumberInt:
738 return _numberInt() != 0;
739 case mongo::Bool:
740 return boolean();
741 case EOO:
742 case jstNULL:
743 case Undefined:
744 return false;
745 default:
746 return true;
747 }
748 }
749
750 /** @return true if element is of a numeric type. */
isNumber()751 inline bool BSONElement::isNumber() const {
752 switch (type()) {
753 case NumberLong:
754 case NumberDouble:
755 case NumberDecimal:
756 case NumberInt:
757 return true;
758 default:
759 return false;
760 }
761 }
762
numberDecimal()763 inline Decimal128 BSONElement::numberDecimal() const {
764 switch (type()) {
765 case NumberDouble:
766 return Decimal128(_numberDouble());
767 case NumberInt:
768 return Decimal128(_numberInt());
769 case NumberLong:
770 return Decimal128(static_cast<int64_t>(_numberLong()));
771 case NumberDecimal:
772 return _numberDecimal();
773 default:
774 return Decimal128::kNormalizedZero;
775 }
776 }
777
numberDouble()778 inline double BSONElement::numberDouble() const {
779 switch (type()) {
780 case NumberDouble:
781 return _numberDouble();
782 case NumberInt:
783 return _numberInt();
784 case NumberLong:
785 return _numberLong();
786 case NumberDecimal:
787 return _numberDecimal().toDouble();
788 default:
789 return 0;
790 }
791 }
792
793 /** Retrieve int value for the element safely. Zero returned if not a number. Converted to int if
794 * another numeric type. */
numberInt()795 inline int BSONElement::numberInt() const {
796 switch (type()) {
797 case NumberDouble:
798 return (int)_numberDouble();
799 case NumberInt:
800 return _numberInt();
801 case NumberLong:
802 return (int)_numberLong();
803 case NumberDecimal:
804 return _numberDecimal().toInt();
805 default:
806 return 0;
807 }
808 }
809
810 /** Retrieve long value for the element safely. Zero returned if not a number. */
numberLong()811 inline long long BSONElement::numberLong() const {
812 switch (type()) {
813 case NumberDouble:
814 return (long long)_numberDouble();
815 case NumberInt:
816 return _numberInt();
817 case NumberLong:
818 return _numberLong();
819 case NumberDecimal:
820 return _numberDecimal().toLong();
821 default:
822 return 0;
823 }
824 }
825
826 /** Like numberLong() but with well-defined behavior for doubles and decimals that
827 * are NaNs, or too large/small to be represented as long longs.
828 * NaNs -> 0
829 * very large values -> LLONG_MAX
830 * very small values -> LLONG_MIN */
safeNumberLong()831 inline long long BSONElement::safeNumberLong() const {
832 switch (type()) {
833 case NumberDouble: {
834 double d = numberDouble();
835 if (std::isnan(d)) {
836 return 0;
837 }
838 if (d > (double)std::numeric_limits<long long>::max()) {
839 return std::numeric_limits<long long>::max();
840 }
841 if (d < std::numeric_limits<long long>::min()) {
842 return std::numeric_limits<long long>::min();
843 }
844 return numberLong();
845 }
846 case NumberDecimal: {
847 Decimal128 d = numberDecimal();
848 if (d.isNaN()) {
849 return 0;
850 }
851 if (d.isGreater(Decimal128(std::numeric_limits<int64_t>::max()))) {
852 return static_cast<long long>(std::numeric_limits<int64_t>::max());
853 }
854 if (d.isLess(Decimal128(std::numeric_limits<int64_t>::min()))) {
855 return static_cast<long long>(std::numeric_limits<int64_t>::min());
856 }
857 return numberLong();
858 }
859 default:
860 return numberLong();
861 }
862 }
863
BSONElement()864 inline BSONElement::BSONElement() {
865 // This needs to be 2 elements because we check the strlen of data + 1 and GCC sees that as
866 // accessing beyond the end of a constant string, even though we always check whether the
867 // element is an eoo.
868 static const char kEooElement[2] = {'\0', '\0'};
869 data = kEooElement;
870 fieldNameSize_ = 0;
871 totalSize = 1;
872 }
873 }
874