summaryrefslogtreecommitdiff
path: root/src/mongo/bson/bsonelement.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/bson/bsonelement.h')
-rw-r--r--src/mongo/bson/bsonelement.h1055
1 files changed, 557 insertions, 498 deletions
diff --git a/src/mongo/bson/bsonelement.h b/src/mongo/bson/bsonelement.h
index 25d9e895b49..9ee5513ddf9 100644
--- a/src/mongo/bson/bsonelement.h
+++ b/src/mongo/bson/bsonelement.h
@@ -30,7 +30,7 @@
#pragma once
#include <cmath>
-#include <string.h> // strlen
+#include <string.h> // strlen
#include <string>
#include <vector>
@@ -42,530 +42,590 @@
#include "mongo/platform/cstdint.h"
namespace mongo {
- class BSONObj;
- class BSONElement;
- class BSONObjBuilder;
- class Timestamp;
+class BSONObj;
+class BSONElement;
+class BSONObjBuilder;
+class Timestamp;
+
+typedef BSONElement be;
+typedef BSONObj bo;
+typedef BSONObjBuilder bob;
+
+/* l and r MUST have same type when called: check that first. */
+int compareElementValues(const BSONElement& l, const BSONElement& r);
+
+
+/** BSONElement represents an "element" in a BSONObj. So for the object { a : 3, b : "abc" },
+ 'a : 3' is the first element (key+value).
+
+ The BSONElement object points into the BSONObj's data. Thus the BSONObj must stay in scope
+ for the life of the BSONElement.
+
+ internals:
+ <type><fieldName ><value>
+ -------- size() ------------
+ -fieldNameSize-
+ value()
+ type()
+*/
+class BSONElement {
+public:
+ /** These functions, which start with a capital letter, throw a MsgAssertionException if the
+ element is not of the required type. Example:
+
+ std::string foo = obj["foo"].String(); // std::exception if not a std::string type or DNE
+ */
+ std::string String() const {
+ return chk(mongo::String).str();
+ }
+ const StringData checkAndGetStringData() const {
+ return chk(mongo::String).valueStringData();
+ }
+ Date_t Date() const {
+ return chk(mongo::Date).date();
+ }
+ double Number() const {
+ return chk(isNumber()).number();
+ }
+ double Double() const {
+ return chk(NumberDouble)._numberDouble();
+ }
+ long long Long() const {
+ return chk(NumberLong)._numberLong();
+ }
+ int Int() const {
+ return chk(NumberInt)._numberInt();
+ }
+ bool Bool() const {
+ return chk(mongo::Bool).boolean();
+ }
+ std::vector<BSONElement> Array() const; // see implementation for detailed comments
+ mongo::OID OID() const {
+ return chk(jstOID).__oid();
+ }
+ void Null() const {
+ chk(isNull());
+ } // throw MsgAssertionException if not null
+ void OK() const {
+ chk(ok());
+ } // throw MsgAssertionException if element DNE
+
+ /** @return the embedded object associated with this field.
+ Note the returned object is a reference to within the parent bson object. If that
+ object is out of scope, this pointer will no longer be valid. Call getOwned() on the
+ returned BSONObj if you need your own copy.
+ throws UserException if the element is not of type object.
+ */
+ BSONObj Obj() const;
- typedef BSONElement be;
- typedef BSONObj bo;
- typedef BSONObjBuilder bob;
+ /** populate v with the value of the element. If type does not match, throw exception.
+ useful in templates -- see also BSONObj::Vals().
+ */
+ void Val(Date_t& v) const {
+ v = Date();
+ }
+ void Val(long long& v) const {
+ v = Long();
+ }
+ void Val(bool& v) const {
+ v = Bool();
+ }
+ void Val(BSONObj& v) const;
+ void Val(mongo::OID& v) const {
+ v = OID();
+ }
+ void Val(int& v) const {
+ v = Int();
+ }
+ void Val(double& v) const {
+ v = Double();
+ }
+ void Val(std::string& v) const {
+ v = String();
+ }
- /* l and r MUST have same type when called: check that first. */
- int compareElementValues(const BSONElement& l, const BSONElement& r);
+ /** Use ok() to check if a value is assigned:
+ if( myObj["foo"].ok() ) ...
+ */
+ bool ok() const {
+ return !eoo();
+ }
+ /**
+ * True if this element has a value (ie not EOO).
+ *
+ * Makes it easier to check for a field's existence and use it:
+ * if (auto elem = myObj["foo"]) {
+ * // Use elem
+ * }
+ * else {
+ * // default behavior
+ * }
+ */
+ explicit operator bool() const {
+ return ok();
+ }
- /** BSONElement represents an "element" in a BSONObj. So for the object { a : 3, b : "abc" },
- 'a : 3' is the first element (key+value).
+ std::string toString(bool includeFieldName = true, bool full = false) const;
+ void toString(StringBuilder& s,
+ bool includeFieldName = true,
+ bool full = false,
+ int depth = 0) const;
+ std::string jsonString(JsonStringFormat format,
+ bool includeFieldNames = true,
+ int pretty = 0) const;
+ operator std::string() const {
+ return toString();
+ }
- The BSONElement object points into the BSONObj's data. Thus the BSONObj must stay in scope
- for the life of the BSONElement.
+ /** Returns the type of the element */
+ BSONType type() const {
+ const signed char typeByte = ConstDataView(data).read<signed char>();
+ return static_cast<BSONType>(typeByte);
+ }
- internals:
- <type><fieldName ><value>
- -------- size() ------------
- -fieldNameSize-
- value()
- type()
+ /** retrieve a field within this element
+ throws exception if *this is not an embedded object
*/
- class BSONElement {
- public:
- /** These functions, which start with a capital letter, throw a MsgAssertionException if the
- element is not of the required type. Example:
-
- std::string foo = obj["foo"].String(); // std::exception if not a std::string type or DNE
- */
- std::string String() const { return chk(mongo::String).str(); }
- const StringData checkAndGetStringData() const {
- return chk(mongo::String).valueStringData();
- }
- Date_t Date() const { return chk(mongo::Date).date(); }
- double Number() const { return chk(isNumber()).number(); }
- double Double() const { return chk(NumberDouble)._numberDouble(); }
- long long Long() const { return chk(NumberLong)._numberLong(); }
- int Int() const { return chk(NumberInt)._numberInt(); }
- bool Bool() const { return chk(mongo::Bool).boolean(); }
- std::vector<BSONElement> Array() const; // see implementation for detailed comments
- mongo::OID OID() const { return chk(jstOID).__oid(); }
- void Null() const { chk(isNull()); } // throw MsgAssertionException if not null
- void OK() const { chk(ok()); } // throw MsgAssertionException if element DNE
-
- /** @return the embedded object associated with this field.
- Note the returned object is a reference to within the parent bson object. If that
- object is out of scope, this pointer will no longer be valid. Call getOwned() on the
- returned BSONObj if you need your own copy.
- throws UserException if the element is not of type object.
- */
- BSONObj Obj() const;
-
- /** populate v with the value of the element. If type does not match, throw exception.
- useful in templates -- see also BSONObj::Vals().
- */
- void Val(Date_t& v) const { v = Date(); }
- void Val(long long& v) const { v = Long(); }
- void Val(bool& v) const { v = Bool(); }
- void Val(BSONObj& v) const;
- void Val(mongo::OID& v) const { v = OID(); }
- void Val(int& v) const { v = Int(); }
- void Val(double& v) const { v = Double(); }
- void Val(std::string& v) const { v = String(); }
-
- /** Use ok() to check if a value is assigned:
- if( myObj["foo"].ok() ) ...
- */
- bool ok() const { return !eoo(); }
-
- /**
- * True if this element has a value (ie not EOO).
- *
- * Makes it easier to check for a field's existence and use it:
- * if (auto elem = myObj["foo"]) {
- * // Use elem
- * }
- * else {
- * // default behavior
- * }
- */
- explicit operator bool() const { return ok(); }
-
- std::string toString( bool includeFieldName = true, bool full=false) const;
- void toString(StringBuilder& s, bool includeFieldName = true, bool full=false, int depth=0) const;
- std::string jsonString( JsonStringFormat format, bool includeFieldNames = true, int pretty = 0 ) const;
- operator std::string() const { return toString(); }
-
- /** Returns the type of the element */
- BSONType type() const {
- const signed char typeByte = ConstDataView(data).read<signed char>();
- return static_cast<BSONType>(typeByte);
- }
+ BSONElement operator[](const std::string& field) const;
- /** retrieve a field within this element
- throws exception if *this is not an embedded object
- */
- BSONElement operator[] (const std::string& field) const;
-
- /** See canonicalizeBSONType in bsontypes.h */
- int canonicalType() const { return canonicalizeBSONType(type()); }
-
- /** Indicates if it is the end-of-object element, which is present at the end of
- every BSON object.
- */
- bool eoo() const { return type() == EOO; }
-
- /** Size of the element.
- @param maxLen If maxLen is specified, don't scan more than maxLen bytes to calculate size.
- */
- int size( int maxLen ) const;
- int size() const;
-
- /** Wrap this element up as a singleton object. */
- BSONObj wrap() const;
-
- /** Wrap this element up as a singleton object with a new name. */
- BSONObj wrap( StringData newName) const;
-
- /** field name of the element. e.g., for
- name : "Joe"
- "name" is the fieldname
- */
- const char * fieldName() const {
- if ( eoo() ) return ""; // no fieldname for it.
- return data + 1;
- }
+ /** See canonicalizeBSONType in bsontypes.h */
+ int canonicalType() const {
+ return canonicalizeBSONType(type());
+ }
- /**
- * NOTE: size includes the NULL terminator.
- */
- int fieldNameSize() const {
- if ( fieldNameSize_ == -1 )
- fieldNameSize_ = (int)strlen( fieldName() ) + 1;
- return fieldNameSize_;
- }
+ /** Indicates if it is the end-of-object element, which is present at the end of
+ every BSON object.
+ */
+ bool eoo() const {
+ return type() == EOO;
+ }
- const StringData fieldNameStringData() const {
- return StringData(fieldName(), eoo() ? 0 : fieldNameSize() - 1);
- }
+ /** Size of the element.
+ @param maxLen If maxLen is specified, don't scan more than maxLen bytes to calculate size.
+ */
+ int size(int maxLen) const;
+ int size() const;
- /** raw data of the element's value (so be careful). */
- const char * value() const {
- return (data + fieldNameSize() + 1);
- }
- /** size in bytes of the element's value (when applicable). */
- int valuesize() const {
- return size() - fieldNameSize() - 1;
- }
+ /** Wrap this element up as a singleton object. */
+ BSONObj wrap() const;
- bool isBoolean() const { return type() == mongo::Bool; }
+ /** Wrap this element up as a singleton object with a new name. */
+ BSONObj wrap(StringData newName) const;
- /** @return value of a boolean element.
- You must assure element is a boolean before
- calling. */
- bool boolean() const {
- return *value() ? true : false;
- }
+ /** field name of the element. e.g., for
+ name : "Joe"
+ "name" is the fieldname
+ */
+ const char* fieldName() const {
+ if (eoo())
+ return ""; // no fieldname for it.
+ return data + 1;
+ }
- bool booleanSafe() const { return isBoolean() && boolean(); }
+ /**
+ * NOTE: size includes the NULL terminator.
+ */
+ int fieldNameSize() const {
+ if (fieldNameSize_ == -1)
+ fieldNameSize_ = (int)strlen(fieldName()) + 1;
+ return fieldNameSize_;
+ }
- /** Retrieve a java style date value from the element.
- Ensure element is of type Date before calling.
- @see Bool(), trueValue()
- */
- Date_t date() const {
- return Date_t::fromMillisSinceEpoch(
- ConstDataView(value()).read<LittleEndian<long long>>());
- }
+ const StringData fieldNameStringData() const {
+ return StringData(fieldName(), eoo() ? 0 : fieldNameSize() - 1);
+ }
- /** Convert the value to boolean, regardless of its type, in a javascript-like fashion
- (i.e., treats zero and null and eoo as false).
- */
- bool trueValue() const;
+ /** raw data of the element's value (so be careful). */
+ const char* value() const {
+ return (data + fieldNameSize() + 1);
+ }
+ /** size in bytes of the element's value (when applicable). */
+ int valuesize() const {
+ return size() - fieldNameSize() - 1;
+ }
- /** True if number, string, bool, date, OID */
- bool isSimpleType() const;
+ bool isBoolean() const {
+ return type() == mongo::Bool;
+ }
- /** True if element is of a numeric type. */
- bool isNumber() const;
+ /** @return value of a boolean element.
+ You must assure element is a boolean before
+ calling. */
+ bool boolean() const {
+ return *value() ? true : false;
+ }
- /** Return double value for this field. MUST be NumberDouble type. */
- double _numberDouble() const {
- return ConstDataView(value()).read<LittleEndian<double>>();
- }
+ bool booleanSafe() const {
+ return isBoolean() && boolean();
+ }
- /** Return int value for this field. MUST be NumberInt type. */
- int _numberInt() const {
- return ConstDataView(value()).read<LittleEndian<int>>();
- }
+ /** Retrieve a java style date value from the element.
+ Ensure element is of type Date before calling.
+ @see Bool(), trueValue()
+ */
+ Date_t date() const {
+ return Date_t::fromMillisSinceEpoch(ConstDataView(value()).read<LittleEndian<long long>>());
+ }
- /** Return long long value for this field. MUST be NumberLong type. */
- long long _numberLong() const {
- return ConstDataView(value()).read<LittleEndian<long long>>();
- }
+ /** Convert the value to boolean, regardless of its type, in a javascript-like fashion
+ (i.e., treats zero and null and eoo as false).
+ */
+ bool trueValue() const;
- /** Retrieve int value for the element safely. Zero returned if not a number. */
- int numberInt() const;
- /** Retrieve long value for the element safely. Zero returned if not a number.
- * Behavior is not defined for double values that are NaNs, or too large/small
- * to be represented by long longs */
- long long numberLong() const;
-
- /** Like numberLong() but with well-defined behavior for doubles that
- * are NaNs, or too large/small to be represented as long longs.
- * NaNs -> 0
- * very large doubles -> LLONG_MAX
- * very small doubles -> LLONG_MIN */
- long long safeNumberLong() const;
-
- /** Retrieve the numeric value of the element. If not of a numeric type, returns 0.
- Note: casts to double, data loss may occur with large (>52 bit) NumberLong values.
- */
- double numberDouble() const;
- /** Retrieve the numeric value of the element. If not of a numeric type, returns 0.
- Note: casts to double, data loss may occur with large (>52 bit) NumberLong values.
- */
- double number() const { return numberDouble(); }
-
- /** Retrieve the object ID stored in the object.
- You must ensure the element is of type jstOID first. */
- mongo::OID __oid() const {
- return OID::from(value());
- }
+ /** True if number, string, bool, date, OID */
+ bool isSimpleType() const;
- /** True if element is null. */
- bool isNull() const {
- return type() == jstNULL;
- }
+ /** True if element is of a numeric type. */
+ bool isNumber() const;
- /** Size (length) of a std::string element.
- You must assure of type std::string first.
- @return std::string size including terminating null
- */
- int valuestrsize() const {
- return ConstDataView(value()).read<LittleEndian<int>>();
- }
+ /** Return double value for this field. MUST be NumberDouble type. */
+ double _numberDouble() const {
+ return ConstDataView(value()).read<LittleEndian<double>>();
+ }
- // for objects the size *includes* the size of the size field
- size_t objsize() const {
- return ConstDataView(value()).read<LittleEndian<uint32_t>>();
- }
+ /** Return int value for this field. MUST be NumberInt type. */
+ int _numberInt() const {
+ return ConstDataView(value()).read<LittleEndian<int>>();
+ }
- /** Get a string's value. Also gives you start of the real data for an embedded object.
- You must assure data is of an appropriate type first -- see also valuestrsafe().
- */
- const char * valuestr() const {
- return value() + 4;
- }
+ /** Return long long value for this field. MUST be NumberLong type. */
+ long long _numberLong() const {
+ return ConstDataView(value()).read<LittleEndian<long long>>();
+ }
- /** Get the std::string value of the element. If not a std::string returns "". */
- const char *valuestrsafe() const {
- return type() == mongo::String ? valuestr() : "";
- }
- /** Get the std::string value of the element. If not a std::string returns "". */
- std::string str() const {
- return type() == mongo::String ? std::string(valuestr(), valuestrsize()-1) : std::string();
- }
+ /** Retrieve int value for the element safely. Zero returned if not a number. */
+ int numberInt() const;
+ /** Retrieve long value for the element safely. Zero returned if not a number.
+ * Behavior is not defined for double values that are NaNs, or too large/small
+ * to be represented by long longs */
+ long long numberLong() const;
- /**
- * Returns a StringData pointing into this element's data. Does not validate that the
- * element is actually of type String.
- */
- const StringData valueStringData() const {
- return StringData(valuestr(), valuestrsize() - 1);
- }
+ /** Like numberLong() but with well-defined behavior for doubles that
+ * are NaNs, or too large/small to be represented as long longs.
+ * NaNs -> 0
+ * very large doubles -> LLONG_MAX
+ * very small doubles -> LLONG_MIN */
+ long long safeNumberLong() const;
- /** Get javascript code of a CodeWScope data element. */
- const char * codeWScopeCode() const {
- massert( 16177 , "not codeWScope" , type() == CodeWScope );
- return value() + 4 + 4; //two ints precede code (see BSON spec)
- }
+ /** Retrieve the numeric value of the element. If not of a numeric type, returns 0.
+ Note: casts to double, data loss may occur with large (>52 bit) NumberLong values.
+ */
+ double numberDouble() const;
+ /** Retrieve the numeric value of the element. If not of a numeric type, returns 0.
+ Note: casts to double, data loss may occur with large (>52 bit) NumberLong values.
+ */
+ double number() const {
+ return numberDouble();
+ }
- /** Get length of the code part of the CodeWScope object
- * This INCLUDES the null char at the end */
- int codeWScopeCodeLen() const {
- massert( 16178 , "not codeWScope" , type() == CodeWScope );
- return ConstDataView(value() + 4).read<LittleEndian<int>>();
- }
+ /** Retrieve the object ID stored in the object.
+ You must ensure the element is of type jstOID first. */
+ mongo::OID __oid() const {
+ return OID::from(value());
+ }
- /** Get the scope SavedContext of a CodeWScope data element.
- *
- * This function is DEPRECATED, since it can error if there are
- * null chars in the codeWScopeCode. However, some existing indexes
- * may be based on an incorrect ordering derived from this function,
- * so it may still need to be used in certain cases.
- * */
- const char * codeWScopeScopeDataUnsafe() const {
- //This can error if there are null chars in the codeWScopeCode
- return codeWScopeCode() + strlen( codeWScopeCode() ) + 1;
- }
+ /** True if element is null. */
+ bool isNull() const {
+ return type() == jstNULL;
+ }
- /* Get the scope SavedContext of a CodeWScope data element.
- *
- * This is the corrected version of codeWScopeScopeDataUnsafe(),
- * but note that existing uses might rely on the behavior of
- * that function so be careful in choosing which version to use.
- */
- const char * codeWScopeScopeData() const {
- return codeWScopeCode() + codeWScopeCodeLen();
- }
+ /** Size (length) of a std::string element.
+ You must assure of type std::string first.
+ @return std::string size including terminating null
+ */
+ int valuestrsize() const {
+ return ConstDataView(value()).read<LittleEndian<int>>();
+ }
- /** Get the embedded object this element holds. */
- BSONObj embeddedObject() const;
+ // for objects the size *includes* the size of the size field
+ size_t objsize() const {
+ return ConstDataView(value()).read<LittleEndian<uint32_t>>();
+ }
- /* uasserts if not an object */
- BSONObj embeddedObjectUserCheck() const;
+ /** Get a string's value. Also gives you start of the real data for an embedded object.
+ You must assure data is of an appropriate type first -- see also valuestrsafe().
+ */
+ const char* valuestr() const {
+ return value() + 4;
+ }
- BSONObj codeWScopeObject() const;
+ /** Get the std::string value of the element. If not a std::string returns "". */
+ const char* valuestrsafe() const {
+ return type() == mongo::String ? valuestr() : "";
+ }
+ /** Get the std::string value of the element. If not a std::string returns "". */
+ std::string str() const {
+ return type() == mongo::String ? std::string(valuestr(), valuestrsize() - 1)
+ : std::string();
+ }
- /** Get raw binary data. Element must be of type BinData. Doesn't handle type 2 specially */
- const char *binData(int& len) const {
- // BinData: <int len> <byte subtype> <byte[len] data>
- verify( type() == BinData );
- len = valuestrsize();
- return value() + 5;
- }
- /** Get binary data. Element must be of type BinData. Handles type 2 */
- const char *binDataClean(int& len) const {
- // BinData: <int len> <byte subtype> <byte[len] data>
- if (binDataType() != ByteArrayDeprecated) {
- return binData(len);
- }
- else {
- // Skip extra size
- len = valuestrsize() - 4;
- return value() + 5 + 4;
- }
- }
+ /**
+ * Returns a StringData pointing into this element's data. Does not validate that the
+ * element is actually of type String.
+ */
+ const StringData valueStringData() const {
+ return StringData(valuestr(), valuestrsize() - 1);
+ }
- BinDataType binDataType() const {
- // BinData: <int len> <byte subtype> <byte[len] data>
- verify( type() == BinData );
- unsigned char c = (value() + 4)[0];
- return (BinDataType)c;
- }
+ /** Get javascript code of a CodeWScope data element. */
+ const char* codeWScopeCode() const {
+ massert(16177, "not codeWScope", type() == CodeWScope);
+ return value() + 4 + 4; // two ints precede code (see BSON spec)
+ }
- /** Retrieve the regex std::string for a Regex element */
- const char *regex() const {
- verify(type() == RegEx);
- return value();
- }
+ /** Get length of the code part of the CodeWScope object
+ * This INCLUDES the null char at the end */
+ int codeWScopeCodeLen() const {
+ massert(16178, "not codeWScope", type() == CodeWScope);
+ return ConstDataView(value() + 4).read<LittleEndian<int>>();
+ }
- /** Retrieve the regex flags (options) for a Regex element */
- const char *regexFlags() const {
- const char *p = regex();
- return p + strlen(p) + 1;
- }
+ /** Get the scope SavedContext of a CodeWScope data element.
+ *
+ * This function is DEPRECATED, since it can error if there are
+ * null chars in the codeWScopeCode. However, some existing indexes
+ * may be based on an incorrect ordering derived from this function,
+ * so it may still need to be used in certain cases.
+ * */
+ const char* codeWScopeScopeDataUnsafe() const {
+ // This can error if there are null chars in the codeWScopeCode
+ return codeWScopeCode() + strlen(codeWScopeCode()) + 1;
+ }
- /** like operator== but doesn't check the fieldname,
- just the value.
- */
- bool valuesEqual(const BSONElement& r) const {
- return woCompare( r , false ) == 0;
- }
+ /* Get the scope SavedContext of a CodeWScope data element.
+ *
+ * This is the corrected version of codeWScopeScopeDataUnsafe(),
+ * but note that existing uses might rely on the behavior of
+ * that function so be careful in choosing which version to use.
+ */
+ const char* codeWScopeScopeData() const {
+ return codeWScopeCode() + codeWScopeCodeLen();
+ }
- /** Returns true if elements are equal. */
- bool operator==(const BSONElement& r) const {
- return woCompare( r , true ) == 0;
+ /** Get the embedded object this element holds. */
+ BSONObj embeddedObject() const;
+
+ /* uasserts if not an object */
+ BSONObj embeddedObjectUserCheck() const;
+
+ BSONObj codeWScopeObject() const;
+
+ /** Get raw binary data. Element must be of type BinData. Doesn't handle type 2 specially */
+ const char* binData(int& len) const {
+ // BinData: <int len> <byte subtype> <byte[len] data>
+ verify(type() == BinData);
+ len = valuestrsize();
+ return value() + 5;
+ }
+ /** Get binary data. Element must be of type BinData. Handles type 2 */
+ const char* binDataClean(int& len) const {
+ // BinData: <int len> <byte subtype> <byte[len] data>
+ if (binDataType() != ByteArrayDeprecated) {
+ return binData(len);
+ } else {
+ // Skip extra size
+ len = valuestrsize() - 4;
+ return value() + 5 + 4;
}
- /** Returns true if elements are unequal. */
- bool operator!=(const BSONElement& r) const { return !operator==(r); }
-
- /** Well ordered comparison.
- @return <0: l<r. 0:l==r. >0:l>r
- order by type, field name, and field value.
- If considerFieldName is true, pay attention to the field name.
- */
- int woCompare( const BSONElement &e, bool considerFieldName = true ) const;
-
- /**
- * Functor compatible with std::hash for std::unordered_{map,set}
- * Warning: The hash function is subject to change. Do not use in cases where hashes need
- * to be consistent across versions.
- */
- struct Hasher {
- size_t operator() (const BSONElement& elem) const;
- };
-
- const char * rawdata() const { return data; }
-
- /** 0 == Equality, just not defined yet */
- int getGtLtOp( int def = 0 ) const;
-
- /** Constructs an empty element */
- BSONElement();
-
- /** True if this element may contain subobjects. */
- bool mayEncapsulate() const {
- switch ( type() ) {
+ }
+
+ BinDataType binDataType() const {
+ // BinData: <int len> <byte subtype> <byte[len] data>
+ verify(type() == BinData);
+ unsigned char c = (value() + 4)[0];
+ return (BinDataType)c;
+ }
+
+ /** Retrieve the regex std::string for a Regex element */
+ const char* regex() const {
+ verify(type() == RegEx);
+ return value();
+ }
+
+ /** Retrieve the regex flags (options) for a Regex element */
+ const char* regexFlags() const {
+ const char* p = regex();
+ return p + strlen(p) + 1;
+ }
+
+ /** like operator== but doesn't check the fieldname,
+ just the value.
+ */
+ bool valuesEqual(const BSONElement& r) const {
+ return woCompare(r, false) == 0;
+ }
+
+ /** Returns true if elements are equal. */
+ bool operator==(const BSONElement& r) const {
+ return woCompare(r, true) == 0;
+ }
+ /** Returns true if elements are unequal. */
+ bool operator!=(const BSONElement& r) const {
+ return !operator==(r);
+ }
+
+ /** Well ordered comparison.
+ @return <0: l<r. 0:l==r. >0:l>r
+ order by type, field name, and field value.
+ If considerFieldName is true, pay attention to the field name.
+ */
+ int woCompare(const BSONElement& e, bool considerFieldName = true) const;
+
+ /**
+ * Functor compatible with std::hash for std::unordered_{map,set}
+ * Warning: The hash function is subject to change. Do not use in cases where hashes need
+ * to be consistent across versions.
+ */
+ struct Hasher {
+ size_t operator()(const BSONElement& elem) const;
+ };
+
+ const char* rawdata() const {
+ return data;
+ }
+
+ /** 0 == Equality, just not defined yet */
+ int getGtLtOp(int def = 0) const;
+
+ /** Constructs an empty element */
+ BSONElement();
+
+ /** True if this element may contain subobjects. */
+ bool mayEncapsulate() const {
+ switch (type()) {
case Object:
case mongo::Array:
case CodeWScope:
return true;
default:
return false;
- }
}
+ }
- /** True if this element can be a BSONObj */
- bool isABSONObj() const {
- switch( type() ) {
+ /** True if this element can be a BSONObj */
+ bool isABSONObj() const {
+ switch (type()) {
case Object:
case mongo::Array:
return true;
default:
return false;
- }
- }
-
- Timestamp timestamp() const {
- if( type() == mongo::Date || type() == bsonTimestamp ) {
- return Timestamp(
- ConstDataView(value()).read<LittleEndian<unsigned long long>>().value);
- }
- return Timestamp();
}
+ }
- Date_t timestampTime() const {
- unsigned long long t = ConstDataView(value() + 4).read<LittleEndian<unsigned int>>();
- return Date_t::fromMillisSinceEpoch(t * 1000);
- }
- unsigned int timestampInc() const {
- return ConstDataView(value()).read<LittleEndian<unsigned int>>();
+ Timestamp timestamp() const {
+ if (type() == mongo::Date || type() == bsonTimestamp) {
+ return Timestamp(ConstDataView(value()).read<LittleEndian<unsigned long long>>().value);
}
+ return Timestamp();
+ }
- unsigned long long timestampValue() const {
- return ConstDataView(value()).read<LittleEndian<unsigned long long>>();
- }
+ Date_t timestampTime() const {
+ unsigned long long t = ConstDataView(value() + 4).read<LittleEndian<unsigned int>>();
+ return Date_t::fromMillisSinceEpoch(t * 1000);
+ }
+ unsigned int timestampInc() const {
+ return ConstDataView(value()).read<LittleEndian<unsigned int>>();
+ }
- const char * dbrefNS() const {
- uassert( 10063 , "not a dbref" , type() == DBRef );
- return value() + 4;
- }
+ unsigned long long timestampValue() const {
+ return ConstDataView(value()).read<LittleEndian<unsigned long long>>();
+ }
- const mongo::OID dbrefOID() const {
- uassert( 10064 , "not a dbref" , type() == DBRef );
- const char * start = value();
- start += 4 + ConstDataView(start).read<LittleEndian<int>>();
- return mongo::OID::from(start);
- }
+ const char* dbrefNS() const {
+ uassert(10063, "not a dbref", type() == DBRef);
+ return value() + 4;
+ }
- /** this does not use fieldName in the comparison, just the value */
- bool operator<( const BSONElement& other ) const {
- int x = (int)canonicalType() - (int)other.canonicalType();
- if ( x < 0 ) return true;
- else if ( x > 0 ) return false;
- return compareElementValues(*this,other) < 0;
- }
+ const mongo::OID dbrefOID() const {
+ uassert(10064, "not a dbref", type() == DBRef);
+ const char* start = value();
+ start += 4 + ConstDataView(start).read<LittleEndian<int>>();
+ return mongo::OID::from(start);
+ }
- // @param maxLen don't scan more than maxLen bytes
- explicit BSONElement(const char *d, int maxLen) : data(d) {
- if ( eoo() ) {
- totalSize = 1;
- fieldNameSize_ = 0;
- }
- else {
- totalSize = -1;
- fieldNameSize_ = -1;
- if ( maxLen != -1 ) {
- size_t size = strnlen( fieldName(), maxLen - 1 );
- uassert( 10333 , "Invalid field name", size < size_t(maxLen - 1) );
- fieldNameSize_ = size + 1;
- }
- }
- }
+ /** this does not use fieldName in the comparison, just the value */
+ bool operator<(const BSONElement& other) const {
+ int x = (int)canonicalType() - (int)other.canonicalType();
+ if (x < 0)
+ return true;
+ else if (x > 0)
+ return false;
+ return compareElementValues(*this, other) < 0;
+ }
- explicit BSONElement(const char *d) : data(d) {
- fieldNameSize_ = -1;
+ // @param maxLen don't scan more than maxLen bytes
+ explicit BSONElement(const char* d, int maxLen) : data(d) {
+ if (eoo()) {
+ totalSize = 1;
+ fieldNameSize_ = 0;
+ } else {
totalSize = -1;
- if ( eoo() ) {
- fieldNameSize_ = 0;
- totalSize = 1;
+ fieldNameSize_ = -1;
+ if (maxLen != -1) {
+ size_t size = strnlen(fieldName(), maxLen - 1);
+ uassert(10333, "Invalid field name", size < size_t(maxLen - 1));
+ fieldNameSize_ = size + 1;
}
}
+ }
- struct FieldNameSizeTag {}; // For disambiguation with ctor taking 'maxLen' above.
-
- /** Construct a BSONElement where you already know the length of the name. The value
- * passed here includes the null terminator. The data pointed to by 'd' must not
- * represent an EOO. You may pass -1 to indicate that you don't actually know the
- * size.
- */
- BSONElement(const char* d, int fieldNameSize, FieldNameSizeTag)
- : data(d)
- , fieldNameSize_(fieldNameSize) // internal size includes null terminator
- , totalSize(-1) {
+ explicit BSONElement(const char* d) : data(d) {
+ fieldNameSize_ = -1;
+ totalSize = -1;
+ if (eoo()) {
+ fieldNameSize_ = 0;
+ totalSize = 1;
}
+ }
- std::string _asCode() const;
-
- template<typename T> bool coerce( T* out ) const;
-
- private:
- const char *data;
- mutable int fieldNameSize_; // cached value
-
- mutable int totalSize; /* caches the computed size */
-
- friend class BSONObjIterator;
- friend class BSONObj;
- const BSONElement& chk(int t) const {
- if ( t != type() ) {
- StringBuilder ss;
- if( eoo() )
- ss << "field not found, expected type " << t;
- else
- ss << "wrong type for field (" << fieldName() << ") " << type() << " != " << t;
- msgasserted(13111, ss.str() );
- }
- return *this;
- }
- const BSONElement& chk(bool expr) const {
- massert(13118, "unexpected or missing type value in BSON object", expr);
- return *this;
- }
- };
+ struct FieldNameSizeTag {}; // For disambiguation with ctor taking 'maxLen' above.
+
+ /** Construct a BSONElement where you already know the length of the name. The value
+ * passed here includes the null terminator. The data pointed to by 'd' must not
+ * represent an EOO. You may pass -1 to indicate that you don't actually know the
+ * size.
+ */
+ BSONElement(const char* d, int fieldNameSize, FieldNameSizeTag)
+ : data(d),
+ fieldNameSize_(fieldNameSize) // internal size includes null terminator
+ ,
+ totalSize(-1) {}
+
+ std::string _asCode() const;
+
+ template <typename T>
+ bool coerce(T* out) const;
+
+private:
+ const char* data;
+ mutable int fieldNameSize_; // cached value
+
+ mutable int totalSize; /* caches the computed size */
+
+ friend class BSONObjIterator;
+ friend class BSONObj;
+ const BSONElement& chk(int t) const {
+ if (t != type()) {
+ StringBuilder ss;
+ if (eoo())
+ ss << "field not found, expected type " << t;
+ else
+ ss << "wrong type for field (" << fieldName() << ") " << type() << " != " << t;
+ msgasserted(13111, ss.str());
+ }
+ return *this;
+ }
+ const BSONElement& chk(bool expr) const {
+ massert(13118, "unexpected or missing type value in BSON object", expr);
+ return *this;
+ }
+};
- inline bool BSONElement::trueValue() const {
- // NOTE Behavior changes must be replicated in Value::coerceToBool().
- switch( type() ) {
+inline bool BSONElement::trueValue() const {
+ // NOTE Behavior changes must be replicated in Value::coerceToBool().
+ switch (type()) {
case NumberLong:
return _numberLong() != 0;
case NumberDouble:
@@ -581,24 +641,24 @@ namespace mongo {
default:
;
- }
- return true;
}
+ return true;
+}
- /** @return true if element is of a numeric type. */
- inline bool BSONElement::isNumber() const {
- switch( type() ) {
+/** @return true if element is of a numeric type. */
+inline bool BSONElement::isNumber() const {
+ switch (type()) {
case NumberLong:
case NumberDouble:
case NumberInt:
return true;
default:
return false;
- }
}
+}
- inline bool BSONElement::isSimpleType() const {
- switch( type() ) {
+inline bool BSONElement::isSimpleType() const {
+ switch (type()) {
case NumberLong:
case NumberDouble:
case NumberInt:
@@ -609,11 +669,11 @@ namespace mongo {
return true;
default:
return false;
- }
}
+}
- inline double BSONElement::numberDouble() const {
- switch( type() ) {
+inline double BSONElement::numberDouble() const {
+ switch (type()) {
case NumberDouble:
return _numberDouble();
case NumberInt:
@@ -622,69 +682,68 @@ namespace mongo {
return _numberLong();
default:
return 0;
- }
}
+}
- /** Retrieve int value for the element safely. Zero returned if not a number. Converted to int if another numeric type. */
- inline int BSONElement::numberInt() const {
- switch( type() ) {
+/** Retrieve int value for the element safely. Zero returned if not a number. Converted to int if another numeric type. */
+inline int BSONElement::numberInt() const {
+ switch (type()) {
case NumberDouble:
- return (int) _numberDouble();
+ return (int)_numberDouble();
case NumberInt:
return _numberInt();
case NumberLong:
- return (int) _numberLong();
+ return (int)_numberLong();
default:
return 0;
- }
}
+}
- /** Retrieve long value for the element safely. Zero returned if not a number. */
- inline long long BSONElement::numberLong() const {
- switch( type() ) {
+/** Retrieve long value for the element safely. Zero returned if not a number. */
+inline long long BSONElement::numberLong() const {
+ switch (type()) {
case NumberDouble:
- return (long long) _numberDouble();
+ return (long long)_numberDouble();
case NumberInt:
return _numberInt();
case NumberLong:
return _numberLong();
default:
return 0;
- }
}
+}
- /** Like numberLong() but with well-defined behavior for doubles that
- * are NaNs, or too large/small to be represented as long longs.
- * NaNs -> 0
- * very large doubles -> LLONG_MAX
- * very small doubles -> LLONG_MIN */
- inline long long BSONElement::safeNumberLong() const {
- double d;
- switch( type() ) {
+/** Like numberLong() but with well-defined behavior for doubles that
+ * are NaNs, or too large/small to be represented as long longs.
+ * NaNs -> 0
+ * very large doubles -> LLONG_MAX
+ * very small doubles -> LLONG_MIN */
+inline long long BSONElement::safeNumberLong() const {
+ double d;
+ switch (type()) {
case NumberDouble:
d = numberDouble();
- if ( std::isnan( d ) ){
+ if (std::isnan(d)) {
return 0;
}
- if ( d > (double) std::numeric_limits<long long>::max() ){
+ if (d > (double)std::numeric_limits<long long>::max()) {
return std::numeric_limits<long long>::max();
}
- if ( d < std::numeric_limits<long long>::min() ){
+ if (d < std::numeric_limits<long long>::min()) {
return std::numeric_limits<long long>::min();
}
default:
return numberLong();
- }
- }
-
- inline BSONElement::BSONElement() {
- static const char kEooElement[] = "";
- data = kEooElement;
- fieldNameSize_ = 0;
- totalSize = 1;
}
+}
- // TODO(SERVER-14596): move to a better place; take a StringData.
- std::string escape( const std::string& s , bool escape_slash=false);
+inline BSONElement::BSONElement() {
+ static const char kEooElement[] = "";
+ data = kEooElement;
+ fieldNameSize_ = 0;
+ totalSize = 1;
+}
+// TODO(SERVER-14596): move to a better place; take a StringData.
+std::string escape(const std::string& s, bool escape_slash = false);
}