summaryrefslogtreecommitdiff
path: root/src/mongo/bson
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/bson')
-rw-r--r--src/mongo/bson/README7
-rw-r--r--src/mongo/bson/bson-inl.h1007
-rw-r--r--src/mongo/bson/bson.h110
-rw-r--r--src/mongo/bson/bson_db.h88
-rw-r--r--src/mongo/bson/bsondemo/bsondemo.cpp113
-rw-r--r--src/mongo/bson/bsondemo/bsondemo.vcproj243
-rw-r--r--src/mongo/bson/bsondemo/bsondemo.vcxproj193
-rw-r--r--src/mongo/bson/bsondemo/bsondemo.vcxproj.filters52
-rw-r--r--src/mongo/bson/bsonelement.h583
-rw-r--r--src/mongo/bson/bsonmisc.h211
-rw-r--r--src/mongo/bson/bsonobj.h497
-rw-r--r--src/mongo/bson/bsonobjbuilder.h842
-rw-r--r--src/mongo/bson/bsonobjiterator.h161
-rw-r--r--src/mongo/bson/bsontypes.h107
-rw-r--r--src/mongo/bson/inline_decls.h68
-rw-r--r--src/mongo/bson/oid.cpp173
-rw-r--r--src/mongo/bson/oid.h138
-rw-r--r--src/mongo/bson/ordering.h73
-rw-r--r--src/mongo/bson/stringdata.h71
-rw-r--r--src/mongo/bson/util/atomic_int.h106
-rw-r--r--src/mongo/bson/util/builder.h322
-rw-r--r--src/mongo/bson/util/misc.h121
22 files changed, 5286 insertions, 0 deletions
diff --git a/src/mongo/bson/README b/src/mongo/bson/README
new file mode 100644
index 00000000000..01ed654bcd2
--- /dev/null
+++ b/src/mongo/bson/README
@@ -0,0 +1,7 @@
+"BSON" stands for "binary JSON" - a binary storage format that is JSON inspired
+(and adds a couple extra types such as Date).
+
+This is the C++ implementation. Implementations which translate BSON<->JSON
+are available for most languages at bsonspec.org.
+
+
diff --git a/src/mongo/bson/bson-inl.h b/src/mongo/bson/bson-inl.h
new file mode 100644
index 00000000000..9e8b3654802
--- /dev/null
+++ b/src/mongo/bson/bson-inl.h
@@ -0,0 +1,1007 @@
+/** @file bsoninlines.h
+ a goal here is that the most common bson methods can be used inline-only, a la boost.
+ thus some things are inline that wouldn't necessarily be otherwise.
+*/
+
+/* Copyright 2009 10gen Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <map>
+#include <limits>
+
+#if defined(_WIN32)
+#undef max
+#undef min
+#endif
+
+namespace mongo {
+
+ inline bool isNaN(double d) {
+ return d != d;
+ }
+
+ inline bool isInf(double d, int* sign = 0) {
+ volatile double tmp = d;
+
+ if ((tmp == d) && ((tmp - d) != 0.0)) {
+ if ( sign ) {
+ *sign = (d < 0.0 ? -1 : 1);
+ }
+ return true;
+ }
+
+ if ( sign ) {
+ *sign = 0;
+ }
+
+ return false;
+ }
+
+ /* must be same type when called, unless both sides are #s
+ this large function is in header to facilitate inline-only use of bson
+ */
+ inline int compareElementValues(const BSONElement& l, const BSONElement& r) {
+ int f;
+
+ switch ( l.type() ) {
+ case EOO:
+ 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;
+ case Bool:
+ return *l.value() - *r.value();
+ case Timestamp:
+ // unsigned compare for timestamps - note they are not really dates but (ordinal + time_t)
+ if ( l.date() < r.date() )
+ return -1;
+ return l.date() == r.date() ? 0 : 1;
+ case Date:
+ {
+ long long a = (long long) l.Date().millis;
+ long long b = (long long) r.Date().millis;
+ if( a < b )
+ return -1;
+ return a == b ? 0 : 1;
+ }
+ case NumberLong:
+ if( r.type() == NumberLong ) {
+ long long L = l._numberLong();
+ long long R = r._numberLong();
+ if( L < R ) return -1;
+ if( L == R ) return 0;
+ return 1;
+ }
+ goto dodouble;
+ case NumberInt:
+ if( r.type() == NumberInt ) {
+ int L = l._numberInt();
+ int R = r._numberInt();
+ if( L < R ) return -1;
+ return L == R ? 0 : 1;
+ }
+ // else fall through
+ case NumberDouble:
+dodouble:
+ {
+ double left = l.number();
+ double right = r.number();
+ if( left < right )
+ return -1;
+ if( left == right )
+ return 0;
+ if( isNaN(left) )
+ return isNaN(right) ? 0 : -1;
+ return 1;
+ }
+ case jstOID:
+ return memcmp(l.value(), r.value(), 12);
+ case Code:
+ case Symbol:
+ case String:
+ /* todo: a utf sort order version one day... */
+ {
+ // we use memcmp as we allow zeros in UTF8 strings
+ int lsz = l.valuestrsize();
+ int rsz = r.valuestrsize();
+ int common = min(lsz, rsz);
+ int res = memcmp(l.valuestr(), r.valuestr(), common);
+ if( res )
+ return res;
+ // longer string is the greater one
+ return lsz-rsz;
+ }
+ case Object:
+ case Array:
+ return l.embeddedObject().woCompare( r.embeddedObject() );
+ case DBRef: {
+ int lsz = l.valuesize();
+ int rsz = r.valuesize();
+ 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 rsz = r.objsize();
+ 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 )
+ return c;
+ return strcmp(l.regexFlags(), r.regexFlags());
+ }
+ case CodeWScope : {
+ f = l.canonicalType() - r.canonicalType();
+ if ( f )
+ return f;
+ f = strcmp( l.codeWScopeCode() , r.codeWScopeCode() );
+ if ( f )
+ return f;
+ f = strcmp( l.codeWScopeScopeData() , r.codeWScopeScopeData() );
+ if ( f )
+ return f;
+ return 0;
+ }
+ default:
+ assert( false);
+ }
+ return -1;
+ }
+
+ /* wo = "well ordered"
+ note: (mongodb related) : this can only change in behavior when index version # changes
+ */
+ inline 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;
+ }
+
+ inline BSONObjIterator BSONObj::begin() const {
+ return BSONObjIterator(*this);
+ }
+
+ inline BSONObj BSONElement::embeddedObjectUserCheck() const {
+ if ( MONGO_likely(isABSONObj()) )
+ return BSONObj(value());
+ stringstream ss;
+ ss << "invalid parameter: expected an object (" << fieldName() << ")";
+ uasserted( 10065 , ss.str() );
+ return BSONObj(); // never reachable
+ }
+
+ inline BSONObj BSONElement::embeddedObject() const {
+ assert( isABSONObj() );
+ return BSONObj(value());
+ }
+
+ inline BSONObj BSONElement::codeWScopeObject() const {
+ assert( type() == CodeWScope );
+ int strSizeWNull = *(int *)( value() + 4 );
+ return BSONObj( value() + 4 + 4 + strSizeWNull );
+ }
+
+ // deep (full) equality
+ inline bool BSONObj::equal(const BSONObj &rhs) const {
+ BSONObjIterator i(*this);
+ BSONObjIterator j(rhs);
+ BSONElement l,r;
+ do {
+ // so far, equal...
+ l = i.next();
+ r = j.next();
+ if ( l.eoo() )
+ return r.eoo();
+ } while( l == r );
+ return false;
+ }
+
+ inline NOINLINE_DECL void BSONObj::_assertInvalid() const {
+ StringBuilder ss;
+ int os = objsize();
+ ss << "Invalid BSONObj size: " << os << " (0x" << toHex( &os, 4 ) << ')';
+ try {
+ BSONElement e = firstElement();
+ ss << " first element: " << e.toString();
+ }
+ catch ( ... ) { }
+ massert( 10334 , ss.str() , 0 );
+ }
+
+ /* the idea with NOINLINE_DECL here is to keep this from inlining in the
+ getOwned() method. the presumption being that is better.
+ */
+ inline NOINLINE_DECL BSONObj BSONObj::copy() const {
+ Holder *h = (Holder*) malloc(objsize() + sizeof(unsigned));
+ h->zero();
+ memcpy(h->data, objdata(), objsize());
+ return BSONObj(h);
+ }
+
+ inline BSONObj BSONObj::getOwned() const {
+ if ( isOwned() )
+ return *this;
+ return copy();
+ }
+
+ // wrap this element up as a singleton object.
+ inline BSONObj BSONElement::wrap() const {
+ BSONObjBuilder b(size()+6);
+ b.append(*this);
+ return b.obj();
+ }
+
+ inline BSONObj BSONElement::wrap( const char * newName ) const {
+ BSONObjBuilder b(size()+6+(int)strlen(newName));
+ b.appendAs(*this,newName);
+ return b.obj();
+ }
+
+ inline void BSONObj::getFields(unsigned n, const char **fieldNames, BSONElement *fields) const {
+ BSONObjIterator i(*this);
+ while ( i.more() ) {
+ BSONElement e = i.next();
+ const char *p = e.fieldName();
+ for( unsigned i = 0; i < n; i++ ) {
+ if( strcmp(p, fieldNames[i]) == 0 ) {
+ fields[i] = e;
+ break;
+ }
+ }
+ }
+ }
+
+ inline BSONElement BSONObj::getField(const StringData& name) const {
+ BSONObjIterator i(*this);
+ while ( i.more() ) {
+ BSONElement e = i.next();
+ if ( strcmp(e.fieldName(), name.data()) == 0 )
+ return e;
+ }
+ return BSONElement();
+ }
+
+ inline int BSONObj::getIntField(const char *name) const {
+ BSONElement e = getField(name);
+ return e.isNumber() ? (int) e.number() : std::numeric_limits< int >::min();
+ }
+
+ inline bool BSONObj::getBoolField(const char *name) const {
+ BSONElement e = getField(name);
+ return e.type() == Bool ? e.boolean() : false;
+ }
+
+ inline const char * BSONObj::getStringField(const char *name) const {
+ BSONElement e = getField(name);
+ return e.type() == String ? e.valuestr() : "";
+ }
+
+ /* add all the fields from the object specified to this object */
+ inline BSONObjBuilder& BSONObjBuilder::appendElements(BSONObj x) {
+ BSONObjIterator it(x);
+ while ( it.moreWithEOO() ) {
+ BSONElement e = it.next();
+ if ( e.eoo() ) break;
+ append(e);
+ }
+ return *this;
+ }
+
+ /* add all the fields from the object specified to this object if they don't exist */
+ inline BSONObjBuilder& BSONObjBuilder::appendElementsUnique(BSONObj x) {
+ set<string> have;
+ {
+ BSONObjIterator i = iterator();
+ while ( i.more() )
+ have.insert( i.next().fieldName() );
+ }
+
+ BSONObjIterator it(x);
+ while ( it.more() ) {
+ BSONElement e = it.next();
+ if ( have.count( e.fieldName() ) )
+ continue;
+ append(e);
+ }
+ return *this;
+ }
+
+
+ inline bool BSONObj::isValid() const {
+ int x = objsize();
+ return x > 0 && x <= BSONObjMaxInternalSize;
+ }
+
+ inline bool BSONObj::getObjectID(BSONElement& e) const {
+ BSONElement f = getField("_id");
+ if( !f.eoo() ) {
+ e = f;
+ return true;
+ }
+ return false;
+ }
+
+ inline BSONObjBuilderValueStream::BSONObjBuilderValueStream( BSONObjBuilder * builder ) {
+ _fieldName = 0;
+ _builder = builder;
+ }
+
+ template<class T>
+ inline BSONObjBuilder& BSONObjBuilderValueStream::operator<<( T value ) {
+ _builder->append(_fieldName, value);
+ _fieldName = 0;
+ return *_builder;
+ }
+
+ inline BSONObjBuilder& BSONObjBuilderValueStream::operator<<( const BSONElement& e ) {
+ _builder->appendAs( e , _fieldName );
+ _fieldName = 0;
+ return *_builder;
+ }
+
+ inline Labeler BSONObjBuilderValueStream::operator<<( const Labeler::Label &l ) {
+ return Labeler( l, this );
+ }
+
+ inline void BSONObjBuilderValueStream::endField( const char *nextFieldName ) {
+ if ( _fieldName && haveSubobj() ) {
+ _builder->append( _fieldName, subobj()->done() );
+ }
+ _subobj.reset();
+ _fieldName = nextFieldName;
+ }
+
+ inline BSONObjBuilder *BSONObjBuilderValueStream::subobj() {
+ if ( !haveSubobj() )
+ _subobj.reset( new BSONObjBuilder() );
+ return _subobj.get();
+ }
+
+ template<class T> inline
+ BSONObjBuilder& Labeler::operator<<( T value ) {
+ s_->subobj()->append( l_.l_, value );
+ return *s_->_builder;
+ }
+
+ inline
+ BSONObjBuilder& Labeler::operator<<( const BSONElement& e ) {
+ s_->subobj()->appendAs( e, l_.l_ );
+ return *s_->_builder;
+ }
+
+ // {a: {b:1}} -> {a.b:1}
+ void nested2dotted(BSONObjBuilder& b, const BSONObj& obj, const string& base="");
+ inline BSONObj nested2dotted(const BSONObj& obj) {
+ BSONObjBuilder b;
+ nested2dotted(b, obj);
+ return b.obj();
+ }
+
+ // {a.b:1} -> {a: {b:1}}
+ void dotted2nested(BSONObjBuilder& b, const BSONObj& obj);
+ inline BSONObj dotted2nested(const BSONObj& obj) {
+ BSONObjBuilder b;
+ dotted2nested(b, obj);
+ return b.obj();
+ }
+
+ inline BSONObjIterator BSONObjBuilder::iterator() const {
+ const char * s = _b.buf() + _offset;
+ const char * e = _b.buf() + _b.len();
+ return BSONObjIterator( s , e );
+ }
+
+ inline bool BSONObjBuilder::hasField( const StringData& name ) const {
+ BSONObjIterator i = iterator();
+ while ( i.more() )
+ if ( strcmp( name.data() , i.next().fieldName() ) == 0 )
+ return true;
+ return false;
+ }
+
+ /* WARNING: nested/dotted conversions are not 100% reversible
+ * nested2dotted(dotted2nested({a.b: {c:1}})) -> {a.b.c: 1}
+ * also, dotted2nested ignores order
+ */
+
+ typedef map<string, BSONElement> BSONMap;
+ inline BSONMap bson2map(const BSONObj& obj) {
+ BSONMap m;
+ BSONObjIterator it(obj);
+ while (it.more()) {
+ BSONElement e = it.next();
+ m[e.fieldName()] = e;
+ }
+ return m;
+ }
+
+ struct BSONElementFieldNameCmp {
+ bool operator()( const BSONElement &l, const BSONElement &r ) const {
+ return strcmp( l.fieldName() , r.fieldName() ) <= 0;
+ }
+ };
+
+ typedef set<BSONElement, BSONElementFieldNameCmp> BSONSortedElements;
+ inline BSONSortedElements bson2set( const BSONObj& obj ) {
+ BSONSortedElements s;
+ BSONObjIterator it(obj);
+ while ( it.more() )
+ s.insert( it.next() );
+ return s;
+ }
+
+ inline string BSONObj::toString( bool isArray, bool full ) const {
+ if ( isEmpty() ) return "{}";
+ StringBuilder s;
+ toString(s, isArray, full);
+ return s.str();
+ }
+ inline void BSONObj::toString(StringBuilder& s, bool isArray, bool full ) const {
+ if ( isEmpty() ) {
+ s << "{}";
+ return;
+ }
+
+ s << ( isArray ? "[ " : "{ " );
+ BSONObjIterator i(*this);
+ bool first = true;
+ while ( 1 ) {
+ massert( 10327 , "Object does not end with EOO", i.moreWithEOO() );
+ BSONElement e = i.next( true );
+ massert( 10328 , "Invalid element size", e.size() > 0 );
+ massert( 10329 , "Element too large", e.size() < ( 1 << 30 ) );
+ int offset = (int) (e.rawdata() - this->objdata());
+ massert( 10330 , "Element extends past end of object",
+ e.size() + offset <= this->objsize() );
+ e.validate();
+ bool end = ( e.size() + offset == this->objsize() );
+ if ( e.eoo() ) {
+ massert( 10331 , "EOO Before end of object", end );
+ break;
+ }
+ if ( first )
+ first = false;
+ else
+ s << ", ";
+ e.toString(s, !isArray, full );
+ }
+ s << ( isArray ? " ]" : " }" );
+ }
+
+ inline void BSONElement::validate() const {
+ const BSONType t = type();
+
+ switch( t ) {
+ case DBRef:
+ case Code:
+ case Symbol:
+ case mongo::String: {
+ unsigned x = (unsigned) valuestrsize();
+ bool lenOk = x > 0 && x < (unsigned) BSONObjMaxInternalSize;
+ if( lenOk && valuestr()[x-1] == 0 )
+ return;
+ StringBuilder buf;
+ buf << "Invalid dbref/code/string/symbol size: " << x;
+ if( lenOk )
+ buf << " strnlen:" << mongo::strnlen( valuestr() , x );
+ msgasserted( 10321 , buf.str() );
+ break;
+ }
+ case CodeWScope: {
+ int totalSize = *( int * )( value() );
+ massert( 10322 , "Invalid CodeWScope size", totalSize >= 8 );
+ int strSizeWNull = *( int * )( value() + 4 );
+ massert( 10323 , "Invalid CodeWScope string size", totalSize >= strSizeWNull + 4 + 4 );
+ massert( 10324 , "Invalid CodeWScope string size",
+ strSizeWNull > 0 &&
+ (strSizeWNull - 1) == mongo::strnlen( codeWScopeCode(), strSizeWNull ) );
+ massert( 10325 , "Invalid CodeWScope size", totalSize >= strSizeWNull + 4 + 4 + 4 );
+ int objSize = *( int * )( value() + 4 + 4 + strSizeWNull );
+ massert( 10326 , "Invalid CodeWScope object size", totalSize == 4 + 4 + strSizeWNull + objSize );
+ // Subobject validation handled elsewhere.
+ }
+ case Object:
+ // We expect Object size validation to be handled elsewhere.
+ default:
+ break;
+ }
+ }
+
+ inline int BSONElement::size( int maxLen ) const {
+ if ( totalSize >= 0 )
+ return totalSize;
+
+ int remain = maxLen - fieldNameSize() - 1;
+
+ int x = 0;
+ switch ( type() ) {
+ case EOO:
+ case Undefined:
+ case jstNULL:
+ case MaxKey:
+ case MinKey:
+ break;
+ case mongo::Bool:
+ x = 1;
+ break;
+ case NumberInt:
+ x = 4;
+ break;
+ case Timestamp:
+ case mongo::Date:
+ case NumberDouble:
+ case NumberLong:
+ x = 8;
+ break;
+ case jstOID:
+ x = 12;
+ break;
+ case Symbol:
+ case Code:
+ case mongo::String:
+ 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 );
+ x = objsize();
+ break;
+
+ case DBRef:
+ 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 );
+ x = objsize();
+ break;
+ case BinData:
+ 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 ) : (size_t)mongo::strnlen( p, remain );
+ //massert( 10318 , "Invalid regex string", len1 != -1 ); // ERH - 4/28/10 - don't think this does anything
+ p = p + len1 + 1;
+ size_t len2;
+ if( maxLen == -1 )
+ len2 = strlen( p );
+ else {
+ size_t x = remain - len1 - 1;
+ assert( x <= 0x7fffffff );
+ len2 = mongo::strnlen( p, (int) x );
+ }
+ //massert( 10319 , "Invalid regex options string", len2 != -1 ); // ERH - 4/28/10 - don't think this does anything
+ x = (int) (len1 + 1 + len2 + 1);
+ }
+ break;
+ default: {
+ StringBuilder ss;
+ ss << "BSONElement: bad type " << (int) type();
+ string msg = ss.str();
+ massert( 13655 , msg.c_str(),false);
+ }
+ }
+ totalSize = x + fieldNameSize() + 1; // BSONType
+
+ return totalSize;
+ }
+
+ inline int BSONElement::size() const {
+ if ( totalSize >= 0 )
+ return totalSize;
+
+ int x = 0;
+ switch ( type() ) {
+ case EOO:
+ case Undefined:
+ case jstNULL:
+ case MaxKey:
+ case MinKey:
+ break;
+ case mongo::Bool:
+ x = 1;
+ break;
+ case NumberInt:
+ x = 4;
+ break;
+ case Timestamp:
+ case mongo::Date:
+ case NumberDouble:
+ case NumberLong:
+ x = 8;
+ break;
+ case jstOID:
+ x = 12;
+ break;
+ case Symbol:
+ case Code:
+ case mongo::String:
+ x = valuestrsize() + 4;
+ break;
+ case DBRef:
+ x = valuestrsize() + 4 + 12;
+ break;
+ case CodeWScope:
+ case Object:
+ case mongo::Array:
+ 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);
+ }
+ break;
+ default:
+ {
+ StringBuilder ss;
+ ss << "BSONElement: bad type " << (int) type();
+ string msg = ss.str();
+ massert(10320 , msg.c_str(),false);
+ }
+ }
+ totalSize = x + fieldNameSize() + 1; // BSONType
+
+ return totalSize;
+ }
+
+ inline string BSONElement::toString( bool includeFieldName, bool full ) const {
+ StringBuilder s;
+ toString(s, includeFieldName, full);
+ return s.str();
+ }
+ inline void BSONElement::toString(StringBuilder& s, bool includeFieldName, bool full ) const {
+ if ( includeFieldName && type() != EOO )
+ s << fieldName() << ": ";
+ switch ( type() ) {
+ case EOO:
+ s << "EOO";
+ break;
+ case mongo::Date:
+ s << "new Date(" << (long long) date() << ')';
+ break;
+ case RegEx: {
+ s << "/" << regex() << '/';
+ const char *p = regexFlags();
+ if ( p ) s << p;
+ }
+ break;
+ case NumberDouble:
+ s.appendDoubleNice( number() );
+ break;
+ case NumberLong:
+ s << _numberLong();
+ break;
+ case NumberInt:
+ s << _numberInt();
+ break;
+ case mongo::Bool:
+ s << ( boolean() ? "true" : "false" );
+ break;
+ case Object:
+ embeddedObject().toString(s, false, full);
+ break;
+ case mongo::Array:
+ embeddedObject().toString(s, true, full);
+ break;
+ case Undefined:
+ s << "undefined";
+ break;
+ case jstNULL:
+ s << "null";
+ break;
+ case MaxKey:
+ s << "MaxKey";
+ break;
+ case MinKey:
+ s << "MinKey";
+ break;
+ case CodeWScope:
+ s << "CodeWScope( "
+ << codeWScopeCode() << ", " << codeWScopeObject().toString(false, full) << ")";
+ break;
+ case Code:
+ if ( !full && valuestrsize() > 80 ) {
+ s.write(valuestr(), 70);
+ s << "...";
+ }
+ else {
+ s.write(valuestr(), valuestrsize()-1);
+ }
+ break;
+ case Symbol:
+ case mongo::String:
+ s << '"';
+ if ( !full && valuestrsize() > 160 ) {
+ s.write(valuestr(), 150);
+ s << "...\"";
+ }
+ else {
+ s.write(valuestr(), valuestrsize()-1);
+ s << '"';
+ }
+ break;
+ case DBRef:
+ s << "DBRef('" << valuestr() << "',";
+ {
+ mongo::OID *x = (mongo::OID *) (valuestr() + valuestrsize());
+ s << *x << ')';
+ }
+ break;
+ case jstOID:
+ s << "ObjectId('";
+ s << __oid() << "')";
+ break;
+ case BinData:
+ s << "BinData";
+ if (full) {
+ int len;
+ const char* data = binDataClean(len);
+ s << '(' << binDataType() << ", " << toHex(data, len) << ')';
+ }
+ break;
+ case Timestamp:
+ s << "Timestamp " << timestampTime() << "|" << timestampInc();
+ break;
+ default:
+ s << "?type=" << type();
+ break;
+ }
+ }
+
+ /* return has eoo() true if no match
+ supports "." notation to reach into embedded objects
+ */
+ inline BSONElement BSONObj::getFieldDotted(const char *name) const {
+ BSONElement e = getField( name );
+ if ( e.eoo() ) {
+ const char *p = strchr(name, '.');
+ if ( p ) {
+ string left(name, p-name);
+ BSONObj sub = getObjectField(left.c_str());
+ return sub.isEmpty() ? BSONElement() : sub.getFieldDotted(p+1);
+ }
+ }
+
+ return e;
+ }
+
+ inline BSONObj BSONObj::getObjectField(const char *name) const {
+ BSONElement e = getField(name);
+ BSONType t = e.type();
+ return t == Object || t == Array ? e.embeddedObject() : BSONObj();
+ }
+
+ inline int BSONObj::nFields() const {
+ int n = 0;
+ BSONObjIterator i(*this);
+ while ( i.moreWithEOO() ) {
+ BSONElement e = i.next();
+ if ( e.eoo() )
+ break;
+ n++;
+ }
+ return n;
+ }
+
+ inline BSONObj::BSONObj() {
+ /* little endian ordering here, but perhaps that is ok regardless as BSON is spec'd
+ to be little endian external to the system. (i.e. the rest of the implementation of bson,
+ not this part, fails to support big endian)
+ */
+ static char p[] = { /*size*/5, 0, 0, 0, /*eoo*/0 };
+ _objdata = p;
+ }
+
+ inline BSONObj BSONElement::Obj() const { return embeddedObjectUserCheck(); }
+
+ inline BSONElement BSONElement::operator[] (const string& field) const {
+ BSONObj o = Obj();
+ return o[field];
+ }
+
+ inline void BSONObj::elems(vector<BSONElement> &v) const {
+ BSONObjIterator i(*this);
+ while( i.more() )
+ v.push_back(i.next());
+ }
+
+ inline void BSONObj::elems(list<BSONElement> &v) const {
+ BSONObjIterator i(*this);
+ while( i.more() )
+ v.push_back(i.next());
+ }
+
+ template <class T>
+ void BSONObj::Vals(vector<T>& v) const {
+ BSONObjIterator i(*this);
+ while( i.more() ) {
+ T t;
+ i.next().Val(t);
+ v.push_back(t);
+ }
+ }
+ template <class T>
+ void BSONObj::Vals(list<T>& v) const {
+ BSONObjIterator i(*this);
+ while( i.more() ) {
+ T t;
+ i.next().Val(t);
+ v.push_back(t);
+ }
+ }
+
+ template <class T>
+ void BSONObj::vals(vector<T>& v) const {
+ BSONObjIterator i(*this);
+ while( i.more() ) {
+ try {
+ T t;
+ i.next().Val(t);
+ v.push_back(t);
+ }
+ catch(...) { }
+ }
+ }
+ template <class T>
+ void BSONObj::vals(list<T>& v) const {
+ BSONObjIterator i(*this);
+ while( i.more() ) {
+ try {
+ T t;
+ i.next().Val(t);
+ v.push_back(t);
+ }
+ catch(...) { }
+ }
+ }
+
+ inline ostream& operator<<( ostream &s, const BSONObj &o ) {
+ return s << o.toString();
+ }
+
+ inline ostream& operator<<( ostream &s, const BSONElement &e ) {
+ return s << e.toString();
+ }
+
+ inline StringBuilder& operator<<( StringBuilder &s, const BSONObj &o ) {
+ o.toString( s );
+ return s;
+ }
+ inline StringBuilder& operator<<( StringBuilder &s, const BSONElement &e ) {
+ e.toString( s );
+ return s;
+ }
+
+
+ inline void BSONElement::Val(BSONObj& v) const { v = Obj(); }
+
+ template<typename T>
+ inline BSONFieldValue<BSONObj> BSONField<T>::query( const char * q , const T& t ) const {
+ BSONObjBuilder b;
+ b.append( q , t );
+ return BSONFieldValue<BSONObj>( _name , b.obj() );
+ }
+
+ // used by jsonString()
+ inline string escape( string s , bool escape_slash=false) {
+ StringBuilder ret;
+ for ( string::iterator i = s.begin(); i != s.end(); ++i ) {
+ switch ( *i ) {
+ case '"':
+ ret << "\\\"";
+ break;
+ case '\\':
+ ret << "\\\\";
+ break;
+ case '/':
+ ret << (escape_slash ? "\\/" : "/");
+ break;
+ case '\b':
+ ret << "\\b";
+ break;
+ case '\f':
+ ret << "\\f";
+ break;
+ case '\n':
+ ret << "\\n";
+ break;
+ case '\r':
+ ret << "\\r";
+ break;
+ case '\t':
+ ret << "\\t";
+ break;
+ default:
+ if ( *i >= 0 && *i <= 0x1f ) {
+ //TODO: these should be utf16 code-units not bytes
+ char c = *i;
+ ret << "\\u00" << toHexLower(&c, 1);
+ }
+ else {
+ ret << *i;
+ }
+ }
+ }
+ return ret.str();
+ }
+
+ inline string BSONObj::hexDump() const {
+ stringstream ss;
+ const char *d = objdata();
+ int size = objsize();
+ for( int i = 0; i < size; ++i ) {
+ ss.width( 2 );
+ ss.fill( '0' );
+ ss << hex << (unsigned)(unsigned char)( d[ i ] ) << dec;
+ if ( ( d[ i ] >= '0' && d[ i ] <= '9' ) || ( d[ i ] >= 'A' && d[ i ] <= 'z' ) )
+ ss << '\'' << d[ i ] << '\'';
+ if ( i != size - 1 )
+ ss << ' ';
+ }
+ return ss.str();
+ }
+
+ inline void BSONObjBuilder::appendKeys( const BSONObj& keyPattern , const BSONObj& values ) {
+ BSONObjIterator i(keyPattern);
+ BSONObjIterator j(values);
+
+ while ( i.more() && j.more() ) {
+ appendAs( j.next() , i.next().fieldName() );
+ }
+
+ assert( ! i.more() );
+ assert( ! j.more() );
+ }
+
+ inline BSONObj BSONObj::removeField(const StringData& name) const {
+ BSONObjBuilder b;
+ BSONObjIterator i(*this);
+ while ( i.more() ) {
+ BSONElement e = i.next();
+ const char *fname = e.fieldName();
+ if( strcmp(name.data(), fname) )
+ b.append(e);
+ }
+ return b.obj();
+ }
+}
diff --git a/src/mongo/bson/bson.h b/src/mongo/bson/bson.h
new file mode 100644
index 00000000000..9515adfd829
--- /dev/null
+++ b/src/mongo/bson/bson.h
@@ -0,0 +1,110 @@
+/** @file bson.h
+
+ Main bson include file for mongodb c++ clients. MongoDB includes ../db/jsobj.h instead.
+ This file, however, pulls in much less code / dependencies.
+
+ @see bsondemo
+*/
+
+/*
+ * Copyright 2009 10gen Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ Main include file for C++ BSON module when using standalone (sans MongoDB client).
+
+ "BSON" stands for "binary JSON" -- ie a binary way to represent objects that would be
+ represented in JSON (plus a few extensions useful for databases & other languages).
+
+ http://www.bsonspec.org/
+*/
+
+#pragma once
+
+#if defined(MONGO_EXPOSE_MACROS)
+#error this header is for client programs, not the mongo database itself. include jsobj.h instead.
+/* because we define simplistic assert helpers here that don't pull in a bunch of util -- so that
+ BSON can be used header only.
+ */
+#endif
+
+#include <cstdlib>
+#include <memory>
+#include <iostream>
+#include <sstream>
+#include <boost/utility.hpp>
+
+namespace bson {
+
+ using std::string;
+ using std::stringstream;
+
+ class assertion : public std::exception {
+ public:
+ assertion( unsigned u , const string& s )
+ : id( u ) , msg( s ) {
+ stringstream ss;
+ ss << "BsonAssertion id: " << u << " " << s;
+ full = ss.str();
+ }
+
+ virtual ~assertion() throw() {}
+
+ virtual const char* what() const throw() { return full.c_str(); }
+
+ unsigned id;
+ string msg;
+ string full;
+ };
+}
+
+namespace mongo {
+#if !defined(assert)
+ inline void assert(bool expr) {
+ if(!expr) {
+ throw bson::assertion( 0 , "assertion failure in bson library" );
+ }
+ }
+#endif
+#if !defined(uassert)
+ inline void uasserted(unsigned msgid, std::string s) {
+ throw bson::assertion( msgid , s );
+ }
+
+ inline void uassert(unsigned msgid, std::string msg, bool expr) {
+ if( !expr )
+ uasserted( msgid , msg );
+ }
+ inline void msgasserted(int msgid, const char *msg) {
+ throw bson::assertion( msgid , msg );
+ }
+ inline void msgasserted(int msgid, const std::string &msg) { msgasserted(msgid, msg.c_str()); }
+ inline void massert(unsigned msgid, std::string msg, bool expr) {
+ if(!expr) {
+ std::cout << "assertion failure in bson library: " << msgid << ' ' << msg << std::endl;
+ throw bson::assertion( msgid , msg );
+ }
+ }
+#endif
+}
+
+#include "util/builder.h"
+#include "bsontypes.h"
+#include "oid.h"
+#include "bsonelement.h"
+#include "bsonobj.h"
+#include "bsonobjbuilder.h"
+#include "bsonobjiterator.h"
+#include "bson-inl.h"
diff --git a/src/mongo/bson/bson_db.h b/src/mongo/bson/bson_db.h
new file mode 100644
index 00000000000..3f597bde3e1
--- /dev/null
+++ b/src/mongo/bson/bson_db.h
@@ -0,0 +1,88 @@
+/** @file bson_db.h
+
+ This file contains the implementation of BSON-related methods that are required
+ by the MongoDB database server.
+
+ Normally, for standalone BSON usage, you do not want this file - it will tend to
+ pull in some other files from the MongoDB project. Thus, bson.h (the main file
+ one would use) does not include this file.
+*/
+
+/* Copyright 2009 10gen Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "../util/optime.h"
+#include "../util/time_support.h"
+
+namespace mongo {
+
+ /**
+ Timestamps are a special BSON datatype that is used internally for replication.
+ Append a timestamp element to the object being ebuilt.
+ @param time - in millis (but stored in seconds)
+ */
+ inline BSONObjBuilder& BSONObjBuilder::appendTimestamp( const StringData& fieldName , unsigned long long time , unsigned int inc ) {
+ OpTime t( (unsigned) (time / 1000) , inc );
+ appendTimestamp( fieldName , t.asDate() );
+ return *this;
+ }
+
+ inline OpTime BSONElement::_opTime() const {
+ if( type() == mongo::Date || type() == Timestamp )
+ return OpTime( *reinterpret_cast< const unsigned long long* >( value() ) );
+ return OpTime();
+ }
+
+ inline string BSONElement::_asCode() const {
+ switch( type() ) {
+ case mongo::String:
+ case Code:
+ return string(valuestr(), valuestrsize()-1);
+ case CodeWScope:
+ return string(codeWScopeCode(), *(int*)(valuestr())-1);
+ default:
+ log() << "can't convert type: " << (int)(type()) << " to code" << endl;
+ }
+ uassert( 10062 , "not code" , 0 );
+ return "";
+ }
+
+ inline BSONObjBuilder& BSONObjBuilderValueStream::operator<<(DateNowLabeler& id) {
+ _builder->appendDate(_fieldName, jsTime());
+ _fieldName = 0;
+ return *_builder;
+ }
+
+ inline BSONObjBuilder& BSONObjBuilderValueStream::operator<<(NullLabeler& id) {
+ _builder->appendNull(_fieldName);
+ _fieldName = 0;
+ return *_builder;
+ }
+
+ inline BSONObjBuilder& BSONObjBuilderValueStream::operator<<(MinKeyLabeler& id) {
+ _builder->appendMinKey(_fieldName);
+ _fieldName = 0;
+ return *_builder;
+ }
+
+ inline BSONObjBuilder& BSONObjBuilderValueStream::operator<<(MaxKeyLabeler& id) {
+ _builder->appendMaxKey(_fieldName);
+ _fieldName = 0;
+ return *_builder;
+ }
+
+}
diff --git a/src/mongo/bson/bsondemo/bsondemo.cpp b/src/mongo/bson/bsondemo/bsondemo.cpp
new file mode 100644
index 00000000000..b53a7b39baa
--- /dev/null
+++ b/src/mongo/bson/bsondemo/bsondemo.cpp
@@ -0,0 +1,113 @@
+/** @file bsondemo.cpp
+
+ Example of use of BSON from C++.
+
+ Requires boost (headers only).
+ Works headers only (the parts actually exercised herein that is - some functions require .cpp files).
+
+ To build and run:
+ g++ -o bsondemo bsondemo.cpp
+ ./bsondemo
+
+ Windows: project files are available in this directory for bsondemo.cpp for use with Visual Studio.
+*/
+
+/*
+ * Copyright 2010 10gen Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "../bson.h"
+#include <iostream>
+#include <vector>
+
+using namespace std;
+using namespace bson;
+
+void iter(bo o) {
+ /* iterator example */
+ cout << "\niter()\n";
+ for( bo::iterator i(o); i.more(); ) {
+ cout << ' ' << i.next().toString() << '\n';
+ }
+}
+
+int main() {
+ cout << "build bits: " << 8 * sizeof(char *) << '\n' << endl;
+
+ /* a bson object defaults on construction to { } */
+ bo empty;
+ cout << "empty: " << empty << endl;
+
+ /* make a simple { name : 'joe', age : 33.7 } object */
+ {
+ bob b;
+ b.append("name", "joe");
+ b.append("age", 33.7);
+ b.obj();
+ }
+
+ /* make { name : 'joe', age : 33.7 } with a more compact notation. */
+ bo x = bob().append("name", "joe").append("age", 33.7).obj();
+
+ /* convert from bson to json */
+ string json = x.toString();
+ cout << "json for x:" << json << endl;
+
+ /* access some fields of bson object x */
+ cout << "Some x things: " << x["name"] << ' ' << x["age"].Number() << ' ' << x.isEmpty() << endl;
+
+ /* make a bit more complex object with some nesting
+ { x : 'asdf', y : true, subobj : { z : 3, q : 4 } }
+ */
+ bo y = BSON( "x" << "asdf" << "y" << true << "subobj" << BSON( "z" << 3 << "q" << 4 ) );
+
+ /* print it */
+ cout << "y: " << y << endl;
+
+ /* reach in and get subobj.z */
+ cout << "subobj.z: " << y.getFieldDotted("subobj.z").Number() << endl;
+
+ /* alternate syntax: */
+ cout << "subobj.z: " << y["subobj"]["z"].Number() << endl;
+
+ /* fetch all *top level* elements from object y into a vector */
+ vector<be> v;
+ y.elems(v);
+ cout << v[0] << endl;
+
+ /* into an array */
+ list<be> L;
+ y.elems(L);
+
+ bo sub = y["subobj"].Obj();
+
+ /* grab all the int's that were in subobj. if it had elements that were not ints, we throw an exception
+ (capital V on Vals() means exception if wrong type found
+ */
+ vector<int> myints;
+ sub.Vals(myints);
+ cout << "my ints: " << myints[0] << ' ' << myints[1] << endl;
+
+ /* grab all the string values from x. if the field isn't of string type, just skip it --
+ lowercase v on vals() indicates skip don't throw.
+ */
+ vector<string> strs;
+ x.vals(strs);
+ cout << strs.size() << " strings, first one: " << strs[0] << endl;
+
+ iter(y);
+ return 0;
+}
+
diff --git a/src/mongo/bson/bsondemo/bsondemo.vcproj b/src/mongo/bson/bsondemo/bsondemo.vcproj
new file mode 100644
index 00000000000..8432cebfd87
--- /dev/null
+++ b/src/mongo/bson/bsondemo/bsondemo.vcproj
@@ -0,0 +1,243 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="bsondemo"
+ ProjectGUID="{C9DB5EB7-81AA-4185-BAA1-DA035654402F}"
+ RootNamespace="bsondemo"
+ Keyword="Win32Proj"
+ TargetFrameworkVersion="196613"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="c:\program files\boost\latest;c:\boost;\boost"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ EnableIntrinsicFunctions="true"
+ AdditionalIncludeDirectories="c:\program files\boost\latest;c:\boost;\boost"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+ RuntimeLibrary="2"
+ EnableFunctionLevelLinking="true"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath=".\bsondemo.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="bson"
+ >
+ <File
+ RelativePath="..\bson.h"
+ >
+ </File>
+ <File
+ RelativePath="..\bson_db.h"
+ >
+ </File>
+ <File
+ RelativePath="..\bsonelement.h"
+ >
+ </File>
+ <File
+ RelativePath="..\bsoninlines.h"
+ >
+ </File>
+ <File
+ RelativePath="..\bsonmisc.h"
+ >
+ </File>
+ <File
+ RelativePath="..\bsonobj.h"
+ >
+ </File>
+ <File
+ RelativePath="..\bsonobjbuilder.h"
+ >
+ </File>
+ <File
+ RelativePath="..\bsonobjiterator.h"
+ >
+ </File>
+ <File
+ RelativePath="..\bsontypes.h"
+ >
+ </File>
+ <File
+ RelativePath="..\oid.h"
+ >
+ </File>
+ <File
+ RelativePath="..\ordering.h"
+ >
+ </File>
+ <Filter
+ Name="util"
+ >
+ <File
+ RelativePath="..\util\builder.h"
+ >
+ </File>
+ <File
+ RelativePath="..\util\misc.h"
+ >
+ </File>
+ </Filter>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/src/mongo/bson/bsondemo/bsondemo.vcxproj b/src/mongo/bson/bsondemo/bsondemo.vcxproj
new file mode 100644
index 00000000000..2ad53894d7d
--- /dev/null
+++ b/src/mongo/bson/bsondemo/bsondemo.vcxproj
@@ -0,0 +1,193 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{C9DB5EB7-81AA-4185-BAA1-DA035654402F}</ProjectGuid>
+ <RootNamespace>bsondemo</RootNamespace>
+ <Keyword>Win32Proj</Keyword>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <CharacterSet>Unicode</CharacterSet>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <CharacterSet>Unicode</CharacterSet>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup>
+ <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)$(Configuration)\</OutDir>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(SolutionDir)$(Configuration)\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Configuration)\</IntDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(Configuration)\</IntDir>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</LinkIncremental>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</LinkIncremental>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)$(Configuration)\</OutDir>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(SolutionDir)$(Configuration)\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Configuration)\</IntDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(Configuration)\</IntDir>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</LinkIncremental>
+ <CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">AllRules.ruleset</CodeAnalysisRuleSet>
+ <CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">AllRules.ruleset</CodeAnalysisRuleSet>
+ <CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" />
+ <CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" />
+ <CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" />
+ <CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" />
+ <CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">AllRules.ruleset</CodeAnalysisRuleSet>
+ <CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Release|x64'">AllRules.ruleset</CodeAnalysisRuleSet>
+ <CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" />
+ <CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
+ <CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" />
+ <CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>c:\boost;\boost</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MinimalRebuild>No</MinimalRebuild>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>EditAndContinue</DebugInformationFormat>
+ <MultiProcessorCompilation>true</MultiProcessorCompilation>
+ </ClCompile>
+ <Link>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <SubSystem>Console</SubSystem>
+ <TargetMachine>MachineX86</TargetMachine>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>c:\boost;\boost</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ <MinimalRebuild>No</MinimalRebuild>
+ <MultiProcessorCompilation>true</MultiProcessorCompilation>
+ </ClCompile>
+ <Link>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <SubSystem>Console</SubSystem>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <Optimization>MaxSpeed</Optimization>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ <AdditionalIncludeDirectories>c:\boost;\boost</AdditionalIncludeDirectories>
+ <MinimalRebuild>No</MinimalRebuild>
+ <MultiProcessorCompilation>true</MultiProcessorCompilation>
+ </ClCompile>
+ <Link>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <SubSystem>Console</SubSystem>
+ <OptimizeReferences>true</OptimizeReferences>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <TargetMachine>MachineX86</TargetMachine>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <Optimization>MaxSpeed</Optimization>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ <AdditionalIncludeDirectories>c:\boost;\boost</AdditionalIncludeDirectories>
+ <MinimalRebuild>No</MinimalRebuild>
+ <MultiProcessorCompilation>true</MultiProcessorCompilation>
+ </ClCompile>
+ <Link>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <SubSystem>Console</SubSystem>
+ <OptimizeReferences>true</OptimizeReferences>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="bsondemo.cpp" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="..\bson.h" />
+ <ClInclude Include="..\bson_db.h" />
+ <ClInclude Include="..\bsonelement.h" />
+ <ClInclude Include="..\bsoninlines.h" />
+ <ClInclude Include="..\bsonmisc.h" />
+ <ClInclude Include="..\bsonobj.h" />
+ <ClInclude Include="..\bsonobjbuilder.h" />
+ <ClInclude Include="..\bsonobjiterator.h" />
+ <ClInclude Include="..\bsontypes.h" />
+ <ClInclude Include="..\oid.h" />
+ <ClInclude Include="..\ordering.h" />
+ <ClInclude Include="..\util\builder.h" />
+ <ClInclude Include="..\util\misc.h" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project>
diff --git a/src/mongo/bson/bsondemo/bsondemo.vcxproj.filters b/src/mongo/bson/bsondemo/bsondemo.vcxproj.filters
new file mode 100644
index 00000000000..35f14d5193b
--- /dev/null
+++ b/src/mongo/bson/bsondemo/bsondemo.vcxproj.filters
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <ClCompile Include="bsondemo.cpp" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="..\ordering.h">
+ <Filter>bson</Filter>
+ </ClInclude>
+ <ClInclude Include="..\bsonelement.h">
+ <Filter>bson</Filter>
+ </ClInclude>
+ <ClInclude Include="..\bsoninlines.h">
+ <Filter>bson</Filter>
+ </ClInclude>
+ <ClInclude Include="..\bsonmisc.h">
+ <Filter>bson</Filter>
+ </ClInclude>
+ <ClInclude Include="..\bsonobj.h">
+ <Filter>bson</Filter>
+ </ClInclude>
+ <ClInclude Include="..\bsonobjbuilder.h">
+ <Filter>bson</Filter>
+ </ClInclude>
+ <ClInclude Include="..\bsonobjiterator.h">
+ <Filter>bson</Filter>
+ </ClInclude>
+ <ClInclude Include="..\bsontypes.h">
+ <Filter>bson</Filter>
+ </ClInclude>
+ <ClInclude Include="..\util\builder.h">
+ <Filter>bson</Filter>
+ </ClInclude>
+ <ClInclude Include="..\util\misc.h">
+ <Filter>bson</Filter>
+ </ClInclude>
+ <ClInclude Include="..\oid.h">
+ <Filter>bson</Filter>
+ </ClInclude>
+ <ClInclude Include="..\bson_db.h">
+ <Filter>bson</Filter>
+ </ClInclude>
+ <ClInclude Include="..\bson.h">
+ <Filter>bson</Filter>
+ </ClInclude>
+ </ItemGroup>
+ <ItemGroup>
+ <Filter Include="bson">
+ <UniqueIdentifier>{ea599740-3c6f-40dd-a121-e825d82ae4aa}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+</Project>
diff --git a/src/mongo/bson/bsonelement.h b/src/mongo/bson/bsonelement.h
new file mode 100644
index 00000000000..57cc2ae5775
--- /dev/null
+++ b/src/mongo/bson/bsonelement.h
@@ -0,0 +1,583 @@
+// BSONElement
+
+/* Copyright 2009 10gen Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <vector>
+#include <string.h>
+#include "util/builder.h"
+#include "bsontypes.h"
+
+namespace mongo {
+ class OpTime;
+ class BSONObj;
+ class BSONElement;
+ class BSONObjBuilder;
+}
+
+namespace bson {
+ typedef mongo::BSONElement be;
+ typedef mongo::BSONObj bo;
+ typedef mongo::BSONObjBuilder bob;
+}
+
+namespace mongo {
+
+ /* l and r MUST have same type when called: check that first. */
+ int compareElementValues(const BSONElement& l, const BSONElement& r);
+
+
+ /** BSONElement represents an "element" in a BSONObj. So for the object { a : 3, b : "abc" },
+ 'a : 3' is the first element (key+value).
+
+ The BSONElement object points into the BSONObj's data. Thus the BSONObj must stay in scope
+ for the life of the BSONElement.
+
+ internals:
+ <type><fieldName ><value>
+ -------- size() ------------
+ -fieldNameSize-
+ value()
+ type()
+ */
+ class BSONElement {
+ public:
+ /** These functions, which start with a capital letter, throw a UserException if the
+ element is not of the required type. Example:
+
+ string foo = obj["foo"].String(); // exception if not a string type or DNE
+ */
+ string String() const { return chk(mongo::String).valuestr(); }
+ Date_t Date() const { return chk(mongo::Date).date(); }
+ double Number() const { return chk(isNumber()).number(); }
+ double Double() const { return chk(NumberDouble)._numberDouble(); }
+ long long Long() const { return chk(NumberLong)._numberLong(); }
+ int Int() const { return chk(NumberInt)._numberInt(); }
+ bool Bool() const { return chk(mongo::Bool).boolean(); }
+ vector<BSONElement> Array() const; // see implementation for detailed comments
+ mongo::OID OID() const { return chk(jstOID).__oid(); }
+ void Null() const { chk(isNull()); } // throw UserException if not null
+ void OK() const { chk(ok()); } // throw UserException if element DNE
+
+ /** @return the embedded object associated with this field.
+ Note the returned object is a reference to within the parent bson object. If that
+ object is out of scope, this pointer will no longer be valid. Call getOwned() on the
+ returned BSONObj if you need your own copy.
+ throws UserException if the element is not of type object.
+ */
+ BSONObj Obj() const;
+
+ /** populate v with the value of the element. If type does not match, throw exception.
+ useful in templates -- see also BSONObj::Vals().
+ */
+ void Val(Date_t& v) const { v = Date(); }
+ void Val(long long& v) const { v = Long(); }
+ void Val(bool& v) const { v = Bool(); }
+ void Val(BSONObj& v) const;
+ void Val(mongo::OID& v) const { v = OID(); }
+ void Val(int& v) const { v = Int(); }
+ void Val(double& v) const { v = Double(); }
+ void Val(string& v) const { v = String(); }
+
+ /** Use ok() to check if a value is assigned:
+ if( myObj["foo"].ok() ) ...
+ */
+ bool ok() const { return !eoo(); }
+
+ string toString( bool includeFieldName = true, bool full=false) const;
+ void toString(StringBuilder& s, bool includeFieldName = true, bool full=false) const;
+ string jsonString( JsonStringFormat format, bool includeFieldNames = true, int pretty = 0 ) const;
+ operator string() const { return toString(); }
+
+ /** Returns the type of the element */
+ BSONType type() const { return (BSONType) *data; }
+
+ /** retrieve a field within this element
+ throws exception if *this is not an embedded object
+ */
+ BSONElement operator[] (const string& field) const;
+
+ /** returns the tyoe of the element fixed for the main type
+ the main purpose is numbers. any numeric type will return NumberDouble
+ Note: if the order changes, indexes have to be re-built or than can be corruption
+ */
+ int canonicalType() const;
+
+ /** Indicates if it is the end-of-object element, which is present at the end of
+ every BSON object.
+ */
+ bool eoo() const { return type() == EOO; }
+
+ /** Size of the element.
+ @param maxLen If maxLen is specified, don't scan more than maxLen bytes to calculate size.
+ */
+ int size( int maxLen ) const;
+ int size() const;
+
+ /** Wrap this element up as a singleton object. */
+ BSONObj wrap() const;
+
+ /** Wrap this element up as a singleton object with a new name. */
+ BSONObj wrap( const char* newName) const;
+
+ /** field name of the element. e.g., for
+ name : "Joe"
+ "name" is the fieldname
+ */
+ const char * fieldName() const {
+ if ( eoo() ) return ""; // no fieldname for it.
+ return data + 1;
+ }
+
+ /** raw data of the element's value (so be careful). */
+ const char * value() const {
+ return (data + fieldNameSize() + 1);
+ }
+ /** size in bytes of the element's value (when applicable). */
+ int valuesize() const {
+ return size() - fieldNameSize() - 1;
+ }
+
+ bool isBoolean() const { return type() == mongo::Bool; }
+
+ /** @return value of a boolean element.
+ You must assure element is a boolean before
+ calling. */
+ bool boolean() const {
+ return *value() ? true : false;
+ }
+
+ bool booleanSafe() const { return isBoolean() && boolean(); }
+
+ /** Retrieve a java style date value from the element.
+ Ensure element is of type Date before calling.
+ @see Bool(), trueValue()
+ */
+ Date_t date() const {
+ return *reinterpret_cast< const Date_t* >( value() );
+ }
+
+ /** Convert the value to boolean, regardless of its type, in a javascript-like fashion
+ (i.e., treats zero and null and eoo as false).
+ */
+ bool trueValue() const;
+
+ /** True if number, string, bool, date, OID */
+ bool isSimpleType() const;
+
+ /** True if element is of a numeric type. */
+ bool isNumber() const;
+
+ /** Return double value for this field. MUST be NumberDouble type. */
+ double _numberDouble() const {return *reinterpret_cast< const double* >( value() ); }
+ /** Return int value for this field. MUST be NumberInt type. */
+ int _numberInt() const {return *reinterpret_cast< const int* >( value() ); }
+ /** Return long long value for this field. MUST be NumberLong type. */
+ long long _numberLong() const {return *reinterpret_cast< const long long* >( value() ); }
+
+ /** Retrieve int value for the element safely. Zero returned if not a number. */
+ int numberInt() const;
+ /** Retrieve long value for the element safely. Zero returned if not a number. */
+ long long numberLong() const;
+ /** Retrieve the numeric value of the element. If not of a numeric type, returns 0.
+ Note: casts to double, data loss may occur with large (>52 bit) NumberLong values.
+ */
+ double numberDouble() const;
+ /** Retrieve the numeric value of the element. If not of a numeric type, returns 0.
+ Note: casts to double, data loss may occur with large (>52 bit) NumberLong values.
+ */
+ double number() const { return numberDouble(); }
+
+ /** Retrieve the object ID stored in the object.
+ You must ensure the element is of type jstOID first. */
+ const mongo::OID &__oid() const { return *reinterpret_cast< const mongo::OID* >( value() ); }
+
+ /** True if element is null. */
+ bool isNull() const {
+ return type() == jstNULL;
+ }
+
+ /** Size (length) of a string element.
+ You must assure of type String first.
+ @return string size including terminating null
+ */
+ int valuestrsize() const {
+ return *reinterpret_cast< const int* >( value() );
+ }
+
+ // for objects the size *includes* the size of the size field
+ int objsize() const {
+ return *reinterpret_cast< const int* >( value() );
+ }
+
+ /** Get a string's value. Also gives you start of the real data for an embedded object.
+ You must assure data is of an appropriate type first -- see also valuestrsafe().
+ */
+ const char * valuestr() const {
+ return value() + 4;
+ }
+
+ /** Get the string value of the element. If not a string returns "". */
+ const char *valuestrsafe() const {
+ return type() == mongo::String ? valuestr() : "";
+ }
+ /** Get the string value of the element. If not a string returns "". */
+ string str() const {
+ return type() == mongo::String ? string(valuestr(), valuestrsize()-1) : string();
+ }
+
+ /** Get javascript code of a CodeWScope data element. */
+ const char * codeWScopeCode() const {
+ return value() + 8;
+ }
+ /** Get the scope SavedContext of a CodeWScope data element. */
+ const char * codeWScopeScopeData() const {
+ // TODO fix
+ return codeWScopeCode() + strlen( codeWScopeCode() ) + 1;
+ }
+
+ /** Get the embedded object this element holds. */
+ BSONObj embeddedObject() const;
+
+ /* uasserts if not an object */
+ BSONObj embeddedObjectUserCheck() const;
+
+ BSONObj codeWScopeObject() const;
+
+ /** Get raw binary data. Element must be of type BinData. Doesn't handle type 2 specially */
+ const char *binData(int& len) const {
+ // BinData: <int len> <byte subtype> <byte[len] data>
+ assert( type() == BinData );
+ len = valuestrsize();
+ return value() + 5;
+ }
+ /** Get binary data. Element must be of type BinData. Handles type 2 */
+ const char *binDataClean(int& len) const {
+ // BinData: <int len> <byte subtype> <byte[len] data>
+ if (binDataType() != ByteArrayDeprecated) {
+ return binData(len);
+ }
+ else {
+ // Skip extra size
+ len = valuestrsize() - 4;
+ return value() + 5 + 4;
+ }
+ }
+
+ BinDataType binDataType() const {
+ // BinData: <int len> <byte subtype> <byte[len] data>
+ assert( type() == BinData );
+ unsigned char c = (value() + 4)[0];
+ return (BinDataType)c;
+ }
+
+ /** Retrieve the regex string for a Regex element */
+ const char *regex() const {
+ assert(type() == RegEx);
+ return value();
+ }
+
+ /** Retrieve the regex flags (options) for a Regex element */
+ const char *regexFlags() const {
+ const char *p = regex();
+ return p + strlen(p) + 1;
+ }
+
+ /** like operator== but doesn't check the fieldname,
+ just the value.
+ */
+ bool valuesEqual(const BSONElement& r) const {
+ return woCompare( r , false ) == 0;
+ }
+
+ /** Returns true if elements are equal. */
+ bool operator==(const BSONElement& r) const {
+ return woCompare( r , true ) == 0;
+ }
+ /** Returns true if elements are unequal. */
+ bool operator!=(const BSONElement& r) const { return !operator==(r); }
+
+ /** Well ordered comparison.
+ @return <0: l<r. 0:l==r. >0:l>r
+ order by type, field name, and field value.
+ If considerFieldName is true, pay attention to the field name.
+ */
+ int woCompare( const BSONElement &e, bool considerFieldName = true ) const;
+
+ const char * rawdata() const { return data; }
+
+ /** 0 == Equality, just not defined yet */
+ int getGtLtOp( int def = 0 ) const;
+
+ /** Constructs an empty element */
+ BSONElement();
+
+ /** Check that data is internally consistent. */
+ void validate() const;
+
+ /** True if this element may contain subobjects. */
+ bool mayEncapsulate() const {
+ switch ( type() ) {
+ case Object:
+ case mongo::Array:
+ case CodeWScope:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ /** True if this element can be a BSONObj */
+ bool isABSONObj() const {
+ switch( type() ) {
+ case Object:
+ case mongo::Array:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ Date_t timestampTime() const {
+ unsigned long long t = ((unsigned int*)(value() + 4 ))[0];
+ return t * 1000;
+ }
+ unsigned int timestampInc() const {
+ return ((unsigned int*)(value() ))[0];
+ }
+
+ const char * dbrefNS() const {
+ uassert( 10063 , "not a dbref" , type() == DBRef );
+ return value() + 4;
+ }
+
+ const mongo::OID& dbrefOID() const {
+ uassert( 10064 , "not a dbref" , type() == DBRef );
+ const char * start = value();
+ start += 4 + *reinterpret_cast< const int* >( start );
+ return *reinterpret_cast< const mongo::OID* >( start );
+ }
+
+ /** this does not use fieldName in the comparison, just the value */
+ bool operator<( const BSONElement& other ) const {
+ int x = (int)canonicalType() - (int)other.canonicalType();
+ if ( x < 0 ) return true;
+ else if ( x > 0 ) return false;
+ return compareElementValues(*this,other) < 0;
+ }
+
+ // @param maxLen don't scan more than maxLen bytes
+ explicit BSONElement(const char *d, int maxLen) : data(d) {
+ if ( eoo() ) {
+ totalSize = 1;
+ fieldNameSize_ = 0;
+ }
+ else {
+ totalSize = -1;
+ fieldNameSize_ = -1;
+ if ( maxLen != -1 ) {
+ int size = (int) strnlen( fieldName(), maxLen - 1 );
+ uassert( 10333 , "Invalid field name", size != -1 );
+ fieldNameSize_ = size + 1;
+ }
+ }
+ }
+
+ explicit BSONElement(const char *d) : data(d) {
+ fieldNameSize_ = -1;
+ totalSize = -1;
+ if ( eoo() ) {
+ fieldNameSize_ = 0;
+ totalSize = 1;
+ }
+ }
+
+ string _asCode() const;
+ OpTime _opTime() const;
+
+ private:
+ const char *data;
+ mutable int fieldNameSize_; // cached value
+ int fieldNameSize() const {
+ if ( fieldNameSize_ == -1 )
+ fieldNameSize_ = (int)strlen( fieldName() ) + 1;
+ return fieldNameSize_;
+ }
+ mutable int totalSize; /* caches the computed size */
+
+ friend class BSONObjIterator;
+ friend class BSONObj;
+ const BSONElement& chk(int t) const {
+ if ( t != type() ) {
+ StringBuilder ss;
+ if( eoo() )
+ ss << "field not found, expected type " << t;
+ else
+ ss << "wrong type for field (" << fieldName() << ") " << type() << " != " << t;
+ uasserted(13111, ss.str() );
+ }
+ return *this;
+ }
+ const BSONElement& chk(bool expr) const {
+ uassert(13118, "unexpected or missing type value in BSON object", expr);
+ return *this;
+ }
+ };
+
+
+ inline int BSONElement::canonicalType() const {
+ BSONType t = type();
+ switch ( t ) {
+ case MinKey:
+ case MaxKey:
+ return t;
+ case EOO:
+ case Undefined:
+ return 0;
+ case jstNULL:
+ return 5;
+ case NumberDouble:
+ case NumberInt:
+ case NumberLong:
+ return 10;
+ case mongo::String:
+ case Symbol:
+ return 15;
+ case Object:
+ return 20;
+ case mongo::Array:
+ return 25;
+ case BinData:
+ return 30;
+ case jstOID:
+ return 35;
+ case mongo::Bool:
+ return 40;
+ case mongo::Date:
+ case Timestamp:
+ return 45;
+ case RegEx:
+ return 50;
+ case DBRef:
+ return 55;
+ case Code:
+ return 60;
+ case CodeWScope:
+ return 65;
+ default:
+ assert(0);
+ return -1;
+ }
+ }
+
+ inline bool BSONElement::trueValue() const {
+ switch( type() ) {
+ case NumberLong:
+ return *reinterpret_cast< const long long* >( value() ) != 0;
+ case NumberDouble:
+ return *reinterpret_cast< const double* >( value() ) != 0;
+ case NumberInt:
+ return *reinterpret_cast< const int* >( value() ) != 0;
+ case mongo::Bool:
+ return boolean();
+ case EOO:
+ case jstNULL:
+ case Undefined:
+ return false;
+
+ default:
+ ;
+ }
+ return true;
+ }
+
+ /** @return true if element is of a numeric type. */
+ inline bool BSONElement::isNumber() const {
+ switch( type() ) {
+ case NumberLong:
+ case NumberDouble:
+ case NumberInt:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ inline bool BSONElement::isSimpleType() const {
+ switch( type() ) {
+ case NumberLong:
+ case NumberDouble:
+ case NumberInt:
+ case mongo::String:
+ case mongo::Bool:
+ case mongo::Date:
+ case jstOID:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ inline double BSONElement::numberDouble() const {
+ switch( type() ) {
+ case NumberDouble:
+ return _numberDouble();
+ case NumberInt:
+ return *reinterpret_cast< const int* >( value() );
+ case NumberLong:
+ return (double) *reinterpret_cast< const long long* >( value() );
+ default:
+ return 0;
+ }
+ }
+
+ /** Retrieve int value for the element safely. Zero returned if not a number. Converted to int if another numeric type. */
+ inline int BSONElement::numberInt() const {
+ switch( type() ) {
+ case NumberDouble:
+ return (int) _numberDouble();
+ case NumberInt:
+ return _numberInt();
+ case NumberLong:
+ return (int) _numberLong();
+ default:
+ return 0;
+ }
+ }
+
+ /** Retrieve long value for the element safely. Zero returned if not a number. */
+ inline long long BSONElement::numberLong() const {
+ switch( type() ) {
+ case NumberDouble:
+ return (long long) _numberDouble();
+ case NumberInt:
+ return _numberInt();
+ case NumberLong:
+ return _numberLong();
+ default:
+ return 0;
+ }
+ }
+
+ inline BSONElement::BSONElement() {
+ static char z = 0;
+ data = &z;
+ fieldNameSize_ = 0;
+ totalSize = 1;
+ }
+
+}
diff --git a/src/mongo/bson/bsonmisc.h b/src/mongo/bson/bsonmisc.h
new file mode 100644
index 00000000000..8a379396d17
--- /dev/null
+++ b/src/mongo/bson/bsonmisc.h
@@ -0,0 +1,211 @@
+// @file bsonmisc.h
+
+/* Copyright 2009 10gen Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+namespace mongo {
+
+ int getGtLtOp(const BSONElement& e);
+
+ struct BSONElementCmpWithoutField {
+ bool operator()( const BSONElement &l, const BSONElement &r ) const {
+ return l.woCompare( r, false ) < 0;
+ }
+ };
+
+ class BSONObjCmp {
+ public:
+ BSONObjCmp( const BSONObj &order = BSONObj() ) : _order( order ) {}
+ bool operator()( const BSONObj &l, const BSONObj &r ) const {
+ return l.woCompare( r, _order ) < 0;
+ }
+ BSONObj order() const { return _order; }
+ private:
+ BSONObj _order;
+ };
+
+ typedef set<BSONObj,BSONObjCmp> BSONObjSet;
+
+ enum FieldCompareResult {
+ LEFT_SUBFIELD = -2,
+ LEFT_BEFORE = -1,
+ SAME = 0,
+ RIGHT_BEFORE = 1 ,
+ RIGHT_SUBFIELD = 2
+ };
+
+ FieldCompareResult compareDottedFieldNames( const string& l , const string& r );
+
+ /** Use BSON macro to build a BSONObj from a stream
+
+ e.g.,
+ BSON( "name" << "joe" << "age" << 33 )
+
+ with auto-generated object id:
+ BSON( GENOID << "name" << "joe" << "age" << 33 )
+
+ The labels GT, GTE, LT, LTE, NE can be helpful for stream-oriented construction
+ of a BSONObj, particularly when assembling a Query. For example,
+ BSON( "a" << GT << 23.4 << NE << 30 << "b" << 2 ) produces the object
+ { a: { \$gt: 23.4, \$ne: 30 }, b: 2 }.
+ */
+#define BSON(x) (( mongo::BSONObjBuilder(64) << x ).obj())
+
+ /** Use BSON_ARRAY macro like BSON macro, but without keys
+
+ BSONArray arr = BSON_ARRAY( "hello" << 1 << BSON( "foo" << BSON_ARRAY( "bar" << "baz" << "qux" ) ) );
+
+ */
+#define BSON_ARRAY(x) (( mongo::BSONArrayBuilder() << x ).arr())
+
+ /* Utility class to auto assign object IDs.
+ Example:
+ cout << BSON( GENOID << "z" << 3 ); // { _id : ..., z : 3 }
+ */
+ extern struct GENOIDLabeler { } GENOID;
+
+ /* Utility class to add a Date element with the current time
+ Example:
+ cout << BSON( "created" << DATENOW ); // { created : "2009-10-09 11:41:42" }
+ */
+ extern struct DateNowLabeler { } DATENOW;
+
+ /* Utility class to assign a NULL value to a given attribute
+ Example:
+ cout << BSON( "a" << BSONNULL ); // { a : null }
+ */
+ extern struct NullLabeler { } BSONNULL;
+
+ /* Utility class to add the minKey (minus infinity) to a given attribute
+ Example:
+ cout << BSON( "a" << MINKEY ); // { "a" : { "$minKey" : 1 } }
+ */
+ extern struct MinKeyLabeler { } MINKEY;
+ extern struct MaxKeyLabeler { } MAXKEY;
+
+ // Utility class to implement GT, GTE, etc as described above.
+ class Labeler {
+ public:
+ struct Label {
+ Label( const char *l ) : l_( l ) {}
+ const char *l_;
+ };
+ Labeler( const Label &l, BSONObjBuilderValueStream *s ) : l_( l ), s_( s ) {}
+ template<class T>
+ BSONObjBuilder& operator<<( T value );
+
+ /* the value of the element e is appended i.e. for
+ "age" << GT << someElement
+ one gets
+ { age : { $gt : someElement's value } }
+ */
+ BSONObjBuilder& operator<<( const BSONElement& e );
+ private:
+ const Label &l_;
+ BSONObjBuilderValueStream *s_;
+ };
+
+ extern Labeler::Label GT;
+ extern Labeler::Label GTE;
+ extern Labeler::Label LT;
+ extern Labeler::Label LTE;
+ extern Labeler::Label NE;
+ extern Labeler::Label SIZE;
+
+
+ // $or helper: OR(BSON("x" << GT << 7), BSON("y" << LT << 6));
+ // becomes : {$or: [{x: {$gt: 7}}, {y: {$lt: 6}}]}
+ inline BSONObj OR(const BSONObj& a, const BSONObj& b);
+ inline BSONObj OR(const BSONObj& a, const BSONObj& b, const BSONObj& c);
+ inline BSONObj OR(const BSONObj& a, const BSONObj& b, const BSONObj& c, const BSONObj& d);
+ inline BSONObj OR(const BSONObj& a, const BSONObj& b, const BSONObj& c, const BSONObj& d, const BSONObj& e);
+ inline BSONObj OR(const BSONObj& a, const BSONObj& b, const BSONObj& c, const BSONObj& d, const BSONObj& e, const BSONObj& f);
+ // definitions in bsonobjbuilder.h b/c of incomplete types
+
+ // Utility class to implement BSON( key << val ) as described above.
+ class BSONObjBuilderValueStream : public boost::noncopyable {
+ public:
+ friend class Labeler;
+ BSONObjBuilderValueStream( BSONObjBuilder * builder );
+
+ BSONObjBuilder& operator<<( const BSONElement& e );
+
+ template<class T>
+ BSONObjBuilder& operator<<( T value );
+
+ BSONObjBuilder& operator<<(DateNowLabeler& id);
+
+ BSONObjBuilder& operator<<(NullLabeler& id);
+
+ BSONObjBuilder& operator<<(MinKeyLabeler& id);
+ BSONObjBuilder& operator<<(MaxKeyLabeler& id);
+
+ Labeler operator<<( const Labeler::Label &l );
+
+ void endField( const char *nextFieldName = 0 );
+ bool subobjStarted() const { return _fieldName != 0; }
+
+ private:
+ const char * _fieldName;
+ BSONObjBuilder * _builder;
+
+ bool haveSubobj() const { return _subobj.get() != 0; }
+ BSONObjBuilder *subobj();
+ auto_ptr< BSONObjBuilder > _subobj;
+ };
+
+ /**
+ used in conjuction with BSONObjBuilder, allows for proper buffer size to prevent crazy memory usage
+ */
+ class BSONSizeTracker {
+ public:
+ BSONSizeTracker() {
+ _pos = 0;
+ for ( int i=0; i<SIZE; i++ )
+ _sizes[i] = 512; // this is the default, so just be consistent
+ }
+
+ ~BSONSizeTracker() {
+ }
+
+ void got( int size ) {
+ _sizes[_pos++] = size;
+ if ( _pos >= SIZE )
+ _pos = 0;
+ }
+
+ /**
+ * right now choosing largest size
+ */
+ int getSize() const {
+ int x = 16; // sane min
+ for ( int i=0; i<SIZE; i++ ) {
+ if ( _sizes[i] > x )
+ x = _sizes[i];
+ }
+ return x;
+ }
+
+ private:
+ enum { SIZE = 10 };
+ int _pos;
+ int _sizes[SIZE];
+ };
+
+ // considers order
+ bool fieldsMatch(const BSONObj& lhs, const BSONObj& rhs);
+}
diff --git a/src/mongo/bson/bsonobj.h b/src/mongo/bson/bsonobj.h
new file mode 100644
index 00000000000..e8ce462403b
--- /dev/null
+++ b/src/mongo/bson/bsonobj.h
@@ -0,0 +1,497 @@
+// @file bsonobj.h
+
+/* Copyright 2009 10gen Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <boost/intrusive_ptr.hpp>
+#include <set>
+#include <list>
+#include <vector>
+#include "util/atomic_int.h"
+#include "util/builder.h"
+#include "stringdata.h"
+
+namespace mongo {
+
+ typedef set< BSONElement, BSONElementCmpWithoutField > BSONElementSet;
+ typedef multiset< BSONElement, BSONElementCmpWithoutField > BSONElementMSet;
+
+ /**
+ C++ representation of a "BSON" object -- that is, an extended JSON-style
+ object in a binary representation.
+
+ See bsonspec.org.
+
+ Note that BSONObj's have a smart pointer capability built in -- so you can
+ pass them around by value. The reference counts used to implement this
+ do not use locking, so copying and destroying BSONObj's are not thread-safe
+ operations.
+
+ BSON object format:
+
+ code
+ <unsigned totalSize> {<byte BSONType><cstring FieldName><Data>}* EOO
+
+ totalSize includes itself.
+
+ Data:
+ Bool: <byte>
+ EOO: nothing follows
+ Undefined: nothing follows
+ OID: an OID object
+ NumberDouble: <double>
+ NumberInt: <int32>
+ String: <unsigned32 strsizewithnull><cstring>
+ Date: <8bytes>
+ Regex: <cstring regex><cstring options>
+ Object: a nested object, leading with its entire size, which terminates with EOO.
+ Array: same as object
+ DBRef: <strlen> <cstring ns> <oid>
+ DBRef: a database reference: basically a collection name plus an Object ID
+ BinData: <int len> <byte subtype> <byte[len] data>
+ Code: a function (not a closure): same format as String.
+ Symbol: a language symbol (say a python symbol). same format as String.
+ Code With Scope: <total size><String><Object>
+ \endcode
+ */
+ class BSONObj {
+ public:
+
+ /** Construct a BSONObj from data in the proper format.
+ * Use this constructor when something else owns msgdata's buffer
+ */
+ explicit BSONObj(const char *msgdata) {
+ init(msgdata);
+ }
+
+ /** Construct a BSONObj from data in the proper format.
+ * Use this constructor when you want BSONObj to free(holder) when it is no longer needed
+ * BSONObj::Holder has an extra 4 bytes for a ref-count before the start of the object
+ */
+ class Holder;
+ explicit BSONObj(Holder* holder) {
+ init(holder);
+ }
+
+ explicit BSONObj(const Record *r);
+
+ /** Construct an empty BSONObj -- that is, {}. */
+ BSONObj();
+
+ ~BSONObj() {
+ _objdata = 0; // defensive
+ }
+
+ /**
+ A BSONObj can use a buffer it "owns" or one it does not.
+
+ OWNED CASE
+ If the BSONObj owns the buffer, the buffer can be shared among several BSONObj's (by assignment).
+ In this case the buffer is basically implemented as a shared_ptr.
+ Since BSONObj's are typically immutable, this works well.
+
+ UNOWNED CASE
+ A BSONObj can also point to BSON data in some other data structure it does not "own" or free later.
+ For example, in a memory mapped file. In this case, it is important the original data stays in
+ scope for as long as the BSONObj is in use. If you think the original data may go out of scope,
+ call BSONObj::getOwned() to promote your BSONObj to having its own copy.
+
+ On a BSONObj assignment, if the source is unowned, both the source and dest will have unowned
+ pointers to the original buffer after the assignment.
+
+ If you are not sure about ownership but need the buffer to last as long as the BSONObj, call
+ getOwned(). getOwned() is a no-op if the buffer is already owned. If not already owned, a malloc
+ and memcpy will result.
+
+ Most ways to create BSONObj's create 'owned' variants. Unowned versions can be created with:
+ (1) specifying true for the ifree parameter in the constructor
+ (2) calling BSONObjBuilder::done(). Use BSONObjBuilder::obj() to get an owned copy
+ (3) retrieving a subobject retrieves an unowned pointer into the parent BSON object
+
+ @return true if this is in owned mode
+ */
+ bool isOwned() const { return _holder.get() != 0; }
+
+ /** assure the data buffer is under the control of this BSONObj and not a remote buffer
+ @see isOwned()
+ */
+ BSONObj getOwned() const;
+
+ /** @return a new full (and owned) copy of the object. */
+ BSONObj copy() const;
+
+ /** Readable representation of a BSON object in an extended JSON-style notation.
+ This is an abbreviated representation which might be used for logging.
+ */
+ string toString( bool isArray = false, bool full=false ) const;
+ void toString(StringBuilder& s, bool isArray = false, bool full=false ) const;
+
+ /** Properly formatted JSON string.
+ @param pretty if true we try to add some lf's and indentation
+ */
+ string jsonString( JsonStringFormat format = Strict, int pretty = 0 ) const;
+
+ /** note: addFields always adds _id even if not specified */
+ int addFields(BSONObj& from, set<string>& fields); /* returns n added */
+
+ /** remove specified field and return a new object with the remaining fields.
+ slowish as builds a full new object
+ */
+ BSONObj removeField(const StringData& name) const;
+
+ /** returns # of top level fields in the object
+ note: iterates to count the fields
+ */
+ int nFields() const;
+
+ /** adds the field names to the fields set. does NOT clear it (appends). */
+ int getFieldNames(set<string>& fields) const;
+
+ /** @return the specified element. element.eoo() will be true if not found.
+ @param name field to find. supports dot (".") notation to reach into embedded objects.
+ for example "x.y" means "in the nested object in field x, retrieve field y"
+ */
+ BSONElement getFieldDotted(const char *name) const;
+ /** @return the specified element. element.eoo() will be true if not found.
+ @param name field to find. supports dot (".") notation to reach into embedded objects.
+ for example "x.y" means "in the nested object in field x, retrieve field y"
+ */
+ BSONElement getFieldDotted(const string& name) const {
+ return getFieldDotted( name.c_str() );
+ }
+
+ /** Like getFieldDotted(), but expands arrays and returns all matching objects.
+ * Turning off expandLastArray allows you to retrieve nested array objects instead of
+ * their contents.
+ */
+ void getFieldsDotted(const StringData& name, BSONElementSet &ret, bool expandLastArray = true ) const;
+ void getFieldsDotted(const StringData& name, BSONElementMSet &ret, bool expandLastArray = true ) const;
+
+ /** Like getFieldDotted(), but returns first array encountered while traversing the
+ dotted fields of name. The name variable is updated to represent field
+ names with respect to the returned element. */
+ BSONElement getFieldDottedOrArray(const char *&name) const;
+
+ /** Get the field of the specified name. eoo() is true on the returned
+ element if not found.
+ */
+ BSONElement getField(const StringData& name) const;
+
+ /** Get several fields at once. This is faster than separate getField() calls as the size of
+ elements iterated can then be calculated only once each.
+ @param n number of fieldNames, and number of elements in the fields array
+ @param fields if a field is found its element is stored in its corresponding position in this array.
+ if not found the array element is unchanged.
+ */
+ void getFields(unsigned n, const char **fieldNames, BSONElement *fields) const;
+
+ /** Get the field of the specified name. eoo() is true on the returned
+ element if not found.
+ */
+ BSONElement operator[] (const char *field) const {
+ return getField(field);
+ }
+
+ BSONElement operator[] (const string& field) const {
+ return getField(field);
+ }
+
+ BSONElement operator[] (int field) const {
+ StringBuilder ss;
+ ss << field;
+ string s = ss.str();
+ return getField(s.c_str());
+ }
+
+ /** @return true if field exists */
+ bool hasField( const char * name ) const { return !getField(name).eoo(); }
+ /** @return true if field exists */
+ bool hasElement(const char *name) const { return hasField(name); }
+
+ /** @return "" if DNE or wrong type */
+ const char * getStringField(const char *name) const;
+
+ /** @return subobject of the given name */
+ BSONObj getObjectField(const char *name) const;
+
+ /** @return INT_MIN if not present - does some type conversions */
+ int getIntField(const char *name) const;
+
+ /** @return false if not present
+ @see BSONElement::trueValue()
+ */
+ bool getBoolField(const char *name) const;
+
+ /**
+ sets element field names to empty string
+ If a field in pattern is missing, it is omitted from the returned
+ object.
+ */
+ BSONObj extractFieldsUnDotted(BSONObj pattern) const;
+
+ /** extract items from object which match a pattern object.
+ e.g., if pattern is { x : 1, y : 1 }, builds an object with
+ x and y elements of this object, if they are present.
+ returns elements with original field names
+ */
+ BSONObj extractFields(const BSONObj &pattern , bool fillWithNull=false) const;
+
+ BSONObj filterFieldsUndotted(const BSONObj &filter, bool inFilter) const;
+
+ BSONElement getFieldUsingIndexNames(const char *fieldName, const BSONObj &indexKey) const;
+
+ /** arrays are bson objects with numeric and increasing field names
+ @return true if field names are numeric and increasing
+ */
+ bool couldBeArray() const;
+
+ /** @return the raw data of the object */
+ const char *objdata() const {
+ return _objdata;
+ }
+ /** @return total size of the BSON object in bytes */
+ int objsize() const { return *(reinterpret_cast<const int*>(objdata())); }
+
+ /** performs a cursory check on the object's size only. */
+ bool isValid() const;
+
+ /** @return if the user is a valid user doc
+ criter: isValid() no . or $ field names
+ */
+ bool okForStorage() const;
+
+ /** @return true if object is empty -- i.e., {} */
+ bool isEmpty() const { return objsize() <= 5; }
+
+ void dump() const;
+
+ /** Alternative output format */
+ string hexDump() const;
+
+ /**wo='well ordered'. fields must be in same order in each object.
+ Ordering is with respect to the signs of the elements
+ and allows ascending / descending key mixing.
+ @return <0 if l<r. 0 if l==r. >0 if l>r
+ */
+ int woCompare(const BSONObj& r, const Ordering &o,
+ bool considerFieldName=true) const;
+
+ /**wo='well ordered'. fields must be in same order in each object.
+ Ordering is with respect to the signs of the elements
+ and allows ascending / descending key mixing.
+ @return <0 if l<r. 0 if l==r. >0 if l>r
+ */
+ int woCompare(const BSONObj& r, const BSONObj &ordering = BSONObj(),
+ bool considerFieldName=true) const;
+
+ bool operator<( const BSONObj& other ) const { return woCompare( other ) < 0; }
+ bool operator<=( const BSONObj& other ) const { return woCompare( other ) <= 0; }
+ bool operator>( const BSONObj& other ) const { return woCompare( other ) > 0; }
+ bool operator>=( const BSONObj& other ) const { return woCompare( other ) >= 0; }
+
+ /**
+ * @param useDotted whether to treat sort key fields as possibly dotted and expand into them
+ */
+ int woSortOrder( const BSONObj& r , const BSONObj& sortKey , bool useDotted=false ) const;
+
+ bool equal(const BSONObj& r) const;
+
+ /** This is "shallow equality" -- ints and doubles won't match. for a
+ deep equality test use woCompare (which is slower).
+ */
+ bool binaryEqual(const BSONObj& r) const {
+ int os = objsize();
+ if ( os == r.objsize() ) {
+ return (os == 0 || memcmp(objdata(),r.objdata(),os)==0);
+ }
+ return false;
+ }
+
+ /** @return first field of the object */
+ BSONElement firstElement() const { return BSONElement(objdata() + 4); }
+
+ /** faster than firstElement().fieldName() - for the first element we can easily find the fieldname without
+ computing the element size.
+ */
+ const char * firstElementFieldName() const {
+ const char *p = objdata() + 4;
+ return *p == EOO ? "" : p+1;
+ }
+
+ BSONType firstElementType() const {
+ const char *p = objdata() + 4;
+ return (BSONType) *p;
+ }
+
+ /** Get the _id field from the object. For good performance drivers should
+ assure that _id is the first element of the object; however, correct operation
+ is assured regardless.
+ @return true if found
+ */
+ bool getObjectID(BSONElement& e) const;
+
+ /** @return A hash code for the object */
+ int hash() const {
+ unsigned x = 0;
+ const char *p = objdata();
+ for ( int i = 0; i < objsize(); i++ )
+ x = x * 131 + p[i];
+ return (x & 0x7fffffff) | 0x8000000; // must be > 0
+ }
+
+ // Return a version of this object where top level elements of types
+ // that are not part of the bson wire protocol are replaced with
+ // string identifier equivalents.
+ // TODO Support conversion of element types other than min and max.
+ BSONObj clientReadable() const;
+
+ /** Return new object with the field names replaced by those in the
+ passed object. */
+ BSONObj replaceFieldNames( const BSONObj &obj ) const;
+
+ /** true unless corrupt */
+ bool valid() const;
+
+ /** @return an md5 value for this object. */
+ string md5() const;
+
+ bool operator==( const BSONObj& other ) const { return equal( other ); }
+ bool operator!=(const BSONObj& other) const { return !operator==( other); }
+
+ enum MatchType {
+ Equality = 0,
+ LT = 0x1,
+ LTE = 0x3,
+ GTE = 0x6,
+ GT = 0x4,
+ opIN = 0x8, // { x : { $in : [1,2,3] } }
+ NE = 0x9,
+ opSIZE = 0x0A,
+ opALL = 0x0B,
+ NIN = 0x0C,
+ opEXISTS = 0x0D,
+ opMOD = 0x0E,
+ opTYPE = 0x0F,
+ opREGEX = 0x10,
+ opOPTIONS = 0x11,
+ opELEM_MATCH = 0x12,
+ opNEAR = 0x13,
+ opWITHIN = 0x14,
+ opMAX_DISTANCE=0x15
+ };
+
+ /** add all elements of the object to the specified vector */
+ void elems(vector<BSONElement> &) const;
+ /** add all elements of the object to the specified list */
+ void elems(list<BSONElement> &) const;
+
+ /** add all values of the object to the specified vector. If type mismatches, exception.
+ this is most useful when the BSONObj is an array, but can be used with non-arrays too in theory.
+
+ example:
+ bo sub = y["subobj"].Obj();
+ vector<int> myints;
+ sub.Vals(myints);
+ */
+ template <class T>
+ void Vals(vector<T> &) const;
+ /** add all values of the object to the specified list. If type mismatches, exception. */
+ template <class T>
+ void Vals(list<T> &) const;
+
+ /** add all values of the object to the specified vector. If type mismatches, skip. */
+ template <class T>
+ void vals(vector<T> &) const;
+ /** add all values of the object to the specified list. If type mismatches, skip. */
+ template <class T>
+ void vals(list<T> &) const;
+
+ friend class BSONObjIterator;
+ typedef BSONObjIterator iterator;
+
+ /** use something like this:
+ for( BSONObj::iterator i = myObj.begin(); i.more(); ) {
+ BSONElement e = i.next();
+ ...
+ }
+ */
+ BSONObjIterator begin() const;
+
+ void appendSelfToBufBuilder(BufBuilder& b) const {
+ assert( objsize() );
+ b.appendBuf(reinterpret_cast<const void *>( objdata() ), objsize());
+ }
+
+#pragma pack(1)
+ class Holder : boost::noncopyable {
+ private:
+ Holder(); // this class should never be explicitly created
+ AtomicUInt refCount;
+ public:
+ char data[4]; // start of object
+
+ void zero() { refCount.zero(); }
+
+ // these are called automatically by boost::intrusive_ptr
+ friend void intrusive_ptr_add_ref(Holder* h) { h->refCount++; }
+ friend void intrusive_ptr_release(Holder* h) {
+#if defined(_DEBUG) // cant use dassert or DEV here
+ assert((int)h->refCount > 0); // make sure we haven't already freed the buffer
+#endif
+ if(--(h->refCount) == 0){
+#if defined(_DEBUG)
+ unsigned sz = (unsigned&) *h->data;
+ assert(sz < BSONObjMaxInternalSize * 3);
+ memset(h->data, 0xdd, sz);
+#endif
+ free(h);
+ }
+ }
+ };
+#pragma pack()
+
+ private:
+ const char *_objdata;
+ boost::intrusive_ptr< Holder > _holder;
+
+ void _assertInvalid() const;
+
+ void init(Holder *holder) {
+ _holder = holder; // holder is now managed by intrusive_ptr
+ init(holder->data);
+ }
+ void init(const char *data) {
+ _objdata = data;
+ if ( !isValid() )
+ _assertInvalid();
+ }
+ };
+
+ ostream& operator<<( ostream &s, const BSONObj &o );
+ ostream& operator<<( ostream &s, const BSONElement &e );
+
+ StringBuilder& operator<<( StringBuilder &s, const BSONObj &o );
+ StringBuilder& operator<<( StringBuilder &s, const BSONElement &e );
+
+
+ struct BSONArray : BSONObj {
+ // Don't add anything other than forwarding constructors!!!
+ BSONArray(): BSONObj() {}
+ explicit BSONArray(const BSONObj& obj): BSONObj(obj) {}
+ };
+
+}
diff --git a/src/mongo/bson/bsonobjbuilder.h b/src/mongo/bson/bsonobjbuilder.h
new file mode 100644
index 00000000000..1fdbcba18a6
--- /dev/null
+++ b/src/mongo/bson/bsonobjbuilder.h
@@ -0,0 +1,842 @@
+/* bsonobjbuilder.h
+
+ Classes in this file:
+ BSONObjBuilder
+ BSONArrayBuilder
+*/
+
+/* Copyright 2009 10gen Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <limits>
+#include <cmath>
+#include <boost/static_assert.hpp>
+#include "bsonelement.h"
+#include "bsonobj.h"
+#include "bsonmisc.h"
+
+namespace mongo {
+
+ using namespace std;
+
+#if defined(_WIN32)
+// warning: 'this' : used in base member initializer list
+#pragma warning( disable : 4355 )
+#endif
+
+ template<typename T>
+ class BSONFieldValue {
+ public:
+ BSONFieldValue( const string& name , const T& t ) {
+ _name = name;
+ _t = t;
+ }
+
+ const T& value() const { return _t; }
+ const string& name() const { return _name; }
+
+ private:
+ string _name;
+ T _t;
+ };
+
+ template<typename T>
+ class BSONField {
+ public:
+ BSONField( const string& name , const string& longName="" )
+ : _name(name), _longName(longName) {}
+ const string& name() const { return _name; }
+ operator string() const { return _name; }
+
+ BSONFieldValue<T> make( const T& t ) const {
+ return BSONFieldValue<T>( _name , t );
+ }
+
+ BSONFieldValue<BSONObj> gt( const T& t ) const { return query( "$gt" , t ); }
+ BSONFieldValue<BSONObj> lt( const T& t ) const { return query( "$lt" , t ); }
+
+ BSONFieldValue<BSONObj> query( const char * q , const T& t ) const;
+
+ BSONFieldValue<T> operator()( const T& t ) const {
+ return BSONFieldValue<T>( _name , t );
+ }
+
+ private:
+ string _name;
+ string _longName;
+ };
+
+ /** Utility for creating a BSONObj.
+ See also the BSON() and BSON_ARRAY() macros.
+ */
+ class BSONObjBuilder : boost::noncopyable {
+ public:
+ /** @param initsize this is just a hint as to the final size of the object */
+ BSONObjBuilder(int initsize=512) : _b(_buf), _buf(initsize + sizeof(unsigned)), _offset( sizeof(unsigned) ), _s( this ) , _tracker(0) , _doneCalled(false) {
+ _b.appendNum((unsigned)0); // ref-count
+ _b.skip(4); /*leave room for size field and ref-count*/
+ }
+
+ /** @param baseBuilder construct a BSONObjBuilder using an existing BufBuilder
+ * This is for more efficient adding of subobjects/arrays. See docs for subobjStart for example.
+ */
+ BSONObjBuilder( BufBuilder &baseBuilder ) : _b( baseBuilder ), _buf( 0 ), _offset( baseBuilder.len() ), _s( this ) , _tracker(0) , _doneCalled(false) {
+ _b.skip( 4 );
+ }
+
+ BSONObjBuilder( const BSONSizeTracker & tracker ) : _b(_buf) , _buf(tracker.getSize() + sizeof(unsigned) ), _offset( sizeof(unsigned) ), _s( this ) , _tracker( (BSONSizeTracker*)(&tracker) ) , _doneCalled(false) {
+ _b.appendNum((unsigned)0); // ref-count
+ _b.skip(4);
+ }
+
+ ~BSONObjBuilder() {
+ if ( !_doneCalled && _b.buf() && _buf.getSize() == 0 ) {
+ _done();
+ }
+ }
+
+ /** add all the fields from the object specified to this object */
+ BSONObjBuilder& appendElements(BSONObj x);
+
+ /** add all the fields from the object specified to this object if they don't exist already */
+ BSONObjBuilder& appendElementsUnique( BSONObj x );
+
+ /** append element to the object we are building */
+ BSONObjBuilder& append( const BSONElement& e) {
+ assert( !e.eoo() ); // do not append eoo, that would corrupt us. the builder auto appends when done() is called.
+ _b.appendBuf((void*) e.rawdata(), e.size());
+ return *this;
+ }
+
+ /** append an element but with a new name */
+ BSONObjBuilder& appendAs(const BSONElement& e, const StringData& fieldName) {
+ assert( !e.eoo() ); // do not append eoo, that would corrupt us. the builder auto appends when done() is called.
+ _b.appendNum((char) e.type());
+ _b.appendStr(fieldName);
+ _b.appendBuf((void *) e.value(), e.valuesize());
+ return *this;
+ }
+
+ /** add a subobject as a member */
+ BSONObjBuilder& append(const StringData& fieldName, BSONObj subObj) {
+ _b.appendNum((char) Object);
+ _b.appendStr(fieldName);
+ _b.appendBuf((void *) subObj.objdata(), subObj.objsize());
+ return *this;
+ }
+
+ /** add a subobject as a member */
+ BSONObjBuilder& appendObject(const StringData& fieldName, const char * objdata , int size = 0 ) {
+ assert( objdata );
+ if ( size == 0 ) {
+ size = *((int*)objdata);
+ }
+
+ assert( size > 4 && size < 100000000 );
+
+ _b.appendNum((char) Object);
+ _b.appendStr(fieldName);
+ _b.appendBuf((void*)objdata, size );
+ return *this;
+ }
+
+ /** add header for a new subobject and return bufbuilder for writing to
+ * the subobject's body
+ *
+ * example:
+ *
+ * BSONObjBuilder b;
+ * BSONObjBuilder sub (b.subobjStart("fieldName"));
+ * // use sub
+ * sub.done()
+ * // use b and convert to object
+ */
+ BufBuilder &subobjStart(const StringData& fieldName) {
+ _b.appendNum((char) Object);
+ _b.appendStr(fieldName);
+ return _b;
+ }
+
+ /** add a subobject as a member with type Array. Thus arr object should have "0", "1", ...
+ style fields in it.
+ */
+ BSONObjBuilder& appendArray(const StringData& fieldName, const BSONObj &subObj) {
+ _b.appendNum((char) Array);
+ _b.appendStr(fieldName);
+ _b.appendBuf((void *) subObj.objdata(), subObj.objsize());
+ return *this;
+ }
+ BSONObjBuilder& append(const StringData& fieldName, BSONArray arr) {
+ return appendArray(fieldName, arr);
+ }
+
+ /** add header for a new subarray and return bufbuilder for writing to
+ the subarray's body */
+ BufBuilder &subarrayStart(const StringData& fieldName) {
+ _b.appendNum((char) Array);
+ _b.appendStr(fieldName);
+ return _b;
+ }
+
+ /** Append a boolean element */
+ BSONObjBuilder& appendBool(const StringData& fieldName, int val) {
+ _b.appendNum((char) Bool);
+ _b.appendStr(fieldName);
+ _b.appendNum((char) (val?1:0));
+ return *this;
+ }
+
+ /** Append a boolean element */
+ BSONObjBuilder& append(const StringData& fieldName, bool val) {
+ _b.appendNum((char) Bool);
+ _b.appendStr(fieldName);
+ _b.appendNum((char) (val?1:0));
+ return *this;
+ }
+
+ /** Append a 32 bit integer element */
+ BSONObjBuilder& append(const StringData& fieldName, int n) {
+ _b.appendNum((char) NumberInt);
+ _b.appendStr(fieldName);
+ _b.appendNum(n);
+ return *this;
+ }
+
+ /** Append a 32 bit unsigned element - cast to a signed int. */
+ BSONObjBuilder& append(const StringData& fieldName, unsigned n) {
+ return append(fieldName, (int) n);
+ }
+
+ /** Append a NumberLong */
+ BSONObjBuilder& append(const StringData& fieldName, long long n) {
+ _b.appendNum((char) NumberLong);
+ _b.appendStr(fieldName);
+ _b.appendNum(n);
+ return *this;
+ }
+
+ /** appends a number. if n < max(int)/2 then uses int, otherwise long long */
+ BSONObjBuilder& appendIntOrLL( const StringData& fieldName , long long n ) {
+ long long x = n;
+ if ( x < 0 )
+ x = x * -1;
+ if ( x < ( (numeric_limits<int>::max)() / 2 ) ) // extra () to avoid max macro on windows
+ append( fieldName , (int)n );
+ else
+ append( fieldName , n );
+ return *this;
+ }
+
+ /**
+ * appendNumber is a series of method for appending the smallest sensible type
+ * mostly for JS
+ */
+ BSONObjBuilder& appendNumber( const StringData& fieldName , int n ) {
+ return append( fieldName , n );
+ }
+
+ BSONObjBuilder& appendNumber( const StringData& fieldName , double d ) {
+ return append( fieldName , d );
+ }
+
+ BSONObjBuilder& appendNumber( const StringData& fieldName , size_t n ) {
+ static size_t maxInt = (size_t)pow( 2.0 , 30.0 );
+
+ if ( n < maxInt )
+ append( fieldName , (int)n );
+ else
+ append( fieldName , (long long)n );
+ return *this;
+ }
+
+ BSONObjBuilder& appendNumber( const StringData& fieldName , long long l ) {
+ static long long maxInt = (int)pow( 2.0 , 30.0 );
+ static long long maxDouble = (long long)pow( 2.0 , 40.0 );
+ long long x = l >= 0 ? l : -l;
+ if ( x < maxInt )
+ append( fieldName , (int)l );
+ else if ( x < maxDouble )
+ append( fieldName , (double)l );
+ else
+ append( fieldName , l );
+ return *this;
+ }
+
+ /** Append a double element */
+ BSONObjBuilder& append(const StringData& fieldName, double n) {
+ _b.appendNum((char) NumberDouble);
+ _b.appendStr(fieldName);
+ _b.appendNum(n);
+ return *this;
+ }
+
+ /** tries to append the data as a number
+ * @return true if the data was able to be converted to a number
+ */
+ bool appendAsNumber( const StringData& fieldName , const string& data );
+
+ /** Append a BSON Object ID (OID type).
+ @deprecated Generally, it is preferred to use the append append(name, oid)
+ method for this.
+ */
+ BSONObjBuilder& appendOID(const StringData& fieldName, OID *oid = 0 , bool generateIfBlank = false ) {
+ _b.appendNum((char) jstOID);
+ _b.appendStr(fieldName);
+ if ( oid )
+ _b.appendBuf( (void *) oid, 12 );
+ else {
+ OID tmp;
+ if ( generateIfBlank )
+ tmp.init();
+ else
+ tmp.clear();
+ _b.appendBuf( (void *) &tmp, 12 );
+ }
+ return *this;
+ }
+
+ /**
+ Append a BSON Object ID.
+ @param fieldName Field name, e.g., "_id".
+ @returns the builder object
+ */
+ BSONObjBuilder& append( const StringData& fieldName, OID oid ) {
+ _b.appendNum((char) jstOID);
+ _b.appendStr(fieldName);
+ _b.appendBuf( (void *) &oid, 12 );
+ return *this;
+ }
+
+ /**
+ Generate and assign an object id for the _id field.
+ _id should be the first element in the object for good performance.
+ */
+ BSONObjBuilder& genOID() {
+ return append("_id", OID::gen());
+ }
+
+ /** Append a time_t date.
+ @param dt a C-style 32 bit date value, that is
+ the number of seconds since January 1, 1970, 00:00:00 GMT
+ */
+ BSONObjBuilder& appendTimeT(const StringData& fieldName, time_t dt) {
+ _b.appendNum((char) Date);
+ _b.appendStr(fieldName);
+ _b.appendNum(static_cast<unsigned long long>(dt) * 1000);
+ return *this;
+ }
+ /** Append a date.
+ @param dt a Java-style 64 bit date value, that is
+ the number of milliseconds since January 1, 1970, 00:00:00 GMT
+ */
+ BSONObjBuilder& appendDate(const StringData& fieldName, Date_t dt) {
+ /* easy to pass a time_t to this and get a bad result. thus this warning. */
+#if defined(_DEBUG) && defined(MONGO_EXPOSE_MACROS)
+ if( dt > 0 && dt <= 0xffffffff ) {
+ static int n;
+ if( n++ == 0 )
+ log() << "DEV WARNING appendDate() called with a tiny (but nonzero) date" << endl;
+ }
+#endif
+ _b.appendNum((char) Date);
+ _b.appendStr(fieldName);
+ _b.appendNum(dt);
+ return *this;
+ }
+ BSONObjBuilder& append(const StringData& fieldName, Date_t dt) {
+ return appendDate(fieldName, dt);
+ }
+
+ /** Append a regular expression value
+ @param regex the regular expression pattern
+ @param regex options such as "i" or "g"
+ */
+ BSONObjBuilder& appendRegex(const StringData& fieldName, const StringData& regex, const StringData& options = "") {
+ _b.appendNum((char) RegEx);
+ _b.appendStr(fieldName);
+ _b.appendStr(regex);
+ _b.appendStr(options);
+ return *this;
+ }
+
+ BSONObjBuilder& appendCode(const StringData& fieldName, const StringData& code) {
+ _b.appendNum((char) Code);
+ _b.appendStr(fieldName);
+ _b.appendNum((int) code.size()+1);
+ _b.appendStr(code);
+ return *this;
+ }
+
+ /** Append a string element.
+ @param sz size includes terminating null character */
+ BSONObjBuilder& append(const StringData& fieldName, const char *str, int sz) {
+ _b.appendNum((char) String);
+ _b.appendStr(fieldName);
+ _b.appendNum((int)sz);
+ _b.appendBuf(str, sz);
+ return *this;
+ }
+ /** Append a string element */
+ BSONObjBuilder& append(const StringData& fieldName, const char *str) {
+ return append(fieldName, str, (int) strlen(str)+1);
+ }
+ /** Append a string element */
+ BSONObjBuilder& append(const StringData& fieldName, const string& str) {
+ return append(fieldName, str.c_str(), (int) str.size()+1);
+ }
+
+ BSONObjBuilder& appendSymbol(const StringData& fieldName, const StringData& symbol) {
+ _b.appendNum((char) Symbol);
+ _b.appendStr(fieldName);
+ _b.appendNum((int) symbol.size()+1);
+ _b.appendStr(symbol);
+ return *this;
+ }
+
+ /** Append a Null element to the object */
+ BSONObjBuilder& appendNull( const StringData& fieldName ) {
+ _b.appendNum( (char) jstNULL );
+ _b.appendStr( fieldName );
+ return *this;
+ }
+
+ // Append an element that is less than all other keys.
+ BSONObjBuilder& appendMinKey( const StringData& fieldName ) {
+ _b.appendNum( (char) MinKey );
+ _b.appendStr( fieldName );
+ return *this;
+ }
+ // Append an element that is greater than all other keys.
+ BSONObjBuilder& appendMaxKey( const StringData& fieldName ) {
+ _b.appendNum( (char) MaxKey );
+ _b.appendStr( fieldName );
+ return *this;
+ }
+
+ // Append a Timestamp field -- will be updated to next OpTime on db insert.
+ BSONObjBuilder& appendTimestamp( const StringData& fieldName ) {
+ _b.appendNum( (char) Timestamp );
+ _b.appendStr( fieldName );
+ _b.appendNum( (unsigned long long) 0 );
+ return *this;
+ }
+
+ BSONObjBuilder& appendTimestamp( const StringData& fieldName , unsigned long long val ) {
+ _b.appendNum( (char) Timestamp );
+ _b.appendStr( fieldName );
+ _b.appendNum( val );
+ return *this;
+ }
+
+ /**
+ Timestamps are a special BSON datatype that is used internally for replication.
+ Append a timestamp element to the object being ebuilt.
+ @param time - in millis (but stored in seconds)
+ */
+ BSONObjBuilder& appendTimestamp( const StringData& fieldName , unsigned long long time , unsigned int inc );
+
+ /*
+ Append an element of the deprecated DBRef type.
+ @deprecated
+ */
+ BSONObjBuilder& appendDBRef( const StringData& fieldName, const StringData& ns, const OID &oid ) {
+ _b.appendNum( (char) DBRef );
+ _b.appendStr( fieldName );
+ _b.appendNum( (int) ns.size() + 1 );
+ _b.appendStr( ns );
+ _b.appendBuf( (void *) &oid, 12 );
+ return *this;
+ }
+
+ /** Append a binary data element
+ @param fieldName name of the field
+ @param len length of the binary data in bytes
+ @param subtype subtype information for the data. @see enum BinDataType in bsontypes.h.
+ Use BinDataGeneral if you don't care about the type.
+ @param data the byte array
+ */
+ BSONObjBuilder& appendBinData( const StringData& fieldName, int len, BinDataType type, const void *data ) {
+ _b.appendNum( (char) BinData );
+ _b.appendStr( fieldName );
+ _b.appendNum( len );
+ _b.appendNum( (char) type );
+ _b.appendBuf( data, len );
+ return *this;
+ }
+
+ /**
+ Subtype 2 is deprecated.
+ Append a BSON bindata bytearray element.
+ @param data a byte array
+ @param len the length of data
+ */
+ BSONObjBuilder& appendBinDataArrayDeprecated( const char * fieldName , const void * data , int len ) {
+ _b.appendNum( (char) BinData );
+ _b.appendStr( fieldName );
+ _b.appendNum( len + 4 );
+ _b.appendNum( (char)0x2 );
+ _b.appendNum( len );
+ _b.appendBuf( data, len );
+ return *this;
+ }
+
+ /** Append to the BSON object a field of type CodeWScope. This is a javascript code
+ fragment accompanied by some scope that goes with it.
+ */
+ BSONObjBuilder& appendCodeWScope( const StringData& fieldName, const StringData& code, const BSONObj &scope ) {
+ _b.appendNum( (char) CodeWScope );
+ _b.appendStr( fieldName );
+ _b.appendNum( ( int )( 4 + 4 + code.size() + 1 + scope.objsize() ) );
+ _b.appendNum( ( int ) code.size() + 1 );
+ _b.appendStr( code );
+ _b.appendBuf( ( void * )scope.objdata(), scope.objsize() );
+ return *this;
+ }
+
+ void appendUndefined( const StringData& fieldName ) {
+ _b.appendNum( (char) Undefined );
+ _b.appendStr( fieldName );
+ }
+
+ /* helper function -- see Query::where() for primary way to do this. */
+ void appendWhere( const StringData& code, const BSONObj &scope ) {
+ appendCodeWScope( "$where" , code , scope );
+ }
+
+ /**
+ these are the min/max when comparing, not strict min/max elements for a given type
+ */
+ void appendMinForType( const StringData& fieldName , int type );
+ void appendMaxForType( const StringData& fieldName , int type );
+
+ /** Append an array of values. */
+ template < class T >
+ BSONObjBuilder& append( const StringData& fieldName, const vector< T >& vals );
+
+ template < class T >
+ BSONObjBuilder& append( const StringData& fieldName, const list< T >& vals );
+
+ /** Append a set of values. */
+ template < class T >
+ BSONObjBuilder& append( const StringData& fieldName, const set< T >& vals );
+
+ /**
+ * destructive
+ * The returned BSONObj will free the buffer when it is finished.
+ * @return owned BSONObj
+ */
+ BSONObj obj() {
+ bool own = owned();
+ massert( 10335 , "builder does not own memory", own );
+ doneFast();
+ BSONObj::Holder* h = (BSONObj::Holder*)_b.buf();
+ decouple(); // sets _b.buf() to NULL
+ return BSONObj(h);
+ }
+
+ /** Fetch the object we have built.
+ BSONObjBuilder still frees the object when the builder goes out of
+ scope -- very important to keep in mind. Use obj() if you
+ would like the BSONObj to last longer than the builder.
+ */
+ BSONObj done() {
+ return BSONObj(_done());
+ }
+
+ // Like 'done' above, but does not construct a BSONObj to return to the caller.
+ void doneFast() {
+ (void)_done();
+ }
+
+ /** Peek at what is in the builder, but leave the builder ready for more appends.
+ The returned object is only valid until the next modification or destruction of the builder.
+ Intended use case: append a field if not already there.
+ */
+ BSONObj asTempObj() {
+ BSONObj temp(_done());
+ _b.setlen(_b.len()-1); //next append should overwrite the EOO
+ _doneCalled = false;
+ return temp;
+ }
+
+ /* assume ownership of the buffer - you must then free it (with free()) */
+ char* decouple(int& l) {
+ char *x = _done();
+ assert( x );
+ l = _b.len();
+ _b.decouple();
+ return x;
+ }
+ void decouple() {
+ _b.decouple(); // post done() call version. be sure jsobj frees...
+ }
+
+ void appendKeys( const BSONObj& keyPattern , const BSONObj& values );
+
+ static string numStr( int i ) {
+ if (i>=0 && i<100 && numStrsReady)
+ return numStrs[i];
+ StringBuilder o;
+ o << i;
+ return o.str();
+ }
+
+ /** Stream oriented way to add field names and values. */
+ BSONObjBuilderValueStream &operator<<(const char * name ) {
+ _s.endField( name );
+ return _s;
+ }
+
+ /** Stream oriented way to add field names and values. */
+ BSONObjBuilder& operator<<( GENOIDLabeler ) { return genOID(); }
+
+ // prevent implicit string conversions which would allow bad things like BSON( BSON( "foo" << 1 ) << 2 )
+ struct ForceExplicitString {
+ ForceExplicitString( const string &str ) : str_( str ) {}
+ string str_;
+ };
+
+ /** Stream oriented way to add field names and values. */
+ BSONObjBuilderValueStream &operator<<( const ForceExplicitString& name ) {
+ return operator<<( name.str_.c_str() );
+ }
+
+ Labeler operator<<( const Labeler::Label &l ) {
+ massert( 10336 , "No subobject started", _s.subobjStarted() );
+ return _s << l;
+ }
+
+ template<typename T>
+ BSONObjBuilderValueStream& operator<<( const BSONField<T>& f ) {
+ _s.endField( f.name().c_str() );
+ return _s;
+ }
+
+ template<typename T>
+ BSONObjBuilder& operator<<( const BSONFieldValue<T>& v ) {
+ append( v.name().c_str() , v.value() );
+ return *this;
+ }
+
+ BSONObjBuilder& operator<<( const BSONElement& e ){
+ append( e );
+ return *this;
+ }
+
+ /** @return true if we are using our own bufbuilder, and not an alternate that was given to us in our constructor */
+ bool owned() const { return &_b == &_buf; }
+
+ BSONObjIterator iterator() const ;
+
+ bool hasField( const StringData& name ) const ;
+
+ int len() const { return _b.len(); }
+
+ BufBuilder& bb() { return _b; }
+
+ private:
+ char* _done() {
+ if ( _doneCalled )
+ return _b.buf() + _offset;
+
+ _doneCalled = true;
+ _s.endField();
+ _b.appendNum((char) EOO);
+ char *data = _b.buf() + _offset;
+ int size = _b.len() - _offset;
+ *((int*)data) = size;
+ if ( _tracker )
+ _tracker->got( size );
+ return data;
+ }
+
+ BufBuilder &_b;
+ BufBuilder _buf;
+ int _offset;
+ BSONObjBuilderValueStream _s;
+ BSONSizeTracker * _tracker;
+ bool _doneCalled;
+
+ static const string numStrs[100]; // cache of 0 to 99 inclusive
+ static bool numStrsReady; // for static init safety. see comments in db/jsobj.cpp
+ };
+
+ class BSONArrayBuilder : boost::noncopyable {
+ public:
+ BSONArrayBuilder() : _i(0), _b() {}
+ BSONArrayBuilder( BufBuilder &_b ) : _i(0), _b(_b) {}
+ BSONArrayBuilder( int initialSize ) : _i(0), _b(initialSize) {}
+
+ template <typename T>
+ BSONArrayBuilder& append(const T& x) {
+ _b.append(num(), x);
+ return *this;
+ }
+
+ BSONArrayBuilder& append(const BSONElement& e) {
+ _b.appendAs(e, num());
+ return *this;
+ }
+
+ template <typename T>
+ BSONArrayBuilder& operator<<(const T& x) {
+ return append(x);
+ }
+
+ void appendNull() {
+ _b.appendNull(num());
+ }
+
+ /**
+ * destructive - ownership moves to returned BSONArray
+ * @return owned BSONArray
+ */
+ BSONArray arr() { return BSONArray(_b.obj()); }
+
+ BSONObj done() { return _b.done(); }
+
+ void doneFast() { _b.doneFast(); }
+
+ template <typename T>
+ BSONArrayBuilder& append(const StringData& name, const T& x) {
+ fill( name );
+ append( x );
+ return *this;
+ }
+
+ // These two just use next position
+ BufBuilder &subobjStart() { return _b.subobjStart( num() ); }
+ BufBuilder &subarrayStart() { return _b.subarrayStart( num() ); }
+
+ // These fill missing entries up to pos. if pos is < next pos is ignored
+ BufBuilder &subobjStart(int pos) {
+ fill(pos);
+ return _b.subobjStart( num() );
+ }
+ BufBuilder &subarrayStart(int pos) {
+ fill(pos);
+ return _b.subarrayStart( num() );
+ }
+
+ // These should only be used where you really need interface compatability with BSONObjBuilder
+ // Currently they are only used by update.cpp and it should probably stay that way
+ BufBuilder &subobjStart( const StringData& name ) {
+ fill( name );
+ return _b.subobjStart( num() );
+ }
+
+ BufBuilder &subarrayStart( const char *name ) {
+ fill( name );
+ return _b.subarrayStart( num() );
+ }
+
+ void appendArray( const StringData& name, BSONObj subObj ) {
+ fill( name );
+ _b.appendArray( num(), subObj );
+ }
+
+ void appendAs( const BSONElement &e, const char *name) {
+ fill( name );
+ append( e );
+ }
+
+ int len() const { return _b.len(); }
+ int arrSize() const { return _i; }
+
+ private:
+ // These two are undefined privates to prevent their accidental
+ // use as we don't support unsigned ints in BSON
+ BSONObjBuilder& append(const StringData& fieldName, unsigned int val);
+ BSONObjBuilder& append(const StringData& fieldName, unsigned long long val);
+
+ void fill( const StringData& name ) {
+ char *r;
+ long int n = strtol( name.data(), &r, 10 );
+ if ( *r )
+ uasserted( 13048, (string)"can't append to array using string field name [" + name.data() + "]" );
+ fill(n);
+ }
+
+ void fill (int upTo){
+ // if this is changed make sure to update error message and jstests/set7.js
+ const int maxElems = 1500000;
+ BOOST_STATIC_ASSERT(maxElems < (BSONObjMaxUserSize/10));
+ uassert(15891, "can't backfill array to larger than 1,500,000 elements", upTo <= maxElems);
+
+ while( _i < upTo )
+ append( nullElt() );
+ }
+
+ static BSONElement nullElt() {
+ static BSONObj n = nullObj();
+ return n.firstElement();
+ }
+
+ static BSONObj nullObj() {
+ BSONObjBuilder _b;
+ _b.appendNull( "" );
+ return _b.obj();
+ }
+
+ string num() { return _b.numStr(_i++); }
+ int _i;
+ BSONObjBuilder _b;
+ };
+
+ template < class T >
+ inline BSONObjBuilder& BSONObjBuilder::append( const StringData& fieldName, const vector< T >& vals ) {
+ BSONObjBuilder arrBuilder;
+ for ( unsigned int i = 0; i < vals.size(); ++i )
+ arrBuilder.append( numStr( i ), vals[ i ] );
+ appendArray( fieldName, arrBuilder.done() );
+ return *this;
+ }
+
+ template < class L >
+ inline BSONObjBuilder& _appendIt( BSONObjBuilder& _this, const StringData& fieldName, const L& vals ) {
+ BSONObjBuilder arrBuilder;
+ int n = 0;
+ for( typename L::const_iterator i = vals.begin(); i != vals.end(); i++ )
+ arrBuilder.append( BSONObjBuilder::numStr(n++), *i );
+ _this.appendArray( fieldName, arrBuilder.done() );
+ return _this;
+ }
+
+ template < class T >
+ inline BSONObjBuilder& BSONObjBuilder::append( const StringData& fieldName, const list< T >& vals ) {
+ return _appendIt< list< T > >( *this, fieldName, vals );
+ }
+
+ template < class T >
+ inline BSONObjBuilder& BSONObjBuilder::append( const StringData& fieldName, const set< T >& vals ) {
+ return _appendIt< set< T > >( *this, fieldName, vals );
+ }
+
+
+ // $or helper: OR(BSON("x" << GT << 7), BSON("y" << LT 6));
+ inline BSONObj OR(const BSONObj& a, const BSONObj& b)
+ { return BSON( "$or" << BSON_ARRAY(a << b) ); }
+ inline BSONObj OR(const BSONObj& a, const BSONObj& b, const BSONObj& c)
+ { return BSON( "$or" << BSON_ARRAY(a << b << c) ); }
+ inline BSONObj OR(const BSONObj& a, const BSONObj& b, const BSONObj& c, const BSONObj& d)
+ { return BSON( "$or" << BSON_ARRAY(a << b << c << d) ); }
+ inline BSONObj OR(const BSONObj& a, const BSONObj& b, const BSONObj& c, const BSONObj& d, const BSONObj& e)
+ { return BSON( "$or" << BSON_ARRAY(a << b << c << d << e) ); }
+ inline BSONObj OR(const BSONObj& a, const BSONObj& b, const BSONObj& c, const BSONObj& d, const BSONObj& e, const BSONObj& f)
+ { return BSON( "$or" << BSON_ARRAY(a << b << c << d << e << f) ); }
+
+}
diff --git a/src/mongo/bson/bsonobjiterator.h b/src/mongo/bson/bsonobjiterator.h
new file mode 100644
index 00000000000..39ae24d9b86
--- /dev/null
+++ b/src/mongo/bson/bsonobjiterator.h
@@ -0,0 +1,161 @@
+// bsonobjiterator.h
+
+/* Copyright 2009 10gen Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <boost/preprocessor/cat.hpp> // like the ## operator but works with __LINE__
+
+namespace mongo {
+
+ /** iterator for a BSONObj
+
+ Note each BSONObj ends with an EOO element: so you will get more() on an empty
+ object, although next().eoo() will be true.
+
+ The BSONObj must stay in scope for the duration of the iterator's execution.
+
+ todo: we may want to make a more stl-like iterator interface for this
+ with things like begin() and end()
+ */
+ class BSONObjIterator {
+ public:
+ /** Create an iterator for a BSON object.
+ */
+ BSONObjIterator(const BSONObj& jso) {
+ int sz = jso.objsize();
+ if ( MONGO_unlikely(sz == 0) ) {
+ _pos = _theend = 0;
+ return;
+ }
+ _pos = jso.objdata() + 4;
+ _theend = jso.objdata() + sz - 1;
+ }
+
+ BSONObjIterator( const char * start , const char * end ) {
+ _pos = start + 4;
+ _theend = end - 1;
+ }
+
+ /** @return true if more elements exist to be enumerated. */
+ bool more() { return _pos < _theend; }
+
+ /** @return true if more elements exist to be enumerated INCLUDING the EOO element which is always at the end. */
+ bool moreWithEOO() { return _pos <= _theend; }
+
+ /** @return the next element in the object. For the final element, element.eoo() will be true. */
+ BSONElement next( bool checkEnd ) {
+ assert( _pos <= _theend );
+ BSONElement e( _pos, checkEnd ? (int)(_theend + 1 - _pos) : -1 );
+ _pos += e.size( checkEnd ? (int)(_theend + 1 - _pos) : -1 );
+ return e;
+ }
+ BSONElement next() {
+ assert( _pos <= _theend );
+ BSONElement e(_pos);
+ _pos += e.size();
+ return e;
+ }
+ void operator++() { next(); }
+ void operator++(int) { next(); }
+
+ BSONElement operator*() {
+ assert( _pos <= _theend );
+ return BSONElement(_pos);
+ }
+
+ private:
+ const char* _pos;
+ const char* _theend;
+ };
+
+ class BSONObjIteratorSorted {
+ public:
+ BSONObjIteratorSorted( const BSONObj& o );
+
+ ~BSONObjIteratorSorted() {
+ assert( _fields );
+ delete[] _fields;
+ _fields = 0;
+ }
+
+ bool more() {
+ return _cur < _nfields;
+ }
+
+ BSONElement next() {
+ assert( _fields );
+ if ( _cur < _nfields )
+ return BSONElement( _fields[_cur++] );
+ return BSONElement();
+ }
+
+ private:
+ const char ** _fields;
+ int _nfields;
+ int _cur;
+ };
+
+ /** 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.
+ */
+ inline vector<BSONElement> BSONElement::Array() const {
+ chk(mongo::Array);
+ vector<BSONElement> v;
+ BSONObjIterator i(Obj());
+ while( i.more() ) {
+ BSONElement e = i.next();
+ const char *f = e.fieldName();
+ try {
+ unsigned u = stringToNum(f);
+ assert( u < 1000000 );
+ if( u >= v.size() )
+ v.resize(u+1);
+ v[u] = e;
+ }
+ catch(unsigned) { }
+ }
+ return v;
+ }
+
+ /** Similar to BOOST_FOREACH
+ *
+ * because the iterator is defined outside of the for, you must use {} around
+ * the surrounding scope. Don't do this:
+ *
+ * if (foo)
+ * BSONForEach(e, obj)
+ * doSomething(e);
+ *
+ * but this is OK:
+ *
+ * if (foo) {
+ * BSONForEach(e, obj)
+ * doSomething(e);
+ * }
+ *
+ */
+
+#define BSONForEach(e, obj) \
+ BSONObjIterator BOOST_PP_CAT(it_,__LINE__)(obj); \
+ for ( BSONElement e; \
+ (BOOST_PP_CAT(it_,__LINE__).more() ? \
+ (e = BOOST_PP_CAT(it_,__LINE__).next(), true) : \
+ false) ; \
+ /*nothing*/ )
+
+}
diff --git a/src/mongo/bson/bsontypes.h b/src/mongo/bson/bsontypes.h
new file mode 100644
index 00000000000..9d95e8e9ad4
--- /dev/null
+++ b/src/mongo/bson/bsontypes.h
@@ -0,0 +1,107 @@
+// bsontypes.h
+
+/* Copyright 2009 10gen Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "util/misc.h"
+
+namespace bson { }
+
+namespace mongo {
+
+ using namespace std;
+
+ class BSONArrayBuilder;
+ class BSONElement;
+ class BSONObj;
+ class BSONObjBuilder;
+ class BSONObjBuilderValueStream;
+ class BSONObjIterator;
+ class Ordering;
+ class Record;
+ struct BSONArray; // empty subclass of BSONObj useful for overloading
+ struct BSONElementCmpWithoutField;
+
+ extern BSONObj maxKey;
+ extern BSONObj minKey;
+
+ /**
+ the complete list of valid BSON types
+ see also bsonspec.org
+ */
+ enum BSONType {
+ /** smaller than all other types */
+ MinKey=-1,
+ /** end of object */
+ EOO=0,
+ /** double precision floating point value */
+ NumberDouble=1,
+ /** character string, stored in utf8 */
+ String=2,
+ /** an embedded object */
+ Object=3,
+ /** an embedded array */
+ Array=4,
+ /** binary data */
+ BinData=5,
+ /** Undefined type */
+ Undefined=6,
+ /** ObjectId */
+ jstOID=7,
+ /** boolean type */
+ Bool=8,
+ /** date type */
+ Date=9,
+ /** null type */
+ jstNULL=10,
+ /** regular expression, a pattern with options */
+ RegEx=11,
+ /** deprecated / will be redesigned */
+ DBRef=12,
+ /** deprecated / use CodeWScope */
+ Code=13,
+ /** a programming language (e.g., Python) symbol */
+ Symbol=14,
+ /** javascript code that can execute on the database server, with SavedContext */
+ CodeWScope=15,
+ /** 32 bit signed integer */
+ NumberInt = 16,
+ /** Updated to a Date with value next OpTime on insert */
+ Timestamp = 17,
+ /** 64 bit integer */
+ NumberLong = 18,
+ /** max type that is not MaxKey */
+ JSTypeMax=18,
+ /** larger than all other types */
+ MaxKey=127
+ };
+
+ /* subtypes of BinData.
+ bdtCustom and above are ones that the JS compiler understands, but are
+ opaque to the database.
+ */
+ enum BinDataType {
+ BinDataGeneral=0,
+ Function=1,
+ ByteArrayDeprecated=2, /* use BinGeneral instead */
+ bdtUUID = 3,
+ MD5Type=5,
+ bdtCustom=128
+ };
+
+}
+
diff --git a/src/mongo/bson/inline_decls.h b/src/mongo/bson/inline_decls.h
new file mode 100644
index 00000000000..30da9b4560d
--- /dev/null
+++ b/src/mongo/bson/inline_decls.h
@@ -0,0 +1,68 @@
+// inline_decls.h
+
+/* Copyright 2010 10gen Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#if defined(__GNUC__)
+
+#define NOINLINE_DECL __attribute__((noinline))
+
+#elif defined(_MSC_VER)
+
+#define NOINLINE_DECL __declspec(noinline)
+
+#else
+
+#define NOINLINE_DECL
+
+#endif
+
+namespace mongo {
+
+/* Note: do not clutter code with these -- ONLY use in hot spots / significant loops. */
+
+#if !defined(__GNUC__)
+
+// branch prediction. indicate we expect to be true
+# define MONGO_likely(x) ((bool)(x))
+
+// branch prediction. indicate we expect to be false
+# define MONGO_unlikely(x) ((bool)(x))
+
+# if defined(_WIN32)
+ // prefetch data from memory
+ inline void prefetch(const void *p) {
+#if defined(_MM_HINT_T0)
+ _mm_prefetch((char *) p, _MM_HINT_T0);
+#endif
+ }
+#else
+ inline void prefetch(void *p) { }
+#endif
+
+#else
+
+# define MONGO_likely(x) ( __builtin_expect((bool)(x), 1) )
+# define MONGO_unlikely(x) ( __builtin_expect((bool)(x), 0) )
+
+ inline void prefetch(void *p) {
+ __builtin_prefetch(p);
+ }
+
+#endif
+
+}
diff --git a/src/mongo/bson/oid.cpp b/src/mongo/bson/oid.cpp
new file mode 100644
index 00000000000..3aee14a3585
--- /dev/null
+++ b/src/mongo/bson/oid.cpp
@@ -0,0 +1,173 @@
+// @file oid.cpp
+
+/* Copyright 2009 10gen Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "pch.h"
+#include "oid.h"
+#include "util/atomic_int.h"
+#include "../db/nonce.h"
+#include "bsonobjbuilder.h"
+
+BOOST_STATIC_ASSERT( sizeof(mongo::OID) == 12 );
+
+namespace mongo {
+
+ // machine # before folding in the process id
+ OID::MachineAndPid OID::ourMachine;
+
+ unsigned OID::ourPid() {
+ unsigned pid;
+#if defined(_WIN32)
+ pid = (unsigned short) GetCurrentProcessId();
+#elif defined(__linux__) || defined(__APPLE__) || defined(__sunos__)
+ pid = (unsigned short) getpid();
+#else
+ pid = (unsigned short) Security::getNonce();
+#endif
+ return pid;
+ }
+
+ void OID::foldInPid(OID::MachineAndPid& x) {
+ unsigned p = ourPid();
+ x._pid ^= (unsigned short) p;
+ // when the pid is greater than 16 bits, let the high bits modulate the machine id field.
+ unsigned short& rest = (unsigned short &) x._machineNumber[1];
+ rest ^= p >> 16;
+ }
+
+ OID::MachineAndPid OID::genMachineAndPid() {
+ BOOST_STATIC_ASSERT( sizeof(mongo::OID::MachineAndPid) == 5 );
+
+ // this is not called often, so the following is not expensive, and gives us some
+ // testing that nonce generation is working right and that our OIDs are (perhaps) ok.
+ {
+ nonce64 a = Security::getNonceDuringInit();
+ nonce64 b = Security::getNonceDuringInit();
+ nonce64 c = Security::getNonceDuringInit();
+ assert( !(a==b && b==c) );
+ }
+
+ unsigned long long n = Security::getNonceDuringInit();
+ OID::MachineAndPid x = ourMachine = (OID::MachineAndPid&) n;
+ foldInPid(x);
+ return x;
+ }
+
+ // after folding in the process id
+ OID::MachineAndPid OID::ourMachineAndPid = OID::genMachineAndPid();
+
+ void OID::regenMachineId() {
+ ourMachineAndPid = genMachineAndPid();
+ }
+
+ inline bool OID::MachineAndPid::operator!=(const OID::MachineAndPid& rhs) const {
+ return _pid != rhs._pid || _machineNumber != rhs._machineNumber;
+ }
+
+ unsigned OID::getMachineId() {
+ unsigned char x[4];
+ x[0] = ourMachineAndPid._machineNumber[0];
+ x[1] = ourMachineAndPid._machineNumber[1];
+ x[2] = ourMachineAndPid._machineNumber[2];
+ x[3] = 0;
+ return (unsigned&) x[0];
+ }
+
+ void OID::justForked() {
+ MachineAndPid x = ourMachine;
+ // we let the random # for machine go into all 5 bytes of MachineAndPid, and then
+ // xor in the pid into _pid. this reduces the probability of collisions.
+ foldInPid(x);
+ ourMachineAndPid = genMachineAndPid();
+ assert( x != ourMachineAndPid );
+ ourMachineAndPid = x;
+ }
+
+ void OID::init() {
+ static AtomicUInt inc = (unsigned) Security::getNonce();
+
+ {
+ unsigned t = (unsigned) time(0);
+ unsigned char *T = (unsigned char *) &t;
+ _time[0] = T[3]; // big endian order because we use memcmp() to compare OID's
+ _time[1] = T[2];
+ _time[2] = T[1];
+ _time[3] = T[0];
+ }
+
+ _machineAndPid = ourMachineAndPid;
+
+ {
+ int new_inc = inc++;
+ unsigned char *T = (unsigned char *) &new_inc;
+ _inc[0] = T[2];
+ _inc[1] = T[1];
+ _inc[2] = T[0];
+ }
+ }
+
+ void OID::init( string s ) {
+ assert( s.size() == 24 );
+ const char *p = s.c_str();
+ for( int i = 0; i < 12; i++ ) {
+ data[i] = fromHex(p);
+ p += 2;
+ }
+ }
+
+ void OID::init(Date_t date, bool max) {
+ int time = (int) (date / 1000);
+ char* T = (char *) &time;
+ data[0] = T[3];
+ data[1] = T[2];
+ data[2] = T[1];
+ data[3] = T[0];
+
+ if (max)
+ *(long long*)(data + 4) = 0xFFFFFFFFFFFFFFFFll;
+ else
+ *(long long*)(data + 4) = 0x0000000000000000ll;
+ }
+
+ time_t OID::asTimeT() {
+ int time;
+ char* T = (char *) &time;
+ T[0] = data[3];
+ T[1] = data[2];
+ T[2] = data[1];
+ T[3] = data[0];
+ return time;
+ }
+
+ const string BSONObjBuilder::numStrs[] = {
+ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
+ "10", "11", "12", "13", "14", "15", "16", "17", "18", "19",
+ "20", "21", "22", "23", "24", "25", "26", "27", "28", "29",
+ "30", "31", "32", "33", "34", "35", "36", "37", "38", "39",
+ "40", "41", "42", "43", "44", "45", "46", "47", "48", "49",
+ "50", "51", "52", "53", "54", "55", "56", "57", "58", "59",
+ "60", "61", "62", "63", "64", "65", "66", "67", "68", "69",
+ "70", "71", "72", "73", "74", "75", "76", "77", "78", "79",
+ "80", "81", "82", "83", "84", "85", "86", "87", "88", "89",
+ "90", "91", "92", "93", "94", "95", "96", "97", "98", "99",
+ };
+
+ // This is to ensure that BSONObjBuilder doesn't try to use numStrs before the strings have been constructed
+ // I've tested just making numStrs a char[][], but the overhead of constructing the strings each time was too high
+ // numStrsReady will be 0 until after numStrs is initialized because it is a static variable
+ bool BSONObjBuilder::numStrsReady = (numStrs[0].size() > 0);
+
+}
diff --git a/src/mongo/bson/oid.h b/src/mongo/bson/oid.h
new file mode 100644
index 00000000000..e5963a0e81d
--- /dev/null
+++ b/src/mongo/bson/oid.h
@@ -0,0 +1,138 @@
+// oid.h
+
+/* Copyright 2009 10gen Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <boost/functional/hash.hpp>
+#include "../util/hex.h"
+
+namespace mongo {
+
+#pragma pack(1)
+ /** Object ID type.
+ BSON objects typically have an _id field for the object id. This field should be the first
+ member of the object when present. class OID is a special type that is a 12 byte id which
+ is likely to be unique to the system. You may also use other types for _id's.
+ When _id field is missing from a BSON object, on an insert the database may insert one
+ automatically in certain circumstances.
+
+ Warning: You must call OID::newState() after a fork().
+
+ Typical contents of the BSON ObjectID is a 12-byte value consisting of a 4-byte timestamp (seconds since epoch),
+ a 3-byte machine id, a 2-byte process id, and a 3-byte counter. Note that the timestamp and counter fields must
+ be stored big endian unlike the rest of BSON. This is because they are compared byte-by-byte and we want to ensure
+ a mostly increasing order.
+ */
+ class OID {
+ public:
+ OID() : a(0), b(0) { }
+
+ /** init from a 24 char hex string */
+ explicit OID(const string &s) { init(s); }
+
+ /** initialize to 'null' */
+ void clear() { a = 0; b = 0; }
+
+ const unsigned char *getData() const { return data; }
+
+ bool operator==(const OID& r) const { return a==r.a && b==r.b; }
+ bool operator!=(const OID& r) const { return a!=r.a || b!=r.b; }
+ int compare( const OID& other ) const { return memcmp( data , other.data , 12 ); }
+ bool operator<( const OID& other ) const { return compare( other ) < 0; }
+ bool operator<=( const OID& other ) const { return compare( other ) <= 0; }
+
+ /** @return the object ID output as 24 hex digits */
+ string str() const { return toHexLower(data, 12); }
+ string toString() const { return str(); }
+
+ static OID gen() { OID o; o.init(); return o; }
+
+ /** sets the contents to a new oid / randomized value */
+ void init();
+
+ /** init from a 24 char hex string */
+ void init( string s );
+
+ /** Set to the min/max OID that could be generated at given timestamp. */
+ void init( Date_t date, bool max=false );
+
+ time_t asTimeT();
+ Date_t asDateT() { return asTimeT() * (long long)1000; }
+
+ bool isSet() const { return a || b; }
+
+ void hash_combine(size_t &seed) const {
+ boost::hash_combine(seed, a);
+ boost::hash_combine(seed, b);
+ }
+
+ /** call this after a fork to update the process id */
+ static void justForked();
+
+ static unsigned getMachineId(); // features command uses
+ static void regenMachineId(); // used by unit tests
+
+ private:
+ struct MachineAndPid {
+ unsigned char _machineNumber[3];
+ unsigned short _pid;
+ bool operator!=(const OID::MachineAndPid& rhs) const;
+ };
+ static MachineAndPid ourMachine, ourMachineAndPid;
+ union {
+ struct {
+ // 12 bytes total
+ unsigned char _time[4];
+ MachineAndPid _machineAndPid;
+ unsigned char _inc[3];
+ };
+ struct {
+ long long a;
+ unsigned b;
+ };
+ unsigned char data[12];
+ };
+
+ static unsigned ourPid();
+ static void foldInPid(MachineAndPid& x);
+ static MachineAndPid genMachineAndPid();
+ };
+#pragma pack()
+
+ ostream& operator<<( ostream &s, const OID &o );
+ inline StringBuilder& operator<< (StringBuilder& s, const OID& o) { return (s << o.str()); }
+
+ /** Formatting mode for generating JSON from BSON.
+ See <http://mongodb.onconfluence.com/display/DOCS/Mongo+Extended+JSON>
+ for details.
+ */
+ enum JsonStringFormat {
+ /** strict RFC format */
+ Strict,
+ /** 10gen format, which is close to JS format. This form is understandable by
+ javascript running inside the Mongo server via eval() */
+ TenGen,
+ /** Javascript JSON compatible */
+ JS
+ };
+
+ inline ostream& operator<<( ostream &s, const OID &o ) {
+ s << o.str();
+ return s;
+ }
+
+}
diff --git a/src/mongo/bson/ordering.h b/src/mongo/bson/ordering.h
new file mode 100644
index 00000000000..bca3296f340
--- /dev/null
+++ b/src/mongo/bson/ordering.h
@@ -0,0 +1,73 @@
+// ordering.h
+
+/* Copyright 2009 10gen Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+namespace mongo {
+
+ // todo: ideally move to db/ instead of bson/, but elim any dependencies first
+
+ /** A precomputation of a BSON index or sort key pattern. That is something like:
+ { a : 1, b : -1 }
+ The constructor is private to make conversion more explicit so we notice where we call make().
+ Over time we should push this up higher and higher.
+ */
+ class Ordering {
+ unsigned bits;
+ Ordering(unsigned b) : bits(b) { }
+ public:
+ Ordering(const Ordering& r) : bits(r.bits) { }
+ void operator=(const Ordering& r) {
+ bits = r.bits;
+ }
+
+ /** so, for key pattern { a : 1, b : -1 }
+ get(0) == 1
+ get(1) == -1
+ */
+ int get(int i) const {
+ return ((1 << i) & bits) ? -1 : 1;
+ }
+
+ // for woCompare...
+ unsigned descending(unsigned mask) const { return bits & mask; }
+
+ /*operator string() const {
+ StringBuilder buf(32);
+ for ( unsigned i=0; i<nkeys; i++)
+ buf.append( get(i) > 0 ? "+" : "-" );
+ return buf.str();
+ }*/
+
+ static Ordering make(const BSONObj& obj) {
+ unsigned b = 0;
+ BSONObjIterator k(obj);
+ unsigned n = 0;
+ while( 1 ) {
+ BSONElement e = k.next();
+ if( e.eoo() )
+ break;
+ uassert( 13103, "too many compound keys", n <= 31 );
+ if( e.number() < 0 )
+ b |= (1 << n);
+ n++;
+ }
+ return Ordering(b);
+ }
+ };
+
+}
diff --git a/src/mongo/bson/stringdata.h b/src/mongo/bson/stringdata.h
new file mode 100644
index 00000000000..1fb4e7d25d3
--- /dev/null
+++ b/src/mongo/bson/stringdata.h
@@ -0,0 +1,71 @@
+// stringdata.h
+
+/* Copyright 2010 10gen Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <string>
+#include <cstring>
+
+namespace mongo {
+
+ using std::string;
+
+ /** A StringData object wraps a 'const string&' or a 'const char*' without
+ * copying its contents. The most common usage is as a function argument that
+ * takes any of the two forms of strings above. Fundamentally, this class tries
+ * go around the fact that string literals in C++ are char[N]'s.
+ *
+ * Note that the object StringData wraps around must be alive while the StringData
+ * is.
+ */
+ class StringData {
+ public:
+ /** Construct a StringData, for the case where the length of
+ * string is not known. 'c' must be a pointer to a null-terminated string.
+ */
+ StringData( const char* c )
+ : _data(c), _size((unsigned) strlen(c)) {}
+
+ /** Construct a StringData explicitly, for the case where the length of the string
+ * is already known. 'c' must be a pointer to a null-terminated string, and strlenOfc
+ * must be the length that std::strlen(c) would return, a.k.a the index of the
+ * terminator in c.
+ */
+ StringData( const char* c, unsigned len )
+ : _data(c), _size(len) {}
+
+ /** Construct a StringData, for the case of a std::string. */
+ StringData( const string& s )
+ : _data(s.c_str()), _size((unsigned) s.size()) {}
+
+ // Construct a StringData explicitly, for the case of a literal whose size is
+ // known at compile time.
+ struct LiteralTag {};
+ template<size_t N>
+ StringData( const char (&val)[N], LiteralTag )
+ : _data(&val[0]), _size(N-1) {}
+
+ // accessors
+ const char* data() const { return _data; }
+ unsigned size() const { return _size; }
+
+ private:
+ const char* const _data; // is always null terminated
+ const unsigned _size; // 'size' does not include the null terminator
+ };
+
+} // namespace mongo
diff --git a/src/mongo/bson/util/atomic_int.h b/src/mongo/bson/util/atomic_int.h
new file mode 100644
index 00000000000..e85a023c3bc
--- /dev/null
+++ b/src/mongo/bson/util/atomic_int.h
@@ -0,0 +1,106 @@
+// atomic_int.h
+// atomic wrapper for unsigned
+
+/* Copyright 2009 10gen Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#if defined(_WIN32)
+# include <windows.h>
+#endif
+
+namespace mongo {
+
+ struct AtomicUInt {
+ AtomicUInt() : x(0) {}
+ AtomicUInt(unsigned z) : x(z) { }
+
+ operator unsigned() const { return x; }
+ unsigned get() const { return x; }
+
+ inline AtomicUInt operator++(); // ++prefix
+ inline AtomicUInt operator++(int);// postfix++
+ inline AtomicUInt operator--(); // --prefix
+ inline AtomicUInt operator--(int); // postfix--
+
+ inline void zero();
+
+ volatile unsigned x;
+ };
+
+#if defined(_WIN32)
+ void AtomicUInt::zero() {
+ InterlockedExchange((volatile long*)&x, 0);
+ }
+ AtomicUInt AtomicUInt::operator++() {
+ return InterlockedIncrement((volatile long*)&x);
+ }
+ AtomicUInt AtomicUInt::operator++(int) {
+ return InterlockedIncrement((volatile long*)&x)-1;
+ }
+ AtomicUInt AtomicUInt::operator--() {
+ return InterlockedDecrement((volatile long*)&x);
+ }
+ AtomicUInt AtomicUInt::operator--(int) {
+ return InterlockedDecrement((volatile long*)&x)+1;
+ }
+#elif defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4)
+ // this is in GCC >= 4.1
+ inline void AtomicUInt::zero() { x = 0; } // TODO: this isn't thread safe - maybe
+ AtomicUInt AtomicUInt::operator++() {
+ return __sync_add_and_fetch(&x, 1);
+ }
+ AtomicUInt AtomicUInt::operator++(int) {
+ return __sync_fetch_and_add(&x, 1);
+ }
+ AtomicUInt AtomicUInt::operator--() {
+ return __sync_add_and_fetch(&x, -1);
+ }
+ AtomicUInt AtomicUInt::operator--(int) {
+ return __sync_fetch_and_add(&x, -1);
+ }
+#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
+ inline void AtomicUInt::zero() { x = 0; } // TODO: this isn't thread safe
+ // from boost 1.39 interprocess/detail/atomic.hpp
+ inline unsigned atomic_int_helper(volatile unsigned *x, int val) {
+ int r;
+ asm volatile
+ (
+ "lock\n\t"
+ "xadd %1, %0":
+ "+m"( *x ), "=r"( r ): // outputs (%0, %1)
+ "1"( val ): // inputs (%2 == %1)
+ "memory", "cc" // clobbers
+ );
+ return r;
+ }
+ AtomicUInt AtomicUInt::operator++() {
+ return atomic_int_helper(&x, 1)+1;
+ }
+ AtomicUInt AtomicUInt::operator++(int) {
+ return atomic_int_helper(&x, 1);
+ }
+ AtomicUInt AtomicUInt::operator--() {
+ return atomic_int_helper(&x, -1)-1;
+ }
+ AtomicUInt AtomicUInt::operator--(int) {
+ return atomic_int_helper(&x, -1);
+ }
+#else
+# error "unsupported compiler or platform"
+#endif
+
+} // namespace mongo
diff --git a/src/mongo/bson/util/builder.h b/src/mongo/bson/util/builder.h
new file mode 100644
index 00000000000..f189f58b27e
--- /dev/null
+++ b/src/mongo/bson/util/builder.h
@@ -0,0 +1,322 @@
+/* builder.h */
+
+/* Copyright 2009 10gen Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <string>
+#include <string.h>
+#include <stdio.h>
+#include "../inline_decls.h"
+#include "../stringdata.h"
+
+namespace mongo {
+
+ /* Note the limit here is rather arbitrary and is simply a standard. generally the code works
+ with any object that fits in ram.
+
+ Also note that the server has some basic checks to enforce this limit but those checks are not exhaustive
+ for example need to check for size too big after
+ update $push (append) operation
+ various db.eval() type operations
+ */
+ const int BSONObjMaxUserSize = 16 * 1024 * 1024;
+
+ /*
+ Sometimeswe we need objects slightly larger - an object in the replication local.oplog
+ is slightly larger than a user object for example.
+ */
+ const int BSONObjMaxInternalSize = BSONObjMaxUserSize + ( 16 * 1024 );
+
+ const int BufferMaxSize = 64 * 1024 * 1024;
+
+ class StringBuilder;
+
+ void msgasserted(int msgid, const char *msg);
+
+ class TrivialAllocator {
+ public:
+ void* Malloc(size_t sz) { return malloc(sz); }
+ void* Realloc(void *p, size_t sz) { return realloc(p, sz); }
+ void Free(void *p) { free(p); }
+ };
+
+ class StackAllocator {
+ public:
+ enum { SZ = 512 };
+ void* Malloc(size_t sz) {
+ if( sz <= SZ ) return buf;
+ return malloc(sz);
+ }
+ void* Realloc(void *p, size_t sz) {
+ if( p == buf ) {
+ if( sz <= SZ ) return buf;
+ void *d = malloc(sz);
+ if ( d == 0 )
+ msgasserted( 15912 , "out of memory StackAllocator::Realloc" );
+ memcpy(d, p, SZ);
+ return d;
+ }
+ return realloc(p, sz);
+ }
+ void Free(void *p) {
+ if( p != buf )
+ free(p);
+ }
+ private:
+ char buf[SZ];
+ };
+
+ template< class Allocator >
+ class _BufBuilder {
+ // non-copyable, non-assignable
+ _BufBuilder( const _BufBuilder& );
+ _BufBuilder& operator=( const _BufBuilder& );
+ Allocator al;
+ public:
+ _BufBuilder(int initsize = 512) : size(initsize) {
+ if ( size > 0 ) {
+ data = (char *) al.Malloc(size);
+ if( data == 0 )
+ msgasserted(10000, "out of memory BufBuilder");
+ }
+ else {
+ data = 0;
+ }
+ l = 0;
+ }
+ ~_BufBuilder() { kill(); }
+
+ void kill() {
+ if ( data ) {
+ al.Free(data);
+ data = 0;
+ }
+ }
+
+ void reset() {
+ l = 0;
+ }
+ void reset( int maxSize ) {
+ l = 0;
+ if ( maxSize && size > maxSize ) {
+ al.Free(data);
+ data = (char*)al.Malloc(maxSize);
+ if ( data == 0 )
+ msgasserted( 15913 , "out of memory BufBuilder::reset" );
+ size = maxSize;
+ }
+ }
+
+ /** leave room for some stuff later
+ @return point to region that was skipped. pointer may change later (on realloc), so for immediate use only
+ */
+ char* skip(int n) { return grow(n); }
+
+ /* note this may be deallocated (realloced) if you keep writing. */
+ char* buf() { return data; }
+ const char* buf() const { return data; }
+
+ /* assume ownership of the buffer - you must then free() it */
+ void decouple() { data = 0; }
+
+ void appendUChar(unsigned char j) {
+ *((unsigned char*)grow(sizeof(unsigned char))) = j;
+ }
+ void appendChar(char j) {
+ *((char*)grow(sizeof(char))) = j;
+ }
+ void appendNum(char j) {
+ *((char*)grow(sizeof(char))) = j;
+ }
+ void appendNum(short j) {
+ *((short*)grow(sizeof(short))) = j;
+ }
+ void appendNum(int j) {
+ *((int*)grow(sizeof(int))) = j;
+ }
+ void appendNum(unsigned j) {
+ *((unsigned*)grow(sizeof(unsigned))) = j;
+ }
+ void appendNum(bool j) {
+ *((bool*)grow(sizeof(bool))) = j;
+ }
+ void appendNum(double j) {
+ *((double*)grow(sizeof(double))) = j;
+ }
+ void appendNum(long long j) {
+ *((long long*)grow(sizeof(long long))) = j;
+ }
+ void appendNum(unsigned long long j) {
+ *((unsigned long long*)grow(sizeof(unsigned long long))) = j;
+ }
+
+ void appendBuf(const void *src, size_t len) {
+ memcpy(grow((int) len), src, len);
+ }
+
+ template<class T>
+ void appendStruct(const T& s) {
+ appendBuf(&s, sizeof(T));
+ }
+
+ void appendStr(const StringData &str , bool includeEndingNull = true ) {
+ const int len = str.size() + ( includeEndingNull ? 1 : 0 );
+ memcpy(grow(len), str.data(), len);
+ }
+
+ /** @return length of current string */
+ int len() const { return l; }
+ void setlen( int newLen ) { l = newLen; }
+ /** @return size of the buffer */
+ int getSize() const { return size; }
+
+ /* returns the pre-grow write position */
+ inline char* grow(int by) {
+ int oldlen = l;
+ l += by;
+ if ( l > size ) {
+ grow_reallocate();
+ }
+ return data + oldlen;
+ }
+
+ private:
+ /* "slow" portion of 'grow()' */
+ void NOINLINE_DECL grow_reallocate() {
+ int a = size * 2;
+ if ( a == 0 )
+ a = 512;
+ if ( l > a )
+ a = l + 16 * 1024;
+ if ( a > BufferMaxSize )
+ msgasserted(13548, "BufBuilder grow() > 64MB");
+ data = (char *) al.Realloc(data, a);
+ size= a;
+ }
+
+ char *data;
+ int l;
+ int size;
+
+ friend class StringBuilder;
+ };
+
+ typedef _BufBuilder<TrivialAllocator> BufBuilder;
+
+ /** The StackBufBuilder builds smaller datasets on the stack instead of using malloc.
+ this can be significantly faster for small bufs. However, you can not decouple() the
+ buffer with StackBufBuilder.
+ While designed to be a variable on the stack, if you were to dynamically allocate one,
+ nothing bad would happen. In fact in some circumstances this might make sense, say,
+ embedded in some other object.
+ */
+ class StackBufBuilder : public _BufBuilder<StackAllocator> {
+ public:
+ StackBufBuilder() : _BufBuilder<StackAllocator>(StackAllocator::SZ) { }
+ void decouple(); // not allowed. not implemented.
+ };
+
+#if defined(_WIN32)
+#pragma warning( push )
+// warning C4996: 'sprintf': This function or variable may be unsafe. Consider using sprintf_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS.
+#pragma warning( disable : 4996 )
+#endif
+
+ /** stringstream deals with locale so this is a lot faster than std::stringstream for UTF8 */
+ class StringBuilder {
+ public:
+ StringBuilder( int initsize=256 )
+ : _buf( initsize ) {
+ }
+
+ StringBuilder& operator<<( double x ) {
+ return SBNUM( x , 25 , "%g" );
+ }
+ StringBuilder& operator<<( int x ) {
+ return SBNUM( x , 11 , "%d" );
+ }
+ StringBuilder& operator<<( unsigned x ) {
+ return SBNUM( x , 11 , "%u" );
+ }
+ StringBuilder& operator<<( long x ) {
+ return SBNUM( x , 22 , "%ld" );
+ }
+ StringBuilder& operator<<( unsigned long x ) {
+ return SBNUM( x , 22 , "%lu" );
+ }
+ StringBuilder& operator<<( long long x ) {
+ return SBNUM( x , 22 , "%lld" );
+ }
+ StringBuilder& operator<<( unsigned long long x ) {
+ return SBNUM( x , 22 , "%llu" );
+ }
+ StringBuilder& operator<<( short x ) {
+ return SBNUM( x , 8 , "%hd" );
+ }
+ StringBuilder& operator<<( char c ) {
+ _buf.grow( 1 )[0] = c;
+ return *this;
+ }
+
+ void appendDoubleNice( double x ) {
+ int prev = _buf.l;
+ char * start = _buf.grow( 32 );
+ int z = sprintf( start , "%.16g" , x );
+ assert( z >= 0 );
+ _buf.l = prev + z;
+ if( strchr(start, '.') == 0 && strchr(start, 'E') == 0 && strchr(start, 'N') == 0 ) {
+ write( ".0" , 2 );
+ }
+ }
+
+ void write( const char* buf, int len) { memcpy( _buf.grow( len ) , buf , len ); }
+
+ void append( const StringData& str ) { memcpy( _buf.grow( str.size() ) , str.data() , str.size() ); }
+
+ StringBuilder& operator<<( const StringData& str ) {
+ append( str );
+ return *this;
+ }
+
+ void reset( int maxSize = 0 ) { _buf.reset( maxSize ); }
+
+ std::string str() const { return std::string(_buf.data, _buf.l); }
+
+ int len() const { return _buf.l; }
+
+ private:
+ BufBuilder _buf;
+
+ // non-copyable, non-assignable
+ StringBuilder( const StringBuilder& );
+ StringBuilder& operator=( const StringBuilder& );
+
+ template <typename T>
+ StringBuilder& SBNUM(T val,int maxSize,const char *macro) {
+ int prev = _buf.l;
+ int z = sprintf( _buf.grow(maxSize) , macro , (val) );
+ assert( z >= 0 );
+ _buf.l = prev + z;
+ return *this;
+ }
+ };
+
+#if defined(_WIN32)
+#pragma warning( pop )
+#endif
+
+} // namespace mongo
diff --git a/src/mongo/bson/util/misc.h b/src/mongo/bson/util/misc.h
new file mode 100644
index 00000000000..b547c981bdf
--- /dev/null
+++ b/src/mongo/bson/util/misc.h
@@ -0,0 +1,121 @@
+/* @file misc.h
+*/
+
+/*
+ * Copyright 2009 10gen Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <ctime>
+
+namespace mongo {
+
+ using namespace std;
+
+ inline void time_t_to_String(time_t t, char *buf) {
+#if defined(_WIN32)
+ ctime_s(buf, 32, &t);
+#else
+ ctime_r(&t, buf);
+#endif
+ buf[24] = 0; // don't want the \n
+ }
+
+ inline string time_t_to_String(time_t t = time(0) ) {
+ char buf[64];
+#if defined(_WIN32)
+ ctime_s(buf, sizeof(buf), &t);
+#else
+ ctime_r(&t, buf);
+#endif
+ buf[24] = 0; // don't want the \n
+ return buf;
+ }
+
+ inline string time_t_to_String_no_year(time_t t) {
+ char buf[64];
+#if defined(_WIN32)
+ ctime_s(buf, sizeof(buf), &t);
+#else
+ ctime_r(&t, buf);
+#endif
+ buf[19] = 0;
+ return buf;
+ }
+
+ inline string time_t_to_String_short(time_t t) {
+ char buf[64];
+#if defined(_WIN32)
+ ctime_s(buf, sizeof(buf), &t);
+#else
+ ctime_r(&t, buf);
+#endif
+ buf[19] = 0;
+ if( buf[0] && buf[1] && buf[2] && buf[3] )
+ return buf + 4; // skip day of week
+ return buf;
+ }
+
+ struct Date_t {
+ // TODO: make signed (and look for related TODO's)
+ unsigned long long millis;
+ Date_t(): millis(0) {}
+ Date_t(unsigned long long m): millis(m) {}
+ operator unsigned long long&() { return millis; }
+ operator const unsigned long long&() const { return millis; }
+ void toTm (tm *buf) {
+ time_t dtime = (time_t) millis/1000;
+#if defined(_WIN32)
+ gmtime_s(buf, &dtime);
+#else
+ gmtime_r(&dtime, buf);
+#endif
+ }
+ string toString() const {
+ char buf[64];
+ time_t_to_String(millis/1000, buf);
+ return buf;
+ }
+ };
+
+ // Like strlen, but only scans up to n bytes.
+ // Returns -1 if no '0' found.
+ inline int strnlen( const char *s, int n ) {
+ for( int i = 0; i < n; ++i )
+ if ( !s[ i ] )
+ return i;
+ return -1;
+ }
+
+ inline bool isNumber( char c ) {
+ return c >= '0' && c <= '9';
+ }
+
+ inline unsigned stringToNum(const char *str) {
+ unsigned x = 0;
+ const char *p = str;
+ while( 1 ) {
+ if( !isNumber(*p) ) {
+ if( *p == 0 && p != str )
+ break;
+ throw 0;
+ }
+ x = x * 10 + *p++ - '0';
+ }
+ return x;
+ }
+
+}