diff options
Diffstat (limited to 'src/mongo/bson/bsonelement.cpp')
-rw-r--r-- | src/mongo/bson/bsonelement.cpp | 918 |
1 files changed, 463 insertions, 455 deletions
diff --git a/src/mongo/bson/bsonelement.cpp b/src/mongo/bson/bsonelement.cpp index 6948135e1e2..799da76b11d 100644 --- a/src/mongo/bson/bsonelement.cpp +++ b/src/mongo/bson/bsonelement.cpp @@ -43,99 +43,94 @@ #include "mongo/util/mongoutils/str.h" namespace mongo { - namespace str = mongoutils::str; +namespace str = mongoutils::str; - using std::dec; - using std::hex; - using std::string; +using std::dec; +using std::hex; +using std::string; - string BSONElement::jsonString( JsonStringFormat format, bool includeFieldNames, int pretty ) const { - std::stringstream s; - if ( includeFieldNames ) - s << '"' << escape( fieldName() ) << "\" : "; - switch ( type() ) { +string BSONElement::jsonString(JsonStringFormat format, bool includeFieldNames, int pretty) const { + std::stringstream s; + if (includeFieldNames) + s << '"' << escape(fieldName()) << "\" : "; + switch (type()) { case mongo::String: case Symbol: - s << '"' << escape( string(valuestr(), valuestrsize()-1) ) << '"'; + s << '"' << escape(string(valuestr(), valuestrsize() - 1)) << '"'; break; case NumberLong: if (format == TenGen) { s << "NumberLong(" << _numberLong() << ")"; - } - else { + } else { s << "{ \"$numberLong\" : \"" << _numberLong() << "\" }"; } break; case NumberInt: - if(format == JS) { + if (format == JS) { s << "NumberInt(" << _numberInt() << ")"; break; } case NumberDouble: - if ( number() >= -std::numeric_limits< double >::max() && - number() <= std::numeric_limits< double >::max() ) { - s.precision( 16 ); + if (number() >= -std::numeric_limits<double>::max() && + number() <= std::numeric_limits<double>::max()) { + s.precision(16); s << number(); } // This is not valid JSON, but according to RFC-4627, "Numeric values that cannot be // represented as sequences of digits (such as Infinity and NaN) are not permitted." so // we are accepting the fact that if we have such values we cannot output valid JSON. - else if ( std::isnan(number()) ) { + else if (std::isnan(number())) { s << "NaN"; - } - else if ( std::isinf(number()) ) { - s << ( number() > 0 ? "Infinity" : "-Infinity"); - } - else { + } else if (std::isinf(number())) { + s << (number() > 0 ? "Infinity" : "-Infinity"); + } else { StringBuilder ss; ss << "Number " << number() << " cannot be represented in JSON"; string message = ss.str(); - massert( 10311 , message.c_str(), false ); + massert(10311, message.c_str(), false); } break; case mongo::Bool: - s << ( boolean() ? "true" : "false" ); + s << (boolean() ? "true" : "false"); break; case jstNULL: s << "null"; break; case Undefined: - if ( format == Strict ) { + if (format == Strict) { s << "{ \"$undefined\" : true }"; - } - else { + } else { s << "undefined"; } break; case Object: - s << embeddedObject().jsonString( format, pretty ); + s << embeddedObject().jsonString(format, pretty); break; case mongo::Array: { - if ( embeddedObject().isEmpty() ) { + if (embeddedObject().isEmpty()) { s << "[]"; break; } s << "[ "; - BSONObjIterator i( embeddedObject() ); + BSONObjIterator i(embeddedObject()); BSONElement e = i.next(); - if ( !e.eoo() ) { + if (!e.eoo()) { int count = 0; - while ( 1 ) { - if( pretty ) { + while (1) { + if (pretty) { s << '\n'; - for( int x = 0; x < pretty; x++ ) + for (int x = 0; x < pretty; x++) s << " "; } if (strtol(e.fieldName(), 0, 10) > count) { s << "undefined"; - } - else { - s << e.jsonString( format, false, pretty?pretty+1:0 ); + } else { + s << e.jsonString(format, false, pretty ? pretty + 1 : 0); e = i.next(); } count++; - if ( e.eoo() ) + if (e.eoo()) break; s << ", "; } @@ -144,45 +139,43 @@ namespace mongo { break; } case DBRef: { - if ( format == TenGen ) + if (format == TenGen) s << "Dbref( "; else s << "{ \"$ref\" : "; s << '"' << valuestr() << "\", "; - if ( format != TenGen ) + if (format != TenGen) s << "\"$id\" : "; s << '"' << mongo::OID::from(valuestr() + valuestrsize()) << "\" "; - if ( format == TenGen ) + if (format == TenGen) s << ')'; else s << '}'; break; } case jstOID: - if ( format == TenGen ) { + if (format == TenGen) { s << "ObjectId( "; - } - else { + } else { s << "{ \"$oid\" : "; } s << '"' << __oid() << '"'; - if ( format == TenGen ) { + if (format == TenGen) { s << " )"; - } - else { + } else { s << " }"; } break; case BinData: { - ConstDataCursor reader( value() ); + ConstDataCursor reader(value()); const int len = reader.readAndAdvance<LittleEndian<int>>(); BinDataType type = static_cast<BinDataType>(reader.readAndAdvance<uint8_t>()); s << "{ \"$binary\" : \""; - base64::encode( s , reader.view() , len ); + base64::encode(s, reader.view(), len); s << "\", \"$type\" : \"" << hex; - s.width( 2 ); - s.fill( '0' ); + s.width(2); + s.fill('0'); s << type << dec; s << "\" }"; break; @@ -199,13 +192,11 @@ namespace mongo { // Date_t::millis is negative (before the epoch). if (d.isFormattable()) { s << "\"" << dateToISOStringLocal(date()) << "\""; - } - else { + } else { s << "{ \"$numberLong\" : \"" << d.toMillisSinceEpoch() << "\" }"; } s << " }"; - } - else { + } else { s << "Date( "; if (pretty) { Date_t d = date(); @@ -217,35 +208,32 @@ namespace mongo { // large, and the case where Date_t::millis is negative (before the epoch). if (d.isFormattable()) { s << "\"" << dateToISOStringLocal(date()) << "\""; - } - else { + } else { // FIXME: This is not parseable by the shell, since it may not fit in a // float s << d.toMillisSinceEpoch(); } - } - else { + } else { s << date().asInt64(); } s << " )"; } break; case RegEx: - if ( format == Strict ) { - s << "{ \"$regex\" : \"" << escape( regex() ); + if (format == Strict) { + s << "{ \"$regex\" : \"" << escape(regex()); s << "\", \"$options\" : \"" << regexFlags() << "\" }"; - } - else { - s << "/" << escape( regex() , true ) << "/"; + } else { + s << "/" << escape(regex(), true) << "/"; // FIXME Worry about alpha order? - for ( const char *f = regexFlags(); *f; ++f ) { - switch ( *f ) { - case 'g': - case 'i': - case 'm': - s << *f; - default: - break; + for (const char* f = regexFlags(); *f; ++f) { + switch (*f) { + case 'g': + case 'i': + case 'm': + s << *f; + default: + break; } } } @@ -253,7 +241,7 @@ namespace mongo { case CodeWScope: { BSONObj scope = codeWScopeObject(); - if ( ! scope.isEmpty() ) { + if (!scope.isEmpty()) { s << "{ \"$code\" : \"" << escape(_asCode()) << "\" , " << "\"$scope\" : " << scope.jsonString() << " }"; break; @@ -265,12 +253,10 @@ namespace mongo { break; case bsonTimestamp: - if ( format == TenGen ) { - s << "Timestamp( " - << durationCount<Seconds>(timestampTime().toDurationSinceEpoch()) + if (format == TenGen) { + s << "Timestamp( " << durationCount<Seconds>(timestampTime().toDurationSinceEpoch()) << ", " << timestampInc() << " )"; - } - else { + } else { s << "{ \"$timestamp\" : { \"t\" : " << durationCount<Seconds>(timestampTime().toDurationSinceEpoch()) << ", \"i\" : " << timestampInc() << " } }"; @@ -290,169 +276,173 @@ namespace mongo { ss << "Cannot create a properly formatted JSON string with " << "element: " << toString() << " of type: " << type(); string message = ss.str(); - massert( 10312 , message.c_str(), false ); - } - return s.str(); + massert(10312, message.c_str(), false); } - - int BSONElement::getGtLtOp( int def ) const { - const char *fn = fieldName(); - if ( fn[0] == '$' && fn[1] ) { - if ( fn[2] == 't' ) { - if ( fn[1] == 'g' ) { - if ( fn[3] == 0 ) return BSONObj::GT; - else if ( fn[3] == 'e' && fn[4] == 0 ) return BSONObj::GTE; - } - else if ( fn[1] == 'l' ) { - if ( fn[3] == 0 ) return BSONObj::LT; - else if ( fn[3] == 'e' && fn[4] == 0 ) return BSONObj::LTE; - } - } - else if ( fn[1] == 'n' && fn[2] == 'e' ) { - if ( fn[3] == 0 ) - return BSONObj::NE; - if ( fn[3] == 'a' && fn[4] == 'r') // matches anything with $near prefix - return BSONObj::opNEAR; + return s.str(); +} + +int BSONElement::getGtLtOp(int def) const { + const char* fn = fieldName(); + if (fn[0] == '$' && fn[1]) { + if (fn[2] == 't') { + if (fn[1] == 'g') { + if (fn[3] == 0) + return BSONObj::GT; + else if (fn[3] == 'e' && fn[4] == 0) + return BSONObj::GTE; + } else if (fn[1] == 'l') { + if (fn[3] == 0) + return BSONObj::LT; + else if (fn[3] == 'e' && fn[4] == 0) + return BSONObj::LTE; } - else if ( fn[1] == 'm' ) { - if ( fn[2] == 'o' && fn[3] == 'd' && fn[4] == 0 ) - return BSONObj::opMOD; - if ( fn[2] == 'a' && fn[3] == 'x' && fn[4] == 'D' && fn[5] == 'i' && fn[6] == 's' && fn[7] == 't' && fn[8] == 'a' && fn[9] == 'n' && fn[10] == 'c' && fn[11] == 'e' && fn[12] == 0 ) - return BSONObj::opMAX_DISTANCE; - } - else if ( fn[1] == 't' && fn[2] == 'y' && fn[3] == 'p' && fn[4] == 'e' && fn[5] == 0 ) - return BSONObj::opTYPE; - else if ( fn[1] == 'i' && fn[2] == 'n' && fn[3] == 0) { - return BSONObj::opIN; - } else if ( fn[1] == 'n' && fn[2] == 'i' && fn[3] == 'n' && fn[4] == 0 ) - return BSONObj::NIN; - else if ( fn[1] == 'a' && fn[2] == 'l' && fn[3] == 'l' && fn[4] == 0 ) - return BSONObj::opALL; - else if ( fn[1] == 's' && fn[2] == 'i' && fn[3] == 'z' && fn[4] == 'e' && fn[5] == 0 ) - return BSONObj::opSIZE; - else if ( fn[1] == 'e' ) { - if ( fn[2] == 'x' && fn[3] == 'i' && fn[4] == 's' && fn[5] == 't' && fn[6] == 's' && fn[7] == 0 ) - return BSONObj::opEXISTS; - if ( fn[2] == 'l' && fn[3] == 'e' && fn[4] == 'm' && fn[5] == 'M' && fn[6] == 'a' && fn[7] == 't' && fn[8] == 'c' && fn[9] == 'h' && fn[10] == 0 ) - return BSONObj::opELEM_MATCH; - } - else if ( fn[1] == 'r' && fn[2] == 'e' && fn[3] == 'g' && fn[4] == 'e' && fn[5] == 'x' && fn[6] == 0 ) - return BSONObj::opREGEX; - else if ( fn[1] == 'o' && fn[2] == 'p' && fn[3] == 't' && fn[4] == 'i' && fn[5] == 'o' && fn[6] == 'n' && fn[7] == 's' && fn[8] == 0 ) - return BSONObj::opOPTIONS; - else if ( fn[1] == 'w' && fn[2] == 'i' && fn[3] == 't' && fn[4] == 'h' && fn[5] == 'i' && fn[6] == 'n' && fn[7] == 0 ) - return BSONObj::opWITHIN; - else if (str::equals(fn + 1, "geoIntersects")) - return BSONObj::opGEO_INTERSECTS; - else if (str::equals(fn + 1, "geoNear")) + } else if (fn[1] == 'n' && fn[2] == 'e') { + if (fn[3] == 0) + return BSONObj::NE; + if (fn[3] == 'a' && fn[4] == 'r') // matches anything with $near prefix return BSONObj::opNEAR; - else if (str::equals(fn + 1, "geoWithin")) - return BSONObj::opWITHIN; - } - return def; + } else if (fn[1] == 'm') { + if (fn[2] == 'o' && fn[3] == 'd' && fn[4] == 0) + return BSONObj::opMOD; + if (fn[2] == 'a' && fn[3] == 'x' && fn[4] == 'D' && fn[5] == 'i' && fn[6] == 's' && + fn[7] == 't' && fn[8] == 'a' && fn[9] == 'n' && fn[10] == 'c' && fn[11] == 'e' && + fn[12] == 0) + return BSONObj::opMAX_DISTANCE; + } else if (fn[1] == 't' && fn[2] == 'y' && fn[3] == 'p' && fn[4] == 'e' && fn[5] == 0) + return BSONObj::opTYPE; + else if (fn[1] == 'i' && fn[2] == 'n' && fn[3] == 0) { + return BSONObj::opIN; + } else if (fn[1] == 'n' && fn[2] == 'i' && fn[3] == 'n' && fn[4] == 0) + return BSONObj::NIN; + else if (fn[1] == 'a' && fn[2] == 'l' && fn[3] == 'l' && fn[4] == 0) + return BSONObj::opALL; + else if (fn[1] == 's' && fn[2] == 'i' && fn[3] == 'z' && fn[4] == 'e' && fn[5] == 0) + return BSONObj::opSIZE; + else if (fn[1] == 'e') { + if (fn[2] == 'x' && fn[3] == 'i' && fn[4] == 's' && fn[5] == 't' && fn[6] == 's' && + fn[7] == 0) + return BSONObj::opEXISTS; + if (fn[2] == 'l' && fn[3] == 'e' && fn[4] == 'm' && fn[5] == 'M' && fn[6] == 'a' && + fn[7] == 't' && fn[8] == 'c' && fn[9] == 'h' && fn[10] == 0) + return BSONObj::opELEM_MATCH; + } else if (fn[1] == 'r' && fn[2] == 'e' && fn[3] == 'g' && fn[4] == 'e' && fn[5] == 'x' && + fn[6] == 0) + return BSONObj::opREGEX; + else if (fn[1] == 'o' && fn[2] == 'p' && fn[3] == 't' && fn[4] == 'i' && fn[5] == 'o' && + fn[6] == 'n' && fn[7] == 's' && fn[8] == 0) + return BSONObj::opOPTIONS; + else if (fn[1] == 'w' && fn[2] == 'i' && fn[3] == 't' && fn[4] == 'h' && fn[5] == 'i' && + fn[6] == 'n' && fn[7] == 0) + return BSONObj::opWITHIN; + else if (str::equals(fn + 1, "geoIntersects")) + return BSONObj::opGEO_INTERSECTS; + else if (str::equals(fn + 1, "geoNear")) + return BSONObj::opNEAR; + else if (str::equals(fn + 1, "geoWithin")) + return BSONObj::opWITHIN; } + return def; +} - /** transform a BSON array into a vector of BSONElements. - we match array # positions with their vector position, and ignore - any fields with non-numeric field names. - */ - std::vector<BSONElement> BSONElement::Array() const { - chk(mongo::Array); - std::vector<BSONElement> v; - BSONObjIterator i(Obj()); - while( i.more() ) { - BSONElement e = i.next(); - const char *f = e.fieldName(); - - unsigned u; - Status status = parseNumberFromString( f, &u ); - if ( status.isOK() ) { - verify( u < 1000000 ); - if( u >= v.size() ) - v.resize(u+1); - v[u] = e; - } - else { - // ignore? - } - } - return v; - } - - /* wo = "well ordered" - note: (mongodb related) : this can only change in behavior when index version # changes +/** transform a BSON array into a vector of BSONElements. + we match array # positions with their vector position, and ignore + any fields with non-numeric field names. */ - int BSONElement::woCompare( const BSONElement &e, - bool considerFieldName ) const { - int lt = (int) canonicalType(); - int rt = (int) e.canonicalType(); - int x = lt - rt; - if( x != 0 && (!isNumber() || !e.isNumber()) ) - return x; - if ( considerFieldName ) { - x = strcmp(fieldName(), e.fieldName()); - if ( x != 0 ) - return x; +std::vector<BSONElement> BSONElement::Array() const { + chk(mongo::Array); + std::vector<BSONElement> v; + BSONObjIterator i(Obj()); + while (i.more()) { + BSONElement e = i.next(); + const char* f = e.fieldName(); + + unsigned u; + Status status = parseNumberFromString(f, &u); + if (status.isOK()) { + verify(u < 1000000); + if (u >= v.size()) + v.resize(u + 1); + v[u] = e; + } else { + // ignore? } - x = compareElementValues(*this, e); + } + return v; +} + +/* wo = "well ordered" + note: (mongodb related) : this can only change in behavior when index version # changes +*/ +int BSONElement::woCompare(const BSONElement& e, bool considerFieldName) const { + int lt = (int)canonicalType(); + int rt = (int)e.canonicalType(); + int x = lt - rt; + if (x != 0 && (!isNumber() || !e.isNumber())) return x; + if (considerFieldName) { + x = strcmp(fieldName(), e.fieldName()); + if (x != 0) + return x; } + x = compareElementValues(*this, e); + return x; +} - BSONObj BSONElement::embeddedObjectUserCheck() const { - if ( MONGO_likely(isABSONObj()) ) - return BSONObj(value()); - std::stringstream ss; - ss << "invalid parameter: expected an object (" << fieldName() << ")"; - uasserted( 10065 , ss.str() ); - return BSONObj(); // never reachable - } - - BSONObj BSONElement::embeddedObject() const { - verify( isABSONObj() ); +BSONObj BSONElement::embeddedObjectUserCheck() const { + if (MONGO_likely(isABSONObj())) return BSONObj(value()); - } - - BSONObj BSONElement::codeWScopeObject() const { - verify( type() == CodeWScope ); - int strSizeWNull = ConstDataView(value() + 4).read<LittleEndian<int>>(); - return BSONObj( value() + 4 + 4 + strSizeWNull ); - } - - // wrap this element up as a singleton object. - BSONObj BSONElement::wrap() const { - BSONObjBuilder b(size()+6); - b.append(*this); - return b.obj(); - } - - BSONObj BSONElement::wrap( StringData newName ) const { - BSONObjBuilder b(size() + 6 + newName.size()); - b.appendAs(*this,newName); - return b.obj(); - } - - void BSONElement::Val(BSONObj& v) const { - v = Obj(); - } - - BSONObj BSONElement::Obj() const { - return embeddedObjectUserCheck(); - } - - BSONElement BSONElement::operator[] (const std::string& field) const { - BSONObj o = Obj(); - return o[field]; - } - - int BSONElement::size( int maxLen ) const { - if ( totalSize >= 0 ) - return totalSize; + std::stringstream ss; + ss << "invalid parameter: expected an object (" << fieldName() << ")"; + uasserted(10065, ss.str()); + return BSONObj(); // never reachable +} + +BSONObj BSONElement::embeddedObject() const { + verify(isABSONObj()); + return BSONObj(value()); +} + +BSONObj BSONElement::codeWScopeObject() const { + verify(type() == CodeWScope); + int strSizeWNull = ConstDataView(value() + 4).read<LittleEndian<int>>(); + return BSONObj(value() + 4 + 4 + strSizeWNull); +} + +// wrap this element up as a singleton object. +BSONObj BSONElement::wrap() const { + BSONObjBuilder b(size() + 6); + b.append(*this); + return b.obj(); +} + +BSONObj BSONElement::wrap(StringData newName) const { + BSONObjBuilder b(size() + 6 + newName.size()); + b.appendAs(*this, newName); + return b.obj(); +} + +void BSONElement::Val(BSONObj& v) const { + v = Obj(); +} + +BSONObj BSONElement::Obj() const { + return embeddedObjectUserCheck(); +} + +BSONElement BSONElement::operator[](const std::string& field) const { + BSONObj o = Obj(); + return o[field]; +} + +int BSONElement::size(int maxLen) const { + if (totalSize >= 0) + return totalSize; - int remain = maxLen - fieldNameSize() - 1; + int remain = maxLen - fieldNameSize() - 1; - int x = 0; - switch ( type() ) { + int x = 0; + switch (type()) { case EOO: case Undefined: case jstNULL: @@ -477,62 +467,66 @@ namespace mongo { case Symbol: case Code: case mongo::String: - massert( 10313 , "Insufficient bytes to calculate element size", maxLen == -1 || remain > 3 ); + massert( + 10313, "Insufficient bytes to calculate element size", maxLen == -1 || remain > 3); x = valuestrsize() + 4; break; case CodeWScope: - massert( 10314 , "Insufficient bytes to calculate element size", maxLen == -1 || remain > 3 ); + massert( + 10314, "Insufficient bytes to calculate element size", maxLen == -1 || remain > 3); x = objsize(); break; case DBRef: - massert( 10315 , "Insufficient bytes to calculate element size", maxLen == -1 || remain > 3 ); + massert( + 10315, "Insufficient bytes to calculate element size", maxLen == -1 || remain > 3); x = valuestrsize() + 4 + 12; break; case Object: case mongo::Array: - massert( 10316 , "Insufficient bytes to calculate element size", maxLen == -1 || remain > 3 ); + massert( + 10316, "Insufficient bytes to calculate element size", maxLen == -1 || remain > 3); x = objsize(); break; case BinData: - massert( 10317 , "Insufficient bytes to calculate element size", maxLen == -1 || remain > 3 ); - x = valuestrsize() + 4 + 1/*subtype*/; + massert( + 10317, "Insufficient bytes to calculate element size", maxLen == -1 || remain > 3); + x = valuestrsize() + 4 + 1 /*subtype*/; break; case RegEx: { - const char *p = value(); - size_t len1 = ( maxLen == -1 ) ? strlen( p ) : strnlen( p, remain ); - massert( 10318 , "Invalid regex string", maxLen == -1 || len1 < size_t(remain) ); + const char* p = value(); + size_t len1 = (maxLen == -1) ? strlen(p) : strnlen(p, remain); + massert(10318, "Invalid regex string", maxLen == -1 || len1 < size_t(remain)); p = p + len1 + 1; size_t len2; - if( maxLen == -1 ) - len2 = strlen( p ); + if (maxLen == -1) + len2 = strlen(p); else { size_t x = remain - len1 - 1; - verify( x <= 0x7fffffff ); - len2 = strnlen( p, x ); - massert( 10319 , "Invalid regex options string", len2 < x ); + verify(x <= 0x7fffffff); + len2 = strnlen(p, x); + massert(10319, "Invalid regex options string", len2 < x); } - x = (int) (len1 + 1 + len2 + 1); - } - break; + x = (int)(len1 + 1 + len2 + 1); + } break; default: { StringBuilder ss; - ss << "BSONElement: bad type " << (int) type(); + ss << "BSONElement: bad type " << (int)type(); std::string msg = ss.str(); - massert( 13655 , msg.c_str(),false); - } + massert(13655, msg.c_str(), false); } - totalSize = x + fieldNameSize() + 1; // BSONType - - return totalSize; } + totalSize = x + fieldNameSize() + 1; // BSONType - int BSONElement::size() const { - if ( totalSize >= 0 ) - return totalSize; + return totalSize; +} - int x = 0; - switch ( type() ) { +int BSONElement::size() const { + if (totalSize >= 0) + return totalSize; + + int x = 0; + switch (type()) { case EOO: case Undefined: case jstNULL: @@ -568,54 +562,50 @@ namespace mongo { x = objsize(); break; case BinData: - x = valuestrsize() + 4 + 1/*subtype*/; - break; - case RegEx: - { - const char *p = value(); - size_t len1 = strlen(p); - p = p + len1 + 1; - size_t len2; - len2 = strlen( p ); - x = (int) (len1 + 1 + len2 + 1); - } + x = valuestrsize() + 4 + 1 /*subtype*/; break; - default: - { - StringBuilder ss; - ss << "BSONElement: bad type " << (int) type(); - std::string msg = ss.str(); - massert(10320 , msg.c_str(),false); - } + case RegEx: { + const char* p = value(); + size_t len1 = strlen(p); + p = p + len1 + 1; + size_t len2; + len2 = strlen(p); + x = (int)(len1 + 1 + len2 + 1); + } break; + default: { + StringBuilder ss; + ss << "BSONElement: bad type " << (int)type(); + std::string msg = ss.str(); + massert(10320, msg.c_str(), false); } - totalSize = x + fieldNameSize() + 1; // BSONType - - return totalSize; } - - std::string BSONElement::toString( bool includeFieldName, bool full ) const { - StringBuilder s; - toString(s, includeFieldName, full); - return s.str(); - } - - void BSONElement::toString( StringBuilder& s, bool includeFieldName, bool full, int depth ) const { - - if ( depth > BSONObj::maxToStringRecursionDepth ) { - // check if we want the full/complete string - if ( full ) { - StringBuilder s; - s << "Reached maximum recursion depth of "; - s << BSONObj::maxToStringRecursionDepth; - uassert(16150, s.str(), full != true); - } - s << "..."; - return; + totalSize = x + fieldNameSize() + 1; // BSONType + + return totalSize; +} + +std::string BSONElement::toString(bool includeFieldName, bool full) const { + StringBuilder s; + toString(s, includeFieldName, full); + return s.str(); +} + +void BSONElement::toString(StringBuilder& s, bool includeFieldName, bool full, int depth) const { + if (depth > BSONObj::maxToStringRecursionDepth) { + // check if we want the full/complete string + if (full) { + StringBuilder s; + s << "Reached maximum recursion depth of "; + s << BSONObj::maxToStringRecursionDepth; + uassert(16150, s.str(), full != true); } + s << "..."; + return; + } - if ( includeFieldName && type() != EOO ) - s << fieldName() << ": "; - switch ( type() ) { + if (includeFieldName && type() != EOO) + s << fieldName() << ": "; + switch (type()) { case EOO: s << "EOO"; break; @@ -624,12 +614,12 @@ namespace mongo { break; case RegEx: { s << "/" << regex() << '/'; - const char *p = regexFlags(); - if ( p ) s << p; - } - break; + const char* p = regexFlags(); + if (p) + s << p; + } break; case NumberDouble: - s.appendDoubleNice( number() ); + s.appendDoubleNice(number()); break; case NumberLong: s << _numberLong(); @@ -638,13 +628,13 @@ namespace mongo { s << _numberInt(); break; case mongo::Bool: - s << ( boolean() ? "true" : "false" ); + s << (boolean() ? "true" : "false"); break; case Object: - embeddedObject().toString(s, false, full, depth+1); + embeddedObject().toString(s, false, full, depth + 1); break; case mongo::Array: - embeddedObject().toString(s, true, full, depth+1); + embeddedObject().toString(s, true, full, depth + 1); break; case Undefined: s << "undefined"; @@ -659,27 +649,25 @@ namespace mongo { s << "MinKey"; break; case CodeWScope: - s << "CodeWScope( " - << codeWScopeCode() << ", " << codeWScopeObject().toString(false, full) << ")"; + s << "CodeWScope( " << codeWScopeCode() << ", " + << codeWScopeObject().toString(false, full) << ")"; break; case Code: - if ( !full && valuestrsize() > 80 ) { + if (!full && valuestrsize() > 80) { s.write(valuestr(), 70); s << "..."; - } - else { - s.write(valuestr(), valuestrsize()-1); + } else { + s.write(valuestr(), valuestrsize() - 1); } break; case Symbol: case mongo::String: s << '"'; - if ( !full && valuestrsize() > 160 ) { + if (!full && valuestrsize() > 160) { s.write(valuestr(), 150); s << "...\""; - } - else { - s.write(valuestr(), valuestrsize()-1); + } else { + s.write(valuestr(), valuestrsize() - 1); s << '"'; } break; @@ -695,11 +683,10 @@ namespace mongo { s << "BinData(" << binDataType() << ", "; { int len; - const char *data = binDataClean(len); - if ( !full && len > 80 ) { + const char* data = binDataClean(len); + if (!full && len > 80) { s << toHex(data, 70) << "...)"; - } - else { + } else { s << toHex(data, len) << ")"; } } @@ -710,89 +697,96 @@ namespace mongo { default: s << "?type=" << type(); break; - } } +} - std::string BSONElement::_asCode() const { - switch( type() ) { +std::string BSONElement::_asCode() const { + switch (type()) { case mongo::String: case Code: - return std::string(valuestr(), valuestrsize()-1); + return std::string(valuestr(), valuestrsize() - 1); case CodeWScope: return std::string(codeWScopeCode(), ConstDataView(valuestr()).read<LittleEndian<int>>() - 1); default: log() << "can't convert type: " << (int)(type()) << " to code" << std::endl; - } - uassert( 10062 , "not code" , 0 ); - return ""; - } - - std::ostream& operator<<( std::ostream &s, const BSONElement &e ) { - return s << e.toString(); - } - - StringBuilder& operator<<( StringBuilder &s, const BSONElement &e ) { - e.toString( s ); - return s; } - - template<> bool BSONElement::coerce<std::string>( std::string* out ) const { - if ( type() != mongo::String ) + uassert(10062, "not code", 0); + return ""; +} + +std::ostream& operator<<(std::ostream& s, const BSONElement& e) { + return s << e.toString(); +} + +StringBuilder& operator<<(StringBuilder& s, const BSONElement& e) { + e.toString(s); + return s; +} + +template <> +bool BSONElement::coerce<std::string>(std::string* out) const { + if (type() != mongo::String) + return false; + *out = String(); + return true; +} + +template <> +bool BSONElement::coerce<int>(int* out) const { + if (!isNumber()) + return false; + *out = numberInt(); + return true; +} + +template <> +bool BSONElement::coerce<long long>(long long* out) const { + if (!isNumber()) + return false; + *out = numberLong(); + return true; +} + +template <> +bool BSONElement::coerce<double>(double* out) const { + if (!isNumber()) + return false; + *out = numberDouble(); + return true; +} + +template <> +bool BSONElement::coerce<bool>(bool* out) const { + *out = trueValue(); + return true; +} + +template <> +bool BSONElement::coerce<std::vector<std::string>>(std::vector<std::string>* out) const { + if (type() != mongo::Array) + return false; + return Obj().coerceVector<std::string>(out); +} + +template <typename T> +bool BSONObj::coerceVector(std::vector<T>* out) const { + BSONObjIterator i(*this); + while (i.more()) { + BSONElement e = i.next(); + T t; + if (!e.coerce<T>(&t)) return false; - *out = String(); - return true; + out->push_back(t); } - - template<> bool BSONElement::coerce<int>( int* out ) const { - if ( !isNumber() ) - return false; - *out = numberInt(); - return true; - } - - template<> bool BSONElement::coerce<long long>( long long* out ) const { - if ( !isNumber() ) - return false; - *out = numberLong(); - return true; - } - - template<> bool BSONElement::coerce<double>( double* out ) const { - if ( !isNumber() ) - return false; - *out = numberDouble(); - return true; - } - - template<> bool BSONElement::coerce<bool>( bool* out ) const { - *out = trueValue(); - return true; - } - - template<> bool BSONElement::coerce< std::vector<std::string> >( std::vector<std::string>* out ) const { - if ( type() != mongo::Array ) - return false; - return Obj().coerceVector<std::string>( out ); - } - - template<typename T> bool BSONObj::coerceVector( std::vector<T>* out ) const { - BSONObjIterator i( *this ); - while ( i.more() ) { - BSONElement e = i.next(); - T t; - if ( ! e.coerce<T>( &t ) ) - return false; - out->push_back( t ); - } - return true; - } - - // used by jsonString() - std::string escape( const std::string& s , bool escape_slash) { - StringBuilder ret; - for ( std::string::const_iterator i = s.begin(); i != s.end(); ++i ) { - switch ( *i ) { + return true; +} + +// used by jsonString() +std::string escape(const std::string& s, bool escape_slash) { + StringBuilder ret; + for (std::string::const_iterator i = s.begin(); i != s.end(); ++i) { + switch (*i) { case '"': ret << "\\\""; break; @@ -818,39 +812,39 @@ namespace mongo { ret << "\\t"; break; default: - if ( *i >= 0 && *i <= 0x1f ) { - //TODO: these should be utf16 code-units not bytes + if (*i >= 0 && *i <= 0x1f) { + // TODO: these should be utf16 code-units not bytes char c = *i; ret << "\\u00" << toHexLower(&c, 1); - } - else { + } else { ret << *i; } - } } - return ret.str(); } + return ret.str(); +} - /** - * l and r must be same canonicalType when called. - */ - int compareElementValues(const BSONElement& l, const BSONElement& r) { - int f; +/** + * l and r must be same canonicalType when called. + */ +int compareElementValues(const BSONElement& l, const BSONElement& r) { + int f; - switch ( l.type() ) { + switch (l.type()) { case EOO: - case Undefined: // EOO and Undefined are same canonicalType + case Undefined: // EOO and Undefined are same canonicalType case jstNULL: case MaxKey: case MinKey: f = l.canonicalType() - r.canonicalType(); - if ( f<0 ) return -1; - return f==0 ? 0 : 1; + if (f < 0) + return -1; + return f == 0 ? 0 : 1; case Bool: return *l.value() - *r.value(); case bsonTimestamp: // unsigned compare for timestamps - note they are not really dates but (ordinal + time_t) - if ( l.date() < r.date() ) + if (l.date() < r.date()) return -1; return l.date() == r.date() ? 0 : 1; case Date: @@ -858,7 +852,7 @@ namespace mongo { { const Date_t a = l.Date(); const Date_t b = r.Date(); - if( a < b ) + if (a < b) return -1; return a == b ? 0 : 1; } @@ -867,28 +861,40 @@ namespace mongo { // All types can precisely represent all NumberInts, so it is safe to simply convert to // whatever rhs's type is. switch (r.type()) { - case NumberInt: return compareInts(l._numberInt(), r._numberInt()); - case NumberLong: return compareLongs(l._numberInt(), r._numberLong()); - case NumberDouble: return compareDoubles(l._numberInt(), r._numberDouble()); - default: invariant(false); + case NumberInt: + return compareInts(l._numberInt(), r._numberInt()); + case NumberLong: + return compareLongs(l._numberInt(), r._numberLong()); + case NumberDouble: + return compareDoubles(l._numberInt(), r._numberDouble()); + default: + invariant(false); } } case NumberLong: { switch (r.type()) { - case NumberLong: return compareLongs(l._numberLong(), r._numberLong()); - case NumberInt: return compareLongs(l._numberLong(), r._numberInt()); - case NumberDouble: return compareLongToDouble(l._numberLong(), r._numberDouble()); - default: invariant(false); + case NumberLong: + return compareLongs(l._numberLong(), r._numberLong()); + case NumberInt: + return compareLongs(l._numberLong(), r._numberInt()); + case NumberDouble: + return compareLongToDouble(l._numberLong(), r._numberDouble()); + default: + invariant(false); } } case NumberDouble: { switch (r.type()) { - case NumberDouble: return compareDoubles(l._numberDouble(), r._numberDouble()); - case NumberInt: return compareDoubles(l._numberDouble(), r._numberInt()); - case NumberLong: return compareDoubleToLong(l._numberDouble(), r._numberLong()); - default: invariant(false); + case NumberDouble: + return compareDoubles(l._numberDouble(), r._numberDouble()); + case NumberInt: + return compareDoubles(l._numberDouble(), r._numberInt()); + case NumberLong: + return compareDoubleToLong(l._numberDouble(), r._numberLong()); + default: + invariant(false); } } @@ -904,57 +910,60 @@ namespace mongo { int rsz = r.valuestrsize(); int common = std::min(lsz, rsz); int res = memcmp(l.valuestr(), r.valuestr(), common); - if( res ) + if (res) return res; // longer std::string is the greater one - return lsz-rsz; + return lsz - rsz; } case Object: case Array: - return l.embeddedObject().woCompare( r.embeddedObject() ); + return l.embeddedObject().woCompare(r.embeddedObject()); case DBRef: { int lsz = l.valuesize(); int rsz = r.valuesize(); - if ( lsz - rsz != 0 ) return lsz - rsz; + if (lsz - rsz != 0) + return lsz - rsz; return memcmp(l.value(), r.value(), lsz); } case BinData: { - int lsz = l.objsize(); // our bin data size in bytes, not including the subtype byte + int lsz = l.objsize(); // our bin data size in bytes, not including the subtype byte int rsz = r.objsize(); - if ( lsz - rsz != 0 ) return lsz - rsz; - return memcmp(l.value()+4, r.value()+4, lsz+1 /*+1 for subtype byte*/); + if (lsz - rsz != 0) + return lsz - rsz; + return memcmp(l.value() + 4, r.value() + 4, lsz + 1 /*+1 for subtype byte*/); } case RegEx: { int c = strcmp(l.regex(), r.regex()); - if ( c ) + if (c) return c; return strcmp(l.regexFlags(), r.regexFlags()); } - case CodeWScope : { - int cmp = StringData(l.codeWScopeCode(), l.codeWScopeCodeLen() - 1).compare( - StringData(r.codeWScopeCode(), r.codeWScopeCodeLen() - 1)); - if (cmp) return cmp; + case CodeWScope: { + int cmp = StringData(l.codeWScopeCode(), l.codeWScopeCodeLen() - 1) + .compare(StringData(r.codeWScopeCode(), r.codeWScopeCodeLen() - 1)); + if (cmp) + return cmp; return l.codeWScopeObject().woCompare(r.codeWScopeObject()); } default: - verify( false); - } - return -1; + verify(false); } - - size_t BSONElement::Hasher::operator()(const BSONElement& elem) const { - size_t hash = 0; + return -1; +} - boost::hash_combine(hash, elem.canonicalType()); +size_t BSONElement::Hasher::operator()(const BSONElement& elem) const { + size_t hash = 0; - const StringData fieldName = elem.fieldNameStringData(); - if (!fieldName.empty()) { - boost::hash_combine(hash, StringData::Hasher()(fieldName)); - } + boost::hash_combine(hash, elem.canonicalType()); + + const StringData fieldName = elem.fieldNameStringData(); + if (!fieldName.empty()) { + boost::hash_combine(hash, StringData::Hasher()(fieldName)); + } - switch (elem.type()) { - // Order of types is the same as in compareElementValues(). + switch (elem.type()) { + // Order of types is the same as in compareElementValues(). case mongo::EOO: case mongo::Undefined: @@ -986,8 +995,7 @@ namespace mongo { const double dbl = elem.numberDouble(); if (std::isnan(dbl)) { boost::hash_combine(hash, std::numeric_limits<double>::quiet_NaN()); - } - else { + } else { boost::hash_combine(hash, dbl); } break; @@ -1011,8 +1019,8 @@ namespace mongo { case mongo::DBRef: case mongo::BinData: // All bytes of the value are required to be identical. - boost::hash_combine(hash, StringData::Hasher()(StringData(elem.value(), - elem.valuesize()))); + boost::hash_combine(hash, + StringData::Hasher()(StringData(elem.value(), elem.valuesize()))); break; case mongo::RegEx: @@ -1021,14 +1029,14 @@ namespace mongo { break; case mongo::CodeWScope: { - boost::hash_combine(hash, StringData::Hasher()( - StringData(elem.codeWScopeCode(), - elem.codeWScopeCodeLen()))); + boost::hash_combine( + hash, + StringData::Hasher()(StringData(elem.codeWScopeCode(), elem.codeWScopeCodeLen()))); boost::hash_combine(hash, BSONObj::Hasher()(elem.codeWScopeObject())); break; } - } - return hash; } + return hash; +} -} // namespace mongo +} // namespace mongo |