|
MongoDB
2.0.3
|
00001 00006 /* Copyright 2009 10gen Inc. 00007 * 00008 * Licensed under the Apache License, Version 2.0 (the "License"); 00009 * you may not use this file except in compliance with the License. 00010 * You may obtain a copy of the License at 00011 * 00012 * http://www.apache.org/licenses/LICENSE-2.0 00013 * 00014 * Unless required by applicable law or agreed to in writing, software 00015 * distributed under the License is distributed on an "AS IS" BASIS, 00016 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00017 * See the License for the specific language governing permissions and 00018 * limitations under the License. 00019 */ 00020 00021 #pragma once 00022 00023 #include <map> 00024 #include <limits> 00025 00026 #if defined(_WIN32) 00027 #undef max 00028 #undef min 00029 #endif 00030 00031 namespace mongo { 00032 00033 inline bool isNaN(double d) { 00034 return d != d; 00035 } 00036 00037 /* must be same type when called, unless both sides are #s 00038 this large function is in header to facilitate inline-only use of bson 00039 */ 00040 inline int compareElementValues(const BSONElement& l, const BSONElement& r) { 00041 int f; 00042 00043 switch ( l.type() ) { 00044 case EOO: 00045 case Undefined: // EOO and Undefined are same canonicalType 00046 case jstNULL: 00047 case MaxKey: 00048 case MinKey: 00049 f = l.canonicalType() - r.canonicalType(); 00050 if ( f<0 ) return -1; 00051 return f==0 ? 0 : 1; 00052 case Bool: 00053 return *l.value() - *r.value(); 00054 case Timestamp: 00055 // unsigned compare for timestamps - note they are not really dates but (ordinal + time_t) 00056 if ( l.date() < r.date() ) 00057 return -1; 00058 return l.date() == r.date() ? 0 : 1; 00059 case Date: 00060 { 00061 long long a = (long long) l.Date().millis; 00062 long long b = (long long) r.Date().millis; 00063 if( a < b ) 00064 return -1; 00065 return a == b ? 0 : 1; 00066 } 00067 case NumberLong: 00068 if( r.type() == NumberLong ) { 00069 long long L = l._numberLong(); 00070 long long R = r._numberLong(); 00071 if( L < R ) return -1; 00072 if( L == R ) return 0; 00073 return 1; 00074 } 00075 goto dodouble; 00076 case NumberInt: 00077 if( r.type() == NumberInt ) { 00078 int L = l._numberInt(); 00079 int R = r._numberInt(); 00080 if( L < R ) return -1; 00081 return L == R ? 0 : 1; 00082 } 00083 // else fall through 00084 case NumberDouble: 00085 dodouble: 00086 { 00087 double left = l.number(); 00088 double right = r.number(); 00089 if( left < right ) 00090 return -1; 00091 if( left == right ) 00092 return 0; 00093 if( isNaN(left) ) 00094 return isNaN(right) ? 0 : -1; 00095 return 1; 00096 } 00097 case jstOID: 00098 return memcmp(l.value(), r.value(), 12); 00099 case Code: 00100 case Symbol: 00101 case String: 00102 /* todo: a utf sort order version one day... */ 00103 { 00104 // we use memcmp as we allow zeros in UTF8 strings 00105 int lsz = l.valuestrsize(); 00106 int rsz = r.valuestrsize(); 00107 int common = min(lsz, rsz); 00108 int res = memcmp(l.valuestr(), r.valuestr(), common); 00109 if( res ) 00110 return res; 00111 // longer string is the greater one 00112 return lsz-rsz; 00113 } 00114 case Object: 00115 case Array: 00116 return l.embeddedObject().woCompare( r.embeddedObject() ); 00117 case DBRef: { 00118 int lsz = l.valuesize(); 00119 int rsz = r.valuesize(); 00120 if ( lsz - rsz != 0 ) return lsz - rsz; 00121 return memcmp(l.value(), r.value(), lsz); 00122 } 00123 case BinData: { 00124 int lsz = l.objsize(); // our bin data size in bytes, not including the subtype byte 00125 int rsz = r.objsize(); 00126 if ( lsz - rsz != 0 ) return lsz - rsz; 00127 return memcmp(l.value()+4, r.value()+4, lsz+1); 00128 } 00129 case RegEx: { 00130 int c = strcmp(l.regex(), r.regex()); 00131 if ( c ) 00132 return c; 00133 return strcmp(l.regexFlags(), r.regexFlags()); 00134 } 00135 case CodeWScope : { 00136 f = l.canonicalType() - r.canonicalType(); 00137 if ( f ) 00138 return f; 00139 f = strcmp( l.codeWScopeCode() , r.codeWScopeCode() ); 00140 if ( f ) 00141 return f; 00142 f = strcmp( l.codeWScopeScopeData() , r.codeWScopeScopeData() ); 00143 if ( f ) 00144 return f; 00145 return 0; 00146 } 00147 default: 00148 assert( false); 00149 } 00150 return -1; 00151 } 00152 00153 /* wo = "well ordered" */ 00154 inline int BSONElement::woCompare( const BSONElement &e, 00155 bool considerFieldName ) const { 00156 int lt = (int) canonicalType(); 00157 int rt = (int) e.canonicalType(); 00158 int x = lt - rt; 00159 if( x != 0 && (!isNumber() || !e.isNumber()) ) 00160 return x; 00161 if ( considerFieldName ) { 00162 x = strcmp(fieldName(), e.fieldName()); 00163 if ( x != 0 ) 00164 return x; 00165 } 00166 x = compareElementValues(*this, e); 00167 return x; 00168 } 00169 00170 inline BSONObjIterator BSONObj::begin() const { 00171 return BSONObjIterator(*this); 00172 } 00173 00174 inline BSONObj BSONElement::embeddedObjectUserCheck() const { 00175 if ( MONGO_likely(isABSONObj()) ) 00176 return BSONObj(value()); 00177 stringstream ss; 00178 ss << "invalid parameter: expected an object (" << fieldName() << ")"; 00179 uasserted( 10065 , ss.str() ); 00180 return BSONObj(); // never reachable 00181 } 00182 00183 inline BSONObj BSONElement::embeddedObject() const { 00184 assert( isABSONObj() ); 00185 return BSONObj(value()); 00186 } 00187 00188 inline BSONObj BSONElement::codeWScopeObject() const { 00189 assert( type() == CodeWScope ); 00190 int strSizeWNull = *(int *)( value() + 4 ); 00191 return BSONObj( value() + 4 + 4 + strSizeWNull ); 00192 } 00193 00194 // deep (full) equality 00195 inline bool BSONObj::equal(const BSONObj &rhs) const { 00196 BSONObjIterator i(*this); 00197 BSONObjIterator j(rhs); 00198 BSONElement l,r; 00199 do { 00200 // so far, equal... 00201 l = i.next(); 00202 r = j.next(); 00203 if ( l.eoo() ) 00204 return r.eoo(); 00205 } while( l == r ); 00206 return false; 00207 } 00208 00209 inline NOINLINE_DECL void BSONObj::_assertInvalid() const { 00210 StringBuilder ss; 00211 int os = objsize(); 00212 ss << "Invalid BSONObj size: " << os << " (0x" << toHex( &os, 4 ) << ')'; 00213 try { 00214 BSONElement e = firstElement(); 00215 ss << " first element: " << e.toString(); 00216 } 00217 catch ( ... ) { } 00218 massert( 10334 , ss.str() , 0 ); 00219 } 00220 00221 /* the idea with NOINLINE_DECL here is to keep this from inlining in the 00222 getOwned() method. the presumption being that is better. 00223 */ 00224 inline NOINLINE_DECL BSONObj BSONObj::copy() const { 00225 Holder *h = (Holder*) malloc(objsize() + sizeof(unsigned)); 00226 h->zero(); 00227 memcpy(h->data, objdata(), objsize()); 00228 return BSONObj(h); 00229 } 00230 00231 inline BSONObj BSONObj::getOwned() const { 00232 if ( isOwned() ) 00233 return *this; 00234 return copy(); 00235 } 00236 00237 // wrap this element up as a singleton object. 00238 inline BSONObj BSONElement::wrap() const { 00239 BSONObjBuilder b(size()+6); 00240 b.append(*this); 00241 return b.obj(); 00242 } 00243 00244 inline BSONObj BSONElement::wrap( const char * newName ) const { 00245 BSONObjBuilder b(size()+6+(int)strlen(newName)); 00246 b.appendAs(*this,newName); 00247 return b.obj(); 00248 } 00249 00250 inline void BSONObj::getFields(unsigned n, const char **fieldNames, BSONElement *fields) const { 00251 BSONObjIterator i(*this); 00252 while ( i.more() ) { 00253 BSONElement e = i.next(); 00254 const char *p = e.fieldName(); 00255 for( unsigned i = 0; i < n; i++ ) { 00256 if( strcmp(p, fieldNames[i]) == 0 ) { 00257 fields[i] = e; 00258 break; 00259 } 00260 } 00261 } 00262 } 00263 00264 inline BSONElement BSONObj::getField(const StringData& name) const { 00265 BSONObjIterator i(*this); 00266 while ( i.more() ) { 00267 BSONElement e = i.next(); 00268 if ( strcmp(e.fieldName(), name.data()) == 0 ) 00269 return e; 00270 } 00271 return BSONElement(); 00272 } 00273 00274 inline int BSONObj::getIntField(const char *name) const { 00275 BSONElement e = getField(name); 00276 return e.isNumber() ? (int) e.number() : std::numeric_limits< int >::min(); 00277 } 00278 00279 inline bool BSONObj::getBoolField(const char *name) const { 00280 BSONElement e = getField(name); 00281 return e.type() == Bool ? e.boolean() : false; 00282 } 00283 00284 inline const char * BSONObj::getStringField(const char *name) const { 00285 BSONElement e = getField(name); 00286 return e.type() == String ? e.valuestr() : ""; 00287 } 00288 00289 /* add all the fields from the object specified to this object */ 00290 inline BSONObjBuilder& BSONObjBuilder::appendElements(BSONObj x) { 00291 BSONObjIterator it(x); 00292 while ( it.moreWithEOO() ) { 00293 BSONElement e = it.next(); 00294 if ( e.eoo() ) break; 00295 append(e); 00296 } 00297 return *this; 00298 } 00299 00300 /* add all the fields from the object specified to this object if they don't exist */ 00301 inline BSONObjBuilder& BSONObjBuilder::appendElementsUnique(BSONObj x) { 00302 set<string> have; 00303 { 00304 BSONObjIterator i = iterator(); 00305 while ( i.more() ) 00306 have.insert( i.next().fieldName() ); 00307 } 00308 00309 BSONObjIterator it(x); 00310 while ( it.more() ) { 00311 BSONElement e = it.next(); 00312 if ( have.count( e.fieldName() ) ) 00313 continue; 00314 append(e); 00315 } 00316 return *this; 00317 } 00318 00319 00320 inline bool BSONObj::isValid() const { 00321 int x = objsize(); 00322 return x > 0 && x <= BSONObjMaxInternalSize; 00323 } 00324 00325 inline bool BSONObj::getObjectID(BSONElement& e) const { 00326 BSONElement f = getField("_id"); 00327 if( !f.eoo() ) { 00328 e = f; 00329 return true; 00330 } 00331 return false; 00332 } 00333 00334 inline BSONObjBuilderValueStream::BSONObjBuilderValueStream( BSONObjBuilder * builder ) { 00335 _fieldName = 0; 00336 _builder = builder; 00337 } 00338 00339 template<class T> 00340 inline BSONObjBuilder& BSONObjBuilderValueStream::operator<<( T value ) { 00341 _builder->append(_fieldName, value); 00342 _fieldName = 0; 00343 return *_builder; 00344 } 00345 00346 inline BSONObjBuilder& BSONObjBuilderValueStream::operator<<( const BSONElement& e ) { 00347 _builder->appendAs( e , _fieldName ); 00348 _fieldName = 0; 00349 return *_builder; 00350 } 00351 00352 inline Labeler BSONObjBuilderValueStream::operator<<( const Labeler::Label &l ) { 00353 return Labeler( l, this ); 00354 } 00355 00356 inline void BSONObjBuilderValueStream::endField( const char *nextFieldName ) { 00357 if ( _fieldName && haveSubobj() ) { 00358 _builder->append( _fieldName, subobj()->done() ); 00359 } 00360 _subobj.reset(); 00361 _fieldName = nextFieldName; 00362 } 00363 00364 inline BSONObjBuilder *BSONObjBuilderValueStream::subobj() { 00365 if ( !haveSubobj() ) 00366 _subobj.reset( new BSONObjBuilder() ); 00367 return _subobj.get(); 00368 } 00369 00370 template<class T> inline 00371 BSONObjBuilder& Labeler::operator<<( T value ) { 00372 s_->subobj()->append( l_.l_, value ); 00373 return *s_->_builder; 00374 } 00375 00376 inline 00377 BSONObjBuilder& Labeler::operator<<( const BSONElement& e ) { 00378 s_->subobj()->appendAs( e, l_.l_ ); 00379 return *s_->_builder; 00380 } 00381 00382 // {a: {b:1}} -> {a.b:1} 00383 void nested2dotted(BSONObjBuilder& b, const BSONObj& obj, const string& base=""); 00384 inline BSONObj nested2dotted(const BSONObj& obj) { 00385 BSONObjBuilder b; 00386 nested2dotted(b, obj); 00387 return b.obj(); 00388 } 00389 00390 // {a.b:1} -> {a: {b:1}} 00391 void dotted2nested(BSONObjBuilder& b, const BSONObj& obj); 00392 inline BSONObj dotted2nested(const BSONObj& obj) { 00393 BSONObjBuilder b; 00394 dotted2nested(b, obj); 00395 return b.obj(); 00396 } 00397 00398 inline BSONObjIterator BSONObjBuilder::iterator() const { 00399 const char * s = _b.buf() + _offset; 00400 const char * e = _b.buf() + _b.len(); 00401 return BSONObjIterator( s , e ); 00402 } 00403 00404 inline bool BSONObjBuilder::hasField( const StringData& name ) const { 00405 BSONObjIterator i = iterator(); 00406 while ( i.more() ) 00407 if ( strcmp( name.data() , i.next().fieldName() ) == 0 ) 00408 return true; 00409 return false; 00410 } 00411 00412 /* WARNING: nested/dotted conversions are not 100% reversible 00413 * nested2dotted(dotted2nested({a.b: {c:1}})) -> {a.b.c: 1} 00414 * also, dotted2nested ignores order 00415 */ 00416 00417 typedef map<string, BSONElement> BSONMap; 00418 inline BSONMap bson2map(const BSONObj& obj) { 00419 BSONMap m; 00420 BSONObjIterator it(obj); 00421 while (it.more()) { 00422 BSONElement e = it.next(); 00423 m[e.fieldName()] = e; 00424 } 00425 return m; 00426 } 00427 00428 struct BSONElementFieldNameCmp { 00429 bool operator()( const BSONElement &l, const BSONElement &r ) const { 00430 return strcmp( l.fieldName() , r.fieldName() ) <= 0; 00431 } 00432 }; 00433 00434 typedef set<BSONElement, BSONElementFieldNameCmp> BSONSortedElements; 00435 inline BSONSortedElements bson2set( const BSONObj& obj ) { 00436 BSONSortedElements s; 00437 BSONObjIterator it(obj); 00438 while ( it.more() ) 00439 s.insert( it.next() ); 00440 return s; 00441 } 00442 00443 inline string BSONObj::toString( bool isArray, bool full ) const { 00444 if ( isEmpty() ) return "{}"; 00445 StringBuilder s; 00446 toString(s, isArray, full); 00447 return s.str(); 00448 } 00449 inline void BSONObj::toString(StringBuilder& s, bool isArray, bool full ) const { 00450 if ( isEmpty() ) { 00451 s << "{}"; 00452 return; 00453 } 00454 00455 s << ( isArray ? "[ " : "{ " ); 00456 BSONObjIterator i(*this); 00457 bool first = true; 00458 while ( 1 ) { 00459 massert( 10327 , "Object does not end with EOO", i.moreWithEOO() ); 00460 BSONElement e = i.next( true ); 00461 massert( 10328 , "Invalid element size", e.size() > 0 ); 00462 massert( 10329 , "Element too large", e.size() < ( 1 << 30 ) ); 00463 int offset = (int) (e.rawdata() - this->objdata()); 00464 massert( 10330 , "Element extends past end of object", 00465 e.size() + offset <= this->objsize() ); 00466 e.validate(); 00467 bool end = ( e.size() + offset == this->objsize() ); 00468 if ( e.eoo() ) { 00469 massert( 10331 , "EOO Before end of object", end ); 00470 break; 00471 } 00472 if ( first ) 00473 first = false; 00474 else 00475 s << ", "; 00476 e.toString(s, !isArray, full ); 00477 } 00478 s << ( isArray ? " ]" : " }" ); 00479 } 00480 00481 inline void BSONElement::validate() const { 00482 const BSONType t = type(); 00483 00484 switch( t ) { 00485 case DBRef: 00486 case Code: 00487 case Symbol: 00488 case mongo::String: { 00489 unsigned x = (unsigned) valuestrsize(); 00490 bool lenOk = x > 0 && x < (unsigned) BSONObjMaxInternalSize; 00491 if( lenOk && valuestr()[x-1] == 0 ) 00492 return; 00493 StringBuilder buf; 00494 buf << "Invalid dbref/code/string/symbol size: " << x; 00495 if( lenOk ) 00496 buf << " strnlen:" << mongo::strnlen( valuestr() , x ); 00497 msgasserted( 10321 , buf.str() ); 00498 break; 00499 } 00500 case CodeWScope: { 00501 int totalSize = *( int * )( value() ); 00502 massert( 10322 , "Invalid CodeWScope size", totalSize >= 8 ); 00503 int strSizeWNull = *( int * )( value() + 4 ); 00504 massert( 10323 , "Invalid CodeWScope string size", totalSize >= strSizeWNull + 4 + 4 ); 00505 massert( 10324 , "Invalid CodeWScope string size", 00506 strSizeWNull > 0 && 00507 (strSizeWNull - 1) == mongo::strnlen( codeWScopeCode(), strSizeWNull ) ); 00508 massert( 10325 , "Invalid CodeWScope size", totalSize >= strSizeWNull + 4 + 4 + 4 ); 00509 int objSize = *( int * )( value() + 4 + 4 + strSizeWNull ); 00510 massert( 10326 , "Invalid CodeWScope object size", totalSize == 4 + 4 + strSizeWNull + objSize ); 00511 // Subobject validation handled elsewhere. 00512 } 00513 case Object: 00514 // We expect Object size validation to be handled elsewhere. 00515 default: 00516 break; 00517 } 00518 } 00519 00520 inline int BSONElement::size( int maxLen ) const { 00521 if ( totalSize >= 0 ) 00522 return totalSize; 00523 00524 int remain = maxLen - fieldNameSize() - 1; 00525 00526 int x = 0; 00527 switch ( type() ) { 00528 case EOO: 00529 case Undefined: 00530 case jstNULL: 00531 case MaxKey: 00532 case MinKey: 00533 break; 00534 case mongo::Bool: 00535 x = 1; 00536 break; 00537 case NumberInt: 00538 x = 4; 00539 break; 00540 case Timestamp: 00541 case mongo::Date: 00542 case NumberDouble: 00543 case NumberLong: 00544 x = 8; 00545 break; 00546 case jstOID: 00547 x = 12; 00548 break; 00549 case Symbol: 00550 case Code: 00551 case mongo::String: 00552 massert( 10313 , "Insufficient bytes to calculate element size", maxLen == -1 || remain > 3 ); 00553 x = valuestrsize() + 4; 00554 break; 00555 case CodeWScope: 00556 massert( 10314 , "Insufficient bytes to calculate element size", maxLen == -1 || remain > 3 ); 00557 x = objsize(); 00558 break; 00559 00560 case DBRef: 00561 massert( 10315 , "Insufficient bytes to calculate element size", maxLen == -1 || remain > 3 ); 00562 x = valuestrsize() + 4 + 12; 00563 break; 00564 case Object: 00565 case mongo::Array: 00566 massert( 10316 , "Insufficient bytes to calculate element size", maxLen == -1 || remain > 3 ); 00567 x = objsize(); 00568 break; 00569 case BinData: 00570 massert( 10317 , "Insufficient bytes to calculate element size", maxLen == -1 || remain > 3 ); 00571 x = valuestrsize() + 4 + 1/*subtype*/; 00572 break; 00573 case RegEx: { 00574 const char *p = value(); 00575 size_t len1 = ( maxLen == -1 ) ? strlen( p ) : (size_t)mongo::strnlen( p, remain ); 00576 //massert( 10318 , "Invalid regex string", len1 != -1 ); // ERH - 4/28/10 - don't think this does anything 00577 p = p + len1 + 1; 00578 size_t len2; 00579 if( maxLen == -1 ) 00580 len2 = strlen( p ); 00581 else { 00582 size_t x = remain - len1 - 1; 00583 assert( x <= 0x7fffffff ); 00584 len2 = mongo::strnlen( p, (int) x ); 00585 } 00586 //massert( 10319 , "Invalid regex options string", len2 != -1 ); // ERH - 4/28/10 - don't think this does anything 00587 x = (int) (len1 + 1 + len2 + 1); 00588 } 00589 break; 00590 default: { 00591 StringBuilder ss; 00592 ss << "BSONElement: bad type " << (int) type(); 00593 string msg = ss.str(); 00594 massert( 13655 , msg.c_str(),false); 00595 } 00596 } 00597 totalSize = x + fieldNameSize() + 1; // BSONType 00598 00599 return totalSize; 00600 } 00601 00602 inline int BSONElement::size() const { 00603 if ( totalSize >= 0 ) 00604 return totalSize; 00605 00606 int x = 0; 00607 switch ( type() ) { 00608 case EOO: 00609 case Undefined: 00610 case jstNULL: 00611 case MaxKey: 00612 case MinKey: 00613 break; 00614 case mongo::Bool: 00615 x = 1; 00616 break; 00617 case NumberInt: 00618 x = 4; 00619 break; 00620 case Timestamp: 00621 case mongo::Date: 00622 case NumberDouble: 00623 case NumberLong: 00624 x = 8; 00625 break; 00626 case jstOID: 00627 x = 12; 00628 break; 00629 case Symbol: 00630 case Code: 00631 case mongo::String: 00632 x = valuestrsize() + 4; 00633 break; 00634 case DBRef: 00635 x = valuestrsize() + 4 + 12; 00636 break; 00637 case CodeWScope: 00638 case Object: 00639 case mongo::Array: 00640 x = objsize(); 00641 break; 00642 case BinData: 00643 x = valuestrsize() + 4 + 1/*subtype*/; 00644 break; 00645 case RegEx: 00646 { 00647 const char *p = value(); 00648 size_t len1 = strlen(p); 00649 p = p + len1 + 1; 00650 size_t len2; 00651 len2 = strlen( p ); 00652 x = (int) (len1 + 1 + len2 + 1); 00653 } 00654 break; 00655 default: 00656 { 00657 StringBuilder ss; 00658 ss << "BSONElement: bad type " << (int) type(); 00659 string msg = ss.str(); 00660 massert(10320 , msg.c_str(),false); 00661 } 00662 } 00663 totalSize = x + fieldNameSize() + 1; // BSONType 00664 00665 return totalSize; 00666 } 00667 00668 inline string BSONElement::toString( bool includeFieldName, bool full ) const { 00669 StringBuilder s; 00670 toString(s, includeFieldName, full); 00671 return s.str(); 00672 } 00673 inline void BSONElement::toString(StringBuilder& s, bool includeFieldName, bool full ) const { 00674 if ( includeFieldName && type() != EOO ) 00675 s << fieldName() << ": "; 00676 switch ( type() ) { 00677 case EOO: 00678 s << "EOO"; 00679 break; 00680 case mongo::Date: 00681 s << "new Date(" << (long long) date() << ')'; 00682 break; 00683 case RegEx: { 00684 s << "/" << regex() << '/'; 00685 const char *p = regexFlags(); 00686 if ( p ) s << p; 00687 } 00688 break; 00689 case NumberDouble: 00690 s.appendDoubleNice( number() ); 00691 break; 00692 case NumberLong: 00693 s << _numberLong(); 00694 break; 00695 case NumberInt: 00696 s << _numberInt(); 00697 break; 00698 case mongo::Bool: 00699 s << ( boolean() ? "true" : "false" ); 00700 break; 00701 case Object: 00702 embeddedObject().toString(s, false, full); 00703 break; 00704 case mongo::Array: 00705 embeddedObject().toString(s, true, full); 00706 break; 00707 case Undefined: 00708 s << "undefined"; 00709 break; 00710 case jstNULL: 00711 s << "null"; 00712 break; 00713 case MaxKey: 00714 s << "MaxKey"; 00715 break; 00716 case MinKey: 00717 s << "MinKey"; 00718 break; 00719 case CodeWScope: 00720 s << "CodeWScope( " 00721 << codeWScopeCode() << ", " << codeWScopeObject().toString(false, full) << ")"; 00722 break; 00723 case Code: 00724 if ( !full && valuestrsize() > 80 ) { 00725 s.write(valuestr(), 70); 00726 s << "..."; 00727 } 00728 else { 00729 s.write(valuestr(), valuestrsize()-1); 00730 } 00731 break; 00732 case Symbol: 00733 case mongo::String: 00734 s << '"'; 00735 if ( !full && valuestrsize() > 160 ) { 00736 s.write(valuestr(), 150); 00737 s << "...\""; 00738 } 00739 else { 00740 s.write(valuestr(), valuestrsize()-1); 00741 s << '"'; 00742 } 00743 break; 00744 case DBRef: 00745 s << "DBRef('" << valuestr() << "',"; 00746 { 00747 mongo::OID *x = (mongo::OID *) (valuestr() + valuestrsize()); 00748 s << *x << ')'; 00749 } 00750 break; 00751 case jstOID: 00752 s << "ObjectId('"; 00753 s << __oid() << "')"; 00754 break; 00755 case BinData: 00756 s << "BinData"; 00757 if (full) { 00758 int len; 00759 const char* data = binDataClean(len); 00760 s << '(' << binDataType() << ", " << toHex(data, len) << ')'; 00761 } 00762 break; 00763 case Timestamp: 00764 s << "Timestamp " << timestampTime() << "|" << timestampInc(); 00765 break; 00766 default: 00767 s << "?type=" << type(); 00768 break; 00769 } 00770 } 00771 00772 /* return has eoo() true if no match 00773 supports "." notation to reach into embedded objects 00774 */ 00775 inline BSONElement BSONObj::getFieldDotted(const char *name) const { 00776 BSONElement e = getField( name ); 00777 if ( e.eoo() ) { 00778 const char *p = strchr(name, '.'); 00779 if ( p ) { 00780 string left(name, p-name); 00781 BSONObj sub = getObjectField(left.c_str()); 00782 return sub.isEmpty() ? BSONElement() : sub.getFieldDotted(p+1); 00783 } 00784 } 00785 00786 return e; 00787 } 00788 00789 inline BSONObj BSONObj::getObjectField(const char *name) const { 00790 BSONElement e = getField(name); 00791 BSONType t = e.type(); 00792 return t == Object || t == Array ? e.embeddedObject() : BSONObj(); 00793 } 00794 00795 inline int BSONObj::nFields() const { 00796 int n = 0; 00797 BSONObjIterator i(*this); 00798 while ( i.moreWithEOO() ) { 00799 BSONElement e = i.next(); 00800 if ( e.eoo() ) 00801 break; 00802 n++; 00803 } 00804 return n; 00805 } 00806 00807 inline BSONObj::BSONObj() { 00808 /* little endian ordering here, but perhaps that is ok regardless as BSON is spec'd 00809 to be little endian external to the system. (i.e. the rest of the implementation of bson, 00810 not this part, fails to support big endian) 00811 */ 00812 static char p[] = { /*size*/5, 0, 0, 0, /*eoo*/0 }; 00813 _objdata = p; 00814 } 00815 00816 inline BSONObj BSONElement::Obj() const { return embeddedObjectUserCheck(); } 00817 00818 inline BSONElement BSONElement::operator[] (const string& field) const { 00819 BSONObj o = Obj(); 00820 return o[field]; 00821 } 00822 00823 inline void BSONObj::elems(vector<BSONElement> &v) const { 00824 BSONObjIterator i(*this); 00825 while( i.more() ) 00826 v.push_back(i.next()); 00827 } 00828 00829 inline void BSONObj::elems(list<BSONElement> &v) const { 00830 BSONObjIterator i(*this); 00831 while( i.more() ) 00832 v.push_back(i.next()); 00833 } 00834 00835 template <class T> 00836 void BSONObj::Vals(vector<T>& v) const { 00837 BSONObjIterator i(*this); 00838 while( i.more() ) { 00839 T t; 00840 i.next().Val(t); 00841 v.push_back(t); 00842 } 00843 } 00844 template <class T> 00845 void BSONObj::Vals(list<T>& v) const { 00846 BSONObjIterator i(*this); 00847 while( i.more() ) { 00848 T t; 00849 i.next().Val(t); 00850 v.push_back(t); 00851 } 00852 } 00853 00854 template <class T> 00855 void BSONObj::vals(vector<T>& v) const { 00856 BSONObjIterator i(*this); 00857 while( i.more() ) { 00858 try { 00859 T t; 00860 i.next().Val(t); 00861 v.push_back(t); 00862 } 00863 catch(...) { } 00864 } 00865 } 00866 template <class T> 00867 void BSONObj::vals(list<T>& v) const { 00868 BSONObjIterator i(*this); 00869 while( i.more() ) { 00870 try { 00871 T t; 00872 i.next().Val(t); 00873 v.push_back(t); 00874 } 00875 catch(...) { } 00876 } 00877 } 00878 00879 inline ostream& operator<<( ostream &s, const BSONObj &o ) { 00880 return s << o.toString(); 00881 } 00882 00883 inline ostream& operator<<( ostream &s, const BSONElement &e ) { 00884 return s << e.toString(); 00885 } 00886 00887 inline StringBuilder& operator<<( StringBuilder &s, const BSONObj &o ) { 00888 o.toString( s ); 00889 return s; 00890 } 00891 inline StringBuilder& operator<<( StringBuilder &s, const BSONElement &e ) { 00892 e.toString( s ); 00893 return s; 00894 } 00895 00896 00897 inline void BSONElement::Val(BSONObj& v) const { v = Obj(); } 00898 00899 template<typename T> 00900 inline BSONFieldValue<BSONObj> BSONField<T>::query( const char * q , const T& t ) const { 00901 BSONObjBuilder b; 00902 b.append( q , t ); 00903 return BSONFieldValue<BSONObj>( _name , b.obj() ); 00904 } 00905 00906 // used by jsonString() 00907 inline string escape( string s , bool escape_slash=false) { 00908 StringBuilder ret; 00909 for ( string::iterator i = s.begin(); i != s.end(); ++i ) { 00910 switch ( *i ) { 00911 case '"': 00912 ret << "\\\""; 00913 break; 00914 case '\\': 00915 ret << "\\\\"; 00916 break; 00917 case '/': 00918 ret << (escape_slash ? "\\/" : "/"); 00919 break; 00920 case '\b': 00921 ret << "\\b"; 00922 break; 00923 case '\f': 00924 ret << "\\f"; 00925 break; 00926 case '\n': 00927 ret << "\\n"; 00928 break; 00929 case '\r': 00930 ret << "\\r"; 00931 break; 00932 case '\t': 00933 ret << "\\t"; 00934 break; 00935 default: 00936 if ( *i >= 0 && *i <= 0x1f ) { 00937 //TODO: these should be utf16 code-units not bytes 00938 char c = *i; 00939 ret << "\\u00" << toHexLower(&c, 1); 00940 } 00941 else { 00942 ret << *i; 00943 } 00944 } 00945 } 00946 return ret.str(); 00947 } 00948 00949 inline string BSONObj::hexDump() const { 00950 stringstream ss; 00951 const char *d = objdata(); 00952 int size = objsize(); 00953 for( int i = 0; i < size; ++i ) { 00954 ss.width( 2 ); 00955 ss.fill( '0' ); 00956 ss << hex << (unsigned)(unsigned char)( d[ i ] ) << dec; 00957 if ( ( d[ i ] >= '0' && d[ i ] <= '9' ) || ( d[ i ] >= 'A' && d[ i ] <= 'z' ) ) 00958 ss << '\'' << d[ i ] << '\''; 00959 if ( i != size - 1 ) 00960 ss << ' '; 00961 } 00962 return ss.str(); 00963 } 00964 00965 inline void BSONObjBuilder::appendKeys( const BSONObj& keyPattern , const BSONObj& values ) { 00966 BSONObjIterator i(keyPattern); 00967 BSONObjIterator j(values); 00968 00969 while ( i.more() && j.more() ) { 00970 appendAs( j.next() , i.next().fieldName() ); 00971 } 00972 00973 assert( ! i.more() ); 00974 assert( ! j.more() ); 00975 } 00976 00977 inline BSONObj BSONObj::removeField(const StringData& name) const { 00978 BSONObjBuilder b; 00979 BSONObjIterator i(*this); 00980 while ( i.more() ) { 00981 BSONElement e = i.next(); 00982 const char *fname = e.fieldName(); 00983 if( strcmp(name.data(), fname) ) 00984 b.append(e); 00985 } 00986 return b.obj(); 00987 } 00988 }
1.8.0