diff options
Diffstat (limited to 'bson/bsonelement.h')
-rw-r--r-- | bson/bsonelement.h | 662 |
1 files changed, 334 insertions, 328 deletions
diff --git a/bson/bsonelement.h b/bson/bsonelement.h index 534c773..23d59fa 100644 --- a/bson/bsonelement.h +++ b/bson/bsonelement.h @@ -36,378 +36,384 @@ namespace mongo { 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 UserException if the - element is not of the required type. Example: - - string foo = obj["foo"].String(); // exception if not a string type or DNE + /** 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() */ - string String() const { return chk(mongo::String).valuestr(); } - 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(); } - BSONObj Obj() const; - vector<BSONElement> Array() const; // see implementation for detailed comments - mongo::OID OID() const { return chk(jstOID).__oid(); } - void Null() const { chk(isNull()); } - void OK() const { chk(ok()); } - - /** populate v with the value of the element. If type does not match, throw exception. - useful in templates -- see also BSONObj::Vals(). + class BSONElement { + public: + /** These functions, which start with a capital letter, throw a UserException if the + element is not of the required type. Example: + + string foo = obj["foo"].String(); // exception if not a string type or DNE */ - 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(string& v) const { v = String(); } - - /** Use ok() to check if a value is assigned: - if( myObj["foo"].ok() ) ... - */ - bool ok() const { return !eoo(); } + string String() const { return chk(mongo::String).valuestr(); } + 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(); } + vector<BSONElement> Array() const; // see implementation for detailed comments + mongo::OID OID() const { return chk(jstOID).__oid(); } + void Null() const { chk(isNull()); } // throw UserException if not null + void OK() const { chk(ok()); } // throw UserException 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(string& v) const { v = String(); } + + /** Use ok() to check if a value is assigned: + if( myObj["foo"].ok() ) ... + */ + bool ok() const { return !eoo(); } - string toString( bool includeFieldName = true, bool full=false) const; - void toString(StringBuilder& s, bool includeFieldName = true, bool full=false) const; - string jsonString( JsonStringFormat format, bool includeFieldNames = true, int pretty = 0 ) const; - operator string() const { return toString(); } + string toString( bool includeFieldName = true, bool full=false) const; + void toString(StringBuilder& s, bool includeFieldName = true, bool full=false) const; + string jsonString( JsonStringFormat format, bool includeFieldNames = true, int pretty = 0 ) const; + operator string() const { return toString(); } - /** Returns the type of the element */ - BSONType type() const { return (BSONType) *data; } + /** Returns the type of the element */ + BSONType type() const { return (BSONType) *data; } - /** retrieve a field within this element - throws exception if *this is not an embedded object - */ - BSONElement operator[] (const string& field) const; - - /** returns the tyoe of the element fixed for the main type - the main purpose is numbers. any numeric type will return NumberDouble - Note: if the order changes, indexes have to be re-built or than can be corruption - */ - int canonicalType() const; + /** retrieve a field within this element + throws exception if *this is not an embedded object + */ + BSONElement operator[] (const string& field) const; - /** 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; } + /** returns the tyoe of the element fixed for the main type + the main purpose is numbers. any numeric type will return NumberDouble + Note: if the order changes, indexes have to be re-built or than can be corruption + */ + int canonicalType() const; - /** Size of the element. - @param maxLen If maxLen is specified, don't scan more than maxLen bytes to calculate size. - */ - int size( int maxLen = -1 ) const; + /** 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; } - /** Wrap this element up as a singleton object. */ - BSONObj wrap() const; + /** Size of the element. + @param maxLen If maxLen is specified, don't scan more than maxLen bytes to calculate size. + */ + int size( int maxLen = -1 ) const; - /** Wrap this element up as a singleton object with a new name. */ - BSONObj wrap( const char* newName) const; + /** Wrap this element up as a singleton object. */ + BSONObj wrap() 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; - } + /** Wrap this element up as a singleton object with a new name. */ + BSONObj wrap( const char* newName) 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; - } + /** 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 isBoolean() const { return type() == mongo::Bool; } + /** 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; + } - /** @return value of a boolean element. - You must assure element is a boolean before - calling. */ - bool boolean() const { - return *value() ? true : false; - } + bool isBoolean() const { return type() == mongo::Bool; } - /** Retrieve a java style date value from the element. - Ensure element is of type Date before calling. - */ - Date_t date() const { - return *reinterpret_cast< const Date_t* >( value() ); - } + /** @return value of a boolean element. + You must assure element is a boolean before + calling. */ + bool boolean() const { + return *value() ? true : false; + } - /** Convert the value to boolean, regardless of its type, in a javascript-like fashion - (i.e., treat zero and null as false). - */ - bool trueValue() const; + /** Retrieve a java style date value from the element. + Ensure element is of type Date before calling. + */ + Date_t date() const { + return *reinterpret_cast< const Date_t* >( value() ); + } - /** True if number, string, bool, date, OID */ - bool isSimpleType() const; + /** Convert the value to boolean, regardless of its type, in a javascript-like fashion + (i.e., treat zero and null as false). + */ + bool trueValue() const; + + /** True if number, string, bool, date, OID */ + bool isSimpleType() const; + + /** True if element is of a numeric type. */ + bool isNumber() const; + + /** Return double value for this field. MUST be NumberDouble type. */ + double _numberDouble() const {return *reinterpret_cast< const double* >( value() ); } + /** Return double value for this field. MUST be NumberInt type. */ + int _numberInt() const {return *reinterpret_cast< const int* >( value() ); } + /** Return double value for this field. MUST be NumberLong type. */ + long long _numberLong() const {return *reinterpret_cast< const long long* >( value() ); } + + /** 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. */ + long long numberLong() 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(); } - /** True if element is of a numeric type. */ - bool isNumber() const; + /** Retrieve the object ID stored in the object. + You must ensure the element is of type jstOID first. */ + const mongo::OID &__oid() const { return *reinterpret_cast< const mongo::OID* >( value() ); } - /** Return double value for this field. MUST be NumberDouble type. */ - double _numberDouble() const {return *reinterpret_cast< const double* >( value() ); } - /** Return double value for this field. MUST be NumberInt type. */ - int _numberInt() const {return *reinterpret_cast< const int* >( value() ); } - /** Return double value for this field. MUST be NumberLong type. */ - long long _numberLong() const {return *reinterpret_cast< const long long* >( value() ); } + /** True if element is null. */ + bool isNull() const { + return type() == jstNULL; + } - /** 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. */ - long long numberLong() 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(); } + /** Size (length) of a string element. + You must assure of type String first. */ + int valuestrsize() const { + return *reinterpret_cast< const int* >( value() ); + } - /** Retrieve the object ID stored in the object. - You must ensure the element is of type jstOID first. */ - const mongo::OID &__oid() const { return *reinterpret_cast< const mongo::OID* >( value() ); } + // for objects the size *includes* the size of the size field + int objsize() const { + return *reinterpret_cast< const int* >( value() ); + } - /** True if element is null. */ - bool isNull() const { - return type() == jstNULL; - } - - /** Size (length) of a string element. - You must assure of type String first. */ - int valuestrsize() const { - return *reinterpret_cast< const int* >( value() ); - } + /** 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; + } - // for objects the size *includes* the size of the size field - int objsize() const { - return *reinterpret_cast< const int* >( value() ); - } + /** Get the string value of the element. If not a string returns "". */ + const char *valuestrsafe() const { + return type() == mongo::String ? valuestr() : ""; + } + /** Get the string value of the element. If not a string returns "". */ + string str() const { + return type() == mongo::String ? string(valuestr(), valuestrsize()-1) : string(); + } - /** 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; - } + /** Get javascript code of a CodeWScope data element. */ + const char * codeWScopeCode() const { + return value() + 8; + } + /** Get the scope SavedContext of a CodeWScope data element. */ + const char * codeWScopeScopeData() const { + // TODO fix + return codeWScopeCode() + strlen( codeWScopeCode() ) + 1; + } - /** Get the string value of the element. If not a string returns "". */ - const char *valuestrsafe() const { - return type() == mongo::String ? valuestr() : ""; - } - /** Get the string value of the element. If not a string returns "". */ - string str() const { - return type() == mongo::String ? string(valuestr(), valuestrsize()-1) : string(); - } + /** Get the embedded object this element holds. */ + BSONObj embeddedObject() const; - /** Get javascript code of a CodeWScope data element. */ - const char * codeWScopeCode() const { - return value() + 8; - } - /** Get the scope SavedContext of a CodeWScope data element. */ - const char * codeWScopeScopeData() const { - // TODO fix - return codeWScopeCode() + strlen( codeWScopeCode() ) + 1; - } + /* uasserts if not an object */ + BSONObj embeddedObjectUserCheck() const; - /** Get the embedded object this element holds. */ - BSONObj embeddedObject() const; + BSONObj codeWScopeObject() const; - /* uasserts if not an object */ - BSONObj embeddedObjectUserCheck() 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> + assert( 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; + } + } - BSONObj codeWScopeObject() const; + BinDataType binDataType() const { + // BinData: <int len> <byte subtype> <byte[len] data> + assert( type() == BinData ); + unsigned char c = (value() + 4)[0]; + return (BinDataType)c; + } - /** 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> - assert( 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; + /** Retrieve the regex string for a Regex element */ + const char *regex() const { + assert(type() == RegEx); + return value(); } - } - - BinDataType binDataType() const { - // BinData: <int len> <byte subtype> <byte[len] data> - assert( type() == BinData ); - unsigned char c = (value() + 4)[0]; - return (BinDataType)c; - } - /** Retrieve the regex string for a Regex element */ - const char *regex() const { - assert(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; + } - /** 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; + } - /** 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 equal. */ - bool operator==(const BSONElement& r) const { - return woCompare( r , true ) == 0; - } + /** 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; - /** 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; + const char * rawdata() const { return data; } - const char * rawdata() const { - return data; - } - - /** 0 == Equality, just not defined yet */ - int getGtLtOp( int def = 0 ) const; - - /** Constructs an empty element */ - BSONElement(); - - /** Check that data is internally consistent. */ - void validate() const; - - /** True if this element may contain subobjects. */ - bool mayEncapsulate() const { - switch ( type() ){ - case Object: - case mongo::Array: - case CodeWScope: - return true; - default: - return false; + /** 0 == Equality, just not defined yet */ + int getGtLtOp( int def = 0 ) const; + + /** Constructs an empty element */ + BSONElement(); + + /** Check that data is internally consistent. */ + void validate() const; + + /** 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() ){ - case Object: - case mongo::Array: - return true; - default: - return false; + /** True if this element can be a BSONObj */ + bool isABSONObj() const { + switch( type() ) { + case Object: + case mongo::Array: + return true; + default: + return false; + } } - } - Date_t timestampTime() const{ - unsigned long long t = ((unsigned int*)(value() + 4 ))[0]; - return t * 1000; - } - unsigned int timestampInc() const{ - return ((unsigned int*)(value() ))[0]; - } + Date_t timestampTime() const { + unsigned long long t = ((unsigned int*)(value() + 4 ))[0]; + return t * 1000; + } + unsigned int timestampInc() const { + return ((unsigned int*)(value() ))[0]; + } - const char * dbrefNS() const { - uassert( 10063 , "not a dbref" , type() == DBRef ); - return value() + 4; - } + const char * dbrefNS() const { + uassert( 10063 , "not a dbref" , type() == DBRef ); + return value() + 4; + } - const mongo::OID& dbrefOID() const { - uassert( 10064 , "not a dbref" , type() == DBRef ); - const char * start = value(); - start += 4 + *reinterpret_cast< const int* >( start ); - return *reinterpret_cast< const mongo::OID* >( start ); - } + const mongo::OID& dbrefOID() const { + uassert( 10064 , "not a dbref" , type() == DBRef ); + const char * start = value(); + start += 4 + *reinterpret_cast< const int* >( start ); + return *reinterpret_cast< const mongo::OID* >( start ); + } - 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; - } - - // If maxLen is specified, don't scan more than maxLen bytes. - explicit BSONElement(const char *d, int maxLen = -1) : data(d) { - fieldNameSize_ = -1; - if ( eoo() ) - fieldNameSize_ = 0; - else { - if ( maxLen != -1 ) { - int size = (int) strnlen( fieldName(), maxLen - 1 ); - massert( 10333 , "Invalid field name", size != -1 ); - fieldNameSize_ = size + 1; - } + 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; } - totalSize = -1; - } - string _asCode() const; - OpTime _opTime() const; + // If maxLen is specified, don't scan more than maxLen bytes. + explicit BSONElement(const char *d, int maxLen = -1) : data(d) { + fieldNameSize_ = -1; + if ( eoo() ) + fieldNameSize_ = 0; + else { + if ( maxLen != -1 ) { + int size = (int) strnlen( fieldName(), maxLen - 1 ); + massert( 10333 , "Invalid field name", size != -1 ); + fieldNameSize_ = size + 1; + } + } + totalSize = -1; + } -private: - const char *data; - mutable int fieldNameSize_; // cached value - int fieldNameSize() const { - if ( fieldNameSize_ == -1 ) - fieldNameSize_ = (int)strlen( fieldName() ) + 1; - return fieldNameSize_; - } - mutable int totalSize; /* caches the computed size */ + string _asCode() const; + OpTime _opTime() const; - friend class BSONObjIterator; - friend class BSONObj; - const BSONElement& chk(int t) const { - if ( t != type() ){ - StringBuilder ss; - ss << "wrong type for BSONElement (" << fieldName() << ") " << type() << " != " << t; - uasserted(13111, ss.str() ); + private: + const char *data; + mutable int fieldNameSize_; // cached value + int fieldNameSize() const { + if ( fieldNameSize_ == -1 ) + fieldNameSize_ = (int)strlen( fieldName() ) + 1; + return fieldNameSize_; } - return *this; - } - const BSONElement& chk(bool expr) const { - uassert(13118, "unexpected or missing type value in BSON object", expr); - return *this; - } -}; + mutable int totalSize; /* caches the computed size */ + + friend class BSONObjIterator; + friend class BSONObj; + const BSONElement& chk(int t) const { + if ( t != type() ) { + StringBuilder ss; + ss << "wrong type for BSONElement (" << fieldName() << ") " << type() << " != " << t; + uasserted(13111, ss.str() ); + } + return *this; + } + const BSONElement& chk(bool expr) const { + uassert(13118, "unexpected or missing type value in BSON object", expr); + return *this; + } + }; inline int BSONElement::canonicalType() const { BSONType t = type(); - switch ( t ){ + switch ( t ) { case MinKey: case MaxKey: return t; @@ -448,7 +454,7 @@ private: assert(0); return -1; } - } + } inline bool BSONElement::trueValue() const { switch( type() ) { @@ -464,7 +470,7 @@ private: case jstNULL: case Undefined: return false; - + default: ; } @@ -478,13 +484,13 @@ private: case NumberDouble: case NumberInt: return true; - default: + default: return false; } } inline bool BSONElement::isSimpleType() const { - switch( type() ){ + switch( type() ) { case NumberLong: case NumberDouble: case NumberInt: @@ -493,7 +499,7 @@ private: case mongo::Date: case jstOID: return true; - default: + default: return false; } } @@ -512,7 +518,7 @@ private: } /** 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 { + inline int BSONElement::numberInt() const { switch( type() ) { case NumberDouble: return (int) _numberDouble(); @@ -526,7 +532,7 @@ private: } /** Retrieve long value for the element safely. Zero returned if not a number. */ - inline long long BSONElement::numberLong() const { + inline long long BSONElement::numberLong() const { switch( type() ) { case NumberDouble: return (long long) _numberDouble(); @@ -537,7 +543,7 @@ private: default: return 0; } - } + } inline BSONElement::BSONElement() { static char z = 0; |