MongoDB  2.0.3
bson-inl.h
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 }