diff options
Diffstat (limited to 'src/mongo/bson/bsonobjbuilder.h')
-rw-r--r-- | src/mongo/bson/bsonobjbuilder.h | 1591 |
1 files changed, 816 insertions, 775 deletions
diff --git a/src/mongo/bson/bsonobjbuilder.h b/src/mongo/bson/bsonobjbuilder.h index 4ca65d75693..76ed3f60ec8 100644 --- a/src/mongo/bson/bsonobjbuilder.h +++ b/src/mongo/bson/bsonobjbuilder.h @@ -50,918 +50,959 @@ namespace mongo { #if defined(_WIN32) // warning: 'this' : used in base member initializer list -#pragma warning( disable : 4355 ) +#pragma warning(disable : 4355) #endif - /** Utility for creating a BSONObj. - See also the BSON() and BSON_ARRAY() macros. - */ - class BSONObjBuilder { - MONGO_DISALLOW_COPYING(BSONObjBuilder); - public: - /** @param initsize this is just a hint as to the final size of the object */ - BSONObjBuilder(int initsize=512) - : _b(_buf) - , _buf(sizeof(BSONObj::Holder) + initsize) - , _offset(sizeof(BSONObj::Holder)) - , _s(this) - , _tracker(0) - , _doneCalled(false) { - // Skip over space for a holder object at the beginning of the buffer, followed by - // space for the object length. The length is filled in by _done. - _b.skip(sizeof(BSONObj::Holder)); - _b.skip(sizeof(int)); - - // Reserve space for the EOO byte. This means _done() can't fail. - _b.reserveBytes(1); - } +/** Utility for creating a BSONObj. + See also the BSON() and BSON_ARRAY() macros. +*/ +class BSONObjBuilder { + MONGO_DISALLOW_COPYING(BSONObjBuilder); + +public: + /** @param initsize this is just a hint as to the final size of the object */ + BSONObjBuilder(int initsize = 512) + : _b(_buf), + _buf(sizeof(BSONObj::Holder) + initsize), + _offset(sizeof(BSONObj::Holder)), + _s(this), + _tracker(0), + _doneCalled(false) { + // Skip over space for a holder object at the beginning of the buffer, followed by + // space for the object length. The length is filled in by _done. + _b.skip(sizeof(BSONObj::Holder)); + _b.skip(sizeof(int)); + + // Reserve space for the EOO byte. This means _done() can't fail. + _b.reserveBytes(1); + } - /** @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) { - // Skip over space for the object length, which is filled in by _done. We don't need a - // holder since we are a sub-builder, and some parent builder has already made the - // reservation. - _b.skip(sizeof(int)); - - // Reserve space for the EOO byte. This means _done() can't fail. - _b.reserveBytes(1); - } + /** @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) { + // Skip over space for the object length, which is filled in by _done. We don't need a + // holder since we are a sub-builder, and some parent builder has already made the + // reservation. + _b.skip(sizeof(int)); + + // Reserve space for the EOO byte. This means _done() can't fail. + _b.reserveBytes(1); + } - BSONObjBuilder( const BSONSizeTracker & tracker ) - : _b(_buf) - , _buf(sizeof(BSONObj::Holder) + tracker.getSize()) - , _offset(sizeof(BSONObj::Holder)) - , _s(this) - , _tracker(const_cast<BSONSizeTracker*>(&tracker)) - , _doneCalled(false) { - // See the comments in the first constructor for details. - _b.skip(sizeof(BSONObj::Holder)); - _b.skip(sizeof(int)); - - // Reserve space for the EOO byte. This means _done() can't fail. - _b.reserveBytes(1); - } + BSONObjBuilder(const BSONSizeTracker& tracker) + : _b(_buf), + _buf(sizeof(BSONObj::Holder) + tracker.getSize()), + _offset(sizeof(BSONObj::Holder)), + _s(this), + _tracker(const_cast<BSONSizeTracker*>(&tracker)), + _doneCalled(false) { + // See the comments in the first constructor for details. + _b.skip(sizeof(BSONObj::Holder)); + _b.skip(sizeof(int)); + + // Reserve space for the EOO byte. This means _done() can't fail. + _b.reserveBytes(1); + } - ~BSONObjBuilder() { - // If 'done' has not already been called, and we have a reference to an owning - // BufBuilder but do not own it ourselves, then we must call _done to write in the - // length. Otherwise, we own this memory and its lifetime ends with us, therefore - // we can elide the write. - if ( !_doneCalled && _b.buf() && _buf.getSize() == 0 ) { - _done(); - } + ~BSONObjBuilder() { + // If 'done' has not already been called, and we have a reference to an owning + // BufBuilder but do not own it ourselves, then we must call _done to write in the + // length. Otherwise, we own this memory and its lifetime ends with us, therefore + // we can elide the write. + 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) { - verify( !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; - } + /** add all the fields from the object specified to this object */ + BSONObjBuilder& appendElements(BSONObj x); - /** append an element but with a new name */ - BSONObjBuilder& appendAs(const BSONElement& e, StringData fieldName) { - verify( !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 all the fields from the object specified to this object if they don't exist already */ + BSONObjBuilder& appendElementsUnique(BSONObj x); - /** add a subobject as a member */ - BSONObjBuilder& append(StringData fieldName, BSONObj subObj) { - _b.appendNum((char) Object); - _b.appendStr(fieldName); - _b.appendBuf((void *) subObj.objdata(), subObj.objsize()); - return *this; - } + /** append element to the object we are building */ + BSONObjBuilder& append(const BSONElement& e) { + verify( + !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; + } - /** add a subobject as a member */ - BSONObjBuilder& appendObject(StringData fieldName, const char * objdata , int size = 0 ) { - verify( objdata ); - if ( size == 0 ) { - size = ConstDataView(objdata).read<LittleEndian<int>>(); - } + /** append an element but with a new name */ + BSONObjBuilder& appendAs(const BSONElement& e, StringData fieldName) { + verify( + !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; + } - verify( size > 4 && size < 100000000 ); + /** add a subobject as a member */ + BSONObjBuilder& append(StringData fieldName, BSONObj subObj) { + _b.appendNum((char)Object); + _b.appendStr(fieldName); + _b.appendBuf((void*)subObj.objdata(), subObj.objsize()); + return *this; + } - _b.appendNum((char) Object); - _b.appendStr(fieldName); - _b.appendBuf((void*)objdata, size ); - return *this; + /** add a subobject as a member */ + BSONObjBuilder& appendObject(StringData fieldName, const char* objdata, int size = 0) { + verify(objdata); + if (size == 0) { + size = ConstDataView(objdata).read<LittleEndian<int>>(); } - /** 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(StringData fieldName) { - _b.appendNum((char) Object); - _b.appendStr(fieldName); - return _b; - } + verify(size > 4 && size < 100000000); - /** add a subobject as a member with type Array. Thus arr object should have "0", "1", ... - style fields in it. - */ - BSONObjBuilder& appendArray(StringData fieldName, const BSONObj &subObj) { - _b.appendNum((char) Array); - _b.appendStr(fieldName); - _b.appendBuf((void *) subObj.objdata(), subObj.objsize()); - return *this; - } - BSONObjBuilder& append(StringData fieldName, BSONArray arr) { - return appendArray(fieldName, arr); - } + _b.appendNum((char)Object); + _b.appendStr(fieldName); + _b.appendBuf((void*)objdata, size); + return *this; + } - /** add header for a new subarray and return bufbuilder for writing to - the subarray's body */ - BufBuilder &subarrayStart(StringData fieldName) { - _b.appendNum((char) Array); - _b.appendStr(fieldName); - return _b; - } + /** 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(StringData fieldName) { + _b.appendNum((char)Object); + _b.appendStr(fieldName); + return _b; + } - /** Append a boolean element */ - BSONObjBuilder& appendBool(StringData fieldName, int val) { - _b.appendNum((char) Bool); - _b.appendStr(fieldName); - _b.appendNum((char) (val?1:0)); - return *this; - } + /** add a subobject as a member with type Array. Thus arr object should have "0", "1", ... + style fields in it. + */ + BSONObjBuilder& appendArray(StringData fieldName, const BSONObj& subObj) { + _b.appendNum((char)Array); + _b.appendStr(fieldName); + _b.appendBuf((void*)subObj.objdata(), subObj.objsize()); + return *this; + } + BSONObjBuilder& append(StringData fieldName, BSONArray arr) { + return appendArray(fieldName, arr); + } - /** Append a boolean element */ - BSONObjBuilder& append(StringData fieldName, bool val) { - _b.appendNum((char) Bool); - _b.appendStr(fieldName); - _b.appendNum((char) (val?1:0)); - return *this; - } + /** add header for a new subarray and return bufbuilder for writing to + the subarray's body */ + BufBuilder& subarrayStart(StringData fieldName) { + _b.appendNum((char)Array); + _b.appendStr(fieldName); + return _b; + } - /** Append a 32 bit integer element */ - BSONObjBuilder& append(StringData fieldName, int n) { - _b.appendNum((char) NumberInt); - _b.appendStr(fieldName); - _b.appendNum(n); - return *this; - } + /** Append a boolean element */ + BSONObjBuilder& appendBool(StringData fieldName, int val) { + _b.appendNum((char)Bool); + _b.appendStr(fieldName); + _b.appendNum((char)(val ? 1 : 0)); + return *this; + } - /** Append a 32 bit unsigned element - cast to a signed int. */ - BSONObjBuilder& append(StringData fieldName, unsigned n) { - return append(fieldName, (int) n); - } + /** Append a boolean element */ + BSONObjBuilder& append(StringData fieldName, bool val) { + _b.appendNum((char)Bool); + _b.appendStr(fieldName); + _b.appendNum((char)(val ? 1 : 0)); + return *this; + } - /** Append a NumberLong */ - BSONObjBuilder& append(StringData fieldName, long long n) { - _b.appendNum((char) NumberLong); - _b.appendStr(fieldName); - _b.appendNum(n); - return *this; - } + /** Append a 32 bit integer element */ + BSONObjBuilder& append(StringData fieldName, int n) { + _b.appendNum((char)NumberInt); + _b.appendStr(fieldName); + _b.appendNum(n); + return *this; + } - /** appends a number. if n < max(int)/2 then uses int, otherwise long long */ - BSONObjBuilder& appendIntOrLL( StringData fieldName , long long n ) { - // extra () to avoid max macro on windows - static const long long maxInt = (std::numeric_limits<int>::max)() / 2; - static const long long minInt = -maxInt; - if ( minInt < n && n < maxInt ) { - append( fieldName , static_cast<int>( n ) ); - } - else { - append( fieldName , n ); - } - return *this; - } + /** Append a 32 bit unsigned element - cast to a signed int. */ + BSONObjBuilder& append(StringData fieldName, unsigned n) { + return append(fieldName, (int)n); + } - /** - * appendNumber is a series of method for appending the smallest sensible type - * mostly for JS - */ - BSONObjBuilder& appendNumber( StringData fieldName , int n ) { - return append( fieldName , n ); - } + /** Append a NumberLong */ + BSONObjBuilder& append(StringData fieldName, long long n) { + _b.appendNum((char)NumberLong); + _b.appendStr(fieldName); + _b.appendNum(n); + return *this; + } - BSONObjBuilder& appendNumber( StringData fieldName , double d ) { - return append( fieldName , d ); + /** appends a number. if n < max(int)/2 then uses int, otherwise long long */ + BSONObjBuilder& appendIntOrLL(StringData fieldName, long long n) { + // extra () to avoid max macro on windows + static const long long maxInt = (std::numeric_limits<int>::max)() / 2; + static const long long minInt = -maxInt; + if (minInt < n && n < maxInt) { + append(fieldName, static_cast<int>(n)); + } else { + append(fieldName, n); } + return *this; + } - BSONObjBuilder& appendNumber( StringData fieldName , size_t n ) { - static const size_t maxInt = ( 1 << 30 ); + /** + * appendNumber is a series of method for appending the smallest sensible type + * mostly for JS + */ + BSONObjBuilder& appendNumber(StringData fieldName, int n) { + return append(fieldName, n); + } - if ( n < maxInt ) - append( fieldName, static_cast<int>( n ) ); - else - append( fieldName, static_cast<long long>( n ) ); - return *this; - } + BSONObjBuilder& appendNumber(StringData fieldName, double d) { + return append(fieldName, d); + } - BSONObjBuilder& appendNumber( StringData fieldName, long long llNumber ) { - static const long long maxInt = ( 1LL << 30 ); - static const long long minInt = -maxInt; - static const long long maxDouble = ( 1LL << 40 ); - static const long long minDouble = -maxDouble; - - if ( minInt < llNumber && llNumber < maxInt ) { - append( fieldName, static_cast<int>( llNumber ) ); - } - else if ( minDouble < llNumber && llNumber < maxDouble ) { - append( fieldName, static_cast<double>( llNumber ) ); - } - else { - append( fieldName, llNumber ); - } - - return *this; - } + BSONObjBuilder& appendNumber(StringData fieldName, size_t n) { + static const size_t maxInt = (1 << 30); - /** Append a double element */ - BSONObjBuilder& append(StringData fieldName, double n) { - _b.appendNum((char) NumberDouble); - _b.appendStr(fieldName); - _b.appendNum(n); - return *this; - } + if (n < maxInt) + append(fieldName, static_cast<int>(n)); + else + append(fieldName, static_cast<long long>(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( StringData fieldName , const std::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(StringData fieldName, OID *oid = 0 , bool generateIfBlank = false ) { - _b.appendNum((char) jstOID); - _b.appendStr(fieldName); - if ( oid ) - _b.appendBuf( oid->view().view(), OID::kOIDSize ); - else { - OID tmp; - if ( generateIfBlank ) - tmp.init(); - else - tmp.clear(); - _b.appendBuf( tmp.view().view(), OID::kOIDSize ); - } - return *this; - } + BSONObjBuilder& appendNumber(StringData fieldName, long long llNumber) { + static const long long maxInt = (1LL << 30); + static const long long minInt = -maxInt; + static const long long maxDouble = (1LL << 40); + static const long long minDouble = -maxDouble; - /** - Append a BSON Object ID. - @param fieldName Field name, e.g., "_id". - @returns the builder object - */ - BSONObjBuilder& append( StringData fieldName, OID oid ) { - _b.appendNum((char) jstOID); - _b.appendStr(fieldName); - _b.appendBuf( oid.view().view(), OID::kOIDSize ); - return *this; + if (minInt < llNumber && llNumber < maxInt) { + append(fieldName, static_cast<int>(llNumber)); + } else if (minDouble < llNumber && llNumber < maxDouble) { + append(fieldName, static_cast<double>(llNumber)); + } else { + append(fieldName, llNumber); } - /** - 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()); - } + return *this; + } - /** 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(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(StringData fieldName, Date_t dt); - BSONObjBuilder& append(StringData fieldName, Date_t dt) { - return appendDate(fieldName, dt); - } + /** Append a double element */ + BSONObjBuilder& append(StringData fieldName, double n) { + _b.appendNum((char)NumberDouble); + _b.appendStr(fieldName); + _b.appendNum(n); + return *this; + } - /** Append a regular expression value - @param regex the regular expression pattern - @param regex options such as "i" or "g" - */ - BSONObjBuilder& appendRegex(StringData fieldName, StringData regex, StringData options = "") { - _b.appendNum((char) RegEx); - _b.appendStr(fieldName); - _b.appendStr(regex); - _b.appendStr(options); - 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(StringData fieldName, const std::string& data); - BSONObjBuilder& append(StringData fieldName, const BSONRegEx& regex) { - return appendRegex(fieldName, regex.pattern, regex.flags); + /** Append a BSON Object ID (OID type). + @deprecated Generally, it is preferred to use the append append(name, oid) + method for this. + */ + BSONObjBuilder& appendOID(StringData fieldName, OID* oid = 0, bool generateIfBlank = false) { + _b.appendNum((char)jstOID); + _b.appendStr(fieldName); + if (oid) + _b.appendBuf(oid->view().view(), OID::kOIDSize); + else { + OID tmp; + if (generateIfBlank) + tmp.init(); + else + tmp.clear(); + _b.appendBuf(tmp.view().view(), OID::kOIDSize); } + return *this; + } - BSONObjBuilder& appendCode(StringData fieldName, StringData code) { - _b.appendNum((char) Code); - _b.appendStr(fieldName); - _b.appendNum((int) code.size()+1); - _b.appendStr(code); - return *this; - } + /** + Append a BSON Object ID. + @param fieldName Field name, e.g., "_id". + @returns the builder object + */ + BSONObjBuilder& append(StringData fieldName, OID oid) { + _b.appendNum((char)jstOID); + _b.appendStr(fieldName); + _b.appendBuf(oid.view().view(), OID::kOIDSize); + return *this; + } - BSONObjBuilder& append(StringData fieldName, const BSONCode& code) { - return appendCode(fieldName, code.code); - } + /** + 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 std::string element. - @param sz size includes terminating null character */ - BSONObjBuilder& append(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 std::string element */ - BSONObjBuilder& append(StringData fieldName, const char *str) { - return append(fieldName, str, (int) strlen(str)+1); - } - /** Append a std::string element */ - BSONObjBuilder& append(StringData fieldName, const std::string& str) { - return append(fieldName, str.c_str(), (int) str.size()+1); - } - /** Append a std::string element */ - BSONObjBuilder& append(StringData fieldName, StringData str) { - _b.appendNum((char) String); - _b.appendStr(fieldName); - _b.appendNum((int)str.size()+1); - _b.appendStr(str, true); - return *this; - } + /** 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(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(StringData fieldName, Date_t dt); + BSONObjBuilder& append(StringData fieldName, Date_t dt) { + return appendDate(fieldName, dt); + } - BSONObjBuilder& appendSymbol(StringData fieldName, StringData symbol) { - _b.appendNum((char) Symbol); - _b.appendStr(fieldName); - _b.appendNum((int) symbol.size()+1); - _b.appendStr(symbol); - return *this; - } + /** Append a regular expression value + @param regex the regular expression pattern + @param regex options such as "i" or "g" + */ + BSONObjBuilder& appendRegex(StringData fieldName, StringData regex, StringData options = "") { + _b.appendNum((char)RegEx); + _b.appendStr(fieldName); + _b.appendStr(regex); + _b.appendStr(options); + return *this; + } - BSONObjBuilder& append(StringData fieldName, const BSONSymbol& symbol) { - return appendSymbol(fieldName, symbol.symbol); - } + BSONObjBuilder& append(StringData fieldName, const BSONRegEx& regex) { + return appendRegex(fieldName, regex.pattern, regex.flags); + } - /** Implements builder interface but no-op in ObjBuilder */ - void appendNull() { - msgasserted(16234, "Invalid call to appendNull in BSONObj Builder."); - } + BSONObjBuilder& appendCode(StringData fieldName, StringData code) { + _b.appendNum((char)Code); + _b.appendStr(fieldName); + _b.appendNum((int)code.size() + 1); + _b.appendStr(code); + return *this; + } - /** Append a Null element to the object */ - BSONObjBuilder& appendNull( StringData fieldName ) { - _b.appendNum( (char) jstNULL ); - _b.appendStr( fieldName ); - return *this; - } + BSONObjBuilder& append(StringData fieldName, const BSONCode& code) { + return appendCode(fieldName, code.code); + } - // Append an element that is less than all other keys. - BSONObjBuilder& appendMinKey( StringData fieldName ) { - _b.appendNum( (char) MinKey ); - _b.appendStr( fieldName ); - return *this; - } - // Append an element that is greater than all other keys. - BSONObjBuilder& appendMaxKey( StringData fieldName ) { - _b.appendNum( (char) MaxKey ); - _b.appendStr( fieldName ); - return *this; - } + /** Append a std::string element. + @param sz size includes terminating null character */ + BSONObjBuilder& append(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 std::string element */ + BSONObjBuilder& append(StringData fieldName, const char* str) { + return append(fieldName, str, (int)strlen(str) + 1); + } + /** Append a std::string element */ + BSONObjBuilder& append(StringData fieldName, const std::string& str) { + return append(fieldName, str.c_str(), (int)str.size() + 1); + } + /** Append a std::string element */ + BSONObjBuilder& append(StringData fieldName, StringData str) { + _b.appendNum((char)String); + _b.appendStr(fieldName); + _b.appendNum((int)str.size() + 1); + _b.appendStr(str, true); + return *this; + } - // Append a Timestamp field -- will be updated to next server Timestamp - BSONObjBuilder& appendTimestamp( StringData fieldName ); - - BSONObjBuilder& appendTimestamp( StringData fieldName , unsigned long long val ); - - /** - * To store a Timestamp in BSON, use this function. - * This captures both the secs and inc fields. - */ - BSONObjBuilder& append(StringData fieldName, Timestamp timestamp); - - /* - Append an element of the deprecated DBRef type. - @deprecated - */ - BSONObjBuilder& appendDBRef( StringData fieldName, StringData ns, const OID &oid ) { - _b.appendNum( (char) DBRef ); - _b.appendStr( fieldName ); - _b.appendNum( (int) ns.size() + 1 ); - _b.appendStr( ns ); - _b.appendBuf( oid.view().view(), OID::kOIDSize ); - return *this; - } + BSONObjBuilder& appendSymbol(StringData fieldName, StringData symbol) { + _b.appendNum((char)Symbol); + _b.appendStr(fieldName); + _b.appendNum((int)symbol.size() + 1); + _b.appendStr(symbol); + return *this; + } - BSONObjBuilder& append(StringData fieldName, const BSONDBRef& dbref) { - return appendDBRef(fieldName, dbref.ns, dbref.oid); - } + BSONObjBuilder& append(StringData fieldName, const BSONSymbol& symbol) { + return appendSymbol(fieldName, symbol.symbol); + } - /** 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( 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; - } + /** Implements builder interface but no-op in ObjBuilder */ + void appendNull() { + msgasserted(16234, "Invalid call to appendNull in BSONObj Builder."); + } - BSONObjBuilder& append(StringData fieldName, const BSONBinData& bd) { - return appendBinData(fieldName, bd.length, bd.type, bd.data); - } + /** Append a Null element to the object */ + BSONObjBuilder& appendNull(StringData fieldName) { + _b.appendNum((char)jstNULL); + _b.appendStr(fieldName); + 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 an element that is less than all other keys. + BSONObjBuilder& appendMinKey(StringData fieldName) { + _b.appendNum((char)MinKey); + _b.appendStr(fieldName); + return *this; + } + // Append an element that is greater than all other keys. + BSONObjBuilder& appendMaxKey(StringData fieldName) { + _b.appendNum((char)MaxKey); + _b.appendStr(fieldName); + 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( StringData fieldName, 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; - } + // Append a Timestamp field -- will be updated to next server Timestamp + BSONObjBuilder& appendTimestamp(StringData fieldName); - BSONObjBuilder& append(StringData fieldName, const BSONCodeWScope& cws) { - return appendCodeWScope(fieldName, cws.code, cws.scope); - } + BSONObjBuilder& appendTimestamp(StringData fieldName, unsigned long long val); - void appendUndefined( StringData fieldName ) { - _b.appendNum( (char) Undefined ); - _b.appendStr( fieldName ); - } + /** + * To store a Timestamp in BSON, use this function. + * This captures both the secs and inc fields. + */ + BSONObjBuilder& append(StringData fieldName, Timestamp timestamp); - /* helper function -- see Query::where() for primary way to do this. */ - void appendWhere( StringData code, const BSONObj &scope ) { - appendCodeWScope( "$where" , code , scope ); - } + /* + Append an element of the deprecated DBRef type. + @deprecated + */ + BSONObjBuilder& appendDBRef(StringData fieldName, StringData ns, const OID& oid) { + _b.appendNum((char)DBRef); + _b.appendStr(fieldName); + _b.appendNum((int)ns.size() + 1); + _b.appendStr(ns); + _b.appendBuf(oid.view().view(), OID::kOIDSize); + return *this; + } - /** - these are the min/max when comparing, not strict min/max elements for a given type - */ - void appendMinForType( StringData fieldName , int type ); - void appendMaxForType( StringData fieldName , int type ); - - /** Append an array of values. */ - template < class T > - BSONObjBuilder& append( StringData fieldName, const std::vector< T >& vals ); - - template < class T > - BSONObjBuilder& append( StringData fieldName, const std::list< T >& vals ); - - /** Append a set of values. */ - template < class T > - BSONObjBuilder& append( StringData fieldName, const std::set< T >& vals ); - - /** - * Append a map of values as a sub-object. - * Note: the keys of the map should be StringData-compatible (i.e. strings). - */ - template < class K, class T > - BSONObjBuilder& append( StringData fieldName, const std::map< K, T >& vals ); - - /** - * destructive - * The returned BSONObj will free the buffer when it is finished. - * @return owned BSONObj - */ - BSONObj obj() { - massert( 10335 , "builder does not own memory", owned() ); - doneFast(); - char* buf = _b.buf(); - decouple(); - return BSONObj::takeOwnership(buf); - } + BSONObjBuilder& append(StringData fieldName, const BSONDBRef& dbref) { + return appendDBRef(fieldName, dbref.ns, dbref.oid); + } - /** 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()); - } + /** 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(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; + } - // Like 'done' above, but does not construct a BSONObj to return to the caller. - void doneFast() { - (void)_done(); - } + BSONObjBuilder& append(StringData fieldName, const BSONBinData& bd) { + return appendBinData(fieldName, bd.length, bd.type, bd.data); + } - /** 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 - _b.reserveBytes(1); // Rereserve room for the real EOO - _doneCalled = false; - return temp; - } + /** + 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; + } - /** Make it look as if "done" has been called, so that our destructor is a no-op. Do - * this if you know that you don't care about the contents of the builder you are - * destroying. - * - * Note that it is invalid to call any method other than the destructor after invoking - * this method. - */ - void abandon() { - _doneCalled = true; - } + /** 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(StringData fieldName, 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 decouple() { - _b.decouple(); // post done() call version. be sure jsobj frees... - } + BSONObjBuilder& append(StringData fieldName, const BSONCodeWScope& cws) { + return appendCodeWScope(fieldName, cws.code, cws.scope); + } - void appendKeys( const BSONObj& keyPattern , const BSONObj& values ); + void appendUndefined(StringData fieldName) { + _b.appendNum((char)Undefined); + _b.appendStr(fieldName); + } - static std::string numStr( int i ) { - if (i>=0 && i<100 && numStrsReady) - return numStrs[i]; - StringBuilder o; - o << i; - return o.str(); - } + /* helper function -- see Query::where() for primary way to do this. */ + void appendWhere(StringData code, const BSONObj& scope) { + appendCodeWScope("$where", code, scope); + } - /** Stream oriented way to add field names and values. */ - BSONObjBuilderValueStream &operator<<( StringData name ) { - _s.endField( name ); - return _s; - } + /** + these are the min/max when comparing, not strict min/max elements for a given type + */ + void appendMinForType(StringData fieldName, int type); + void appendMaxForType(StringData fieldName, int type); + + /** Append an array of values. */ + template <class T> + BSONObjBuilder& append(StringData fieldName, const std::vector<T>& vals); + + template <class T> + BSONObjBuilder& append(StringData fieldName, const std::list<T>& vals); + + /** Append a set of values. */ + template <class T> + BSONObjBuilder& append(StringData fieldName, const std::set<T>& vals); + + /** + * Append a map of values as a sub-object. + * Note: the keys of the map should be StringData-compatible (i.e. strings). + */ + template <class K, class T> + BSONObjBuilder& append(StringData fieldName, const std::map<K, T>& vals); + + /** + * destructive + * The returned BSONObj will free the buffer when it is finished. + * @return owned BSONObj + */ + BSONObj obj() { + massert(10335, "builder does not own memory", owned()); + doneFast(); + char* buf = _b.buf(); + decouple(); + return BSONObj::takeOwnership(buf); + } - /** Stream oriented way to add field names and values. */ - BSONObjBuilder& operator<<( GENOIDLabeler ) { return genOID(); } + /** 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()); + } - Labeler operator<<( const Labeler::Label &l ) { - massert( 10336 , "No subobject started", _s.subobjStarted() ); - return _s << l; - } + // Like 'done' above, but does not construct a BSONObj to return to the caller. + void doneFast() { + (void)_done(); + } - template<typename T> - BSONObjBuilderValueStream& operator<<( const BSONField<T>& f ) { - _s.endField( f.name() ); - return _s; - } + /** 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 + _b.reserveBytes(1); // Rereserve room for the real EOO + _doneCalled = false; + return temp; + } - template<typename T> - BSONObjBuilder& operator<<( const BSONFieldValue<T>& v ) { - append( v.name(), v.value() ); - return *this; - } + /** Make it look as if "done" has been called, so that our destructor is a no-op. Do + * this if you know that you don't care about the contents of the builder you are + * destroying. + * + * Note that it is invalid to call any method other than the destructor after invoking + * this method. + */ + void abandon() { + _doneCalled = true; + } - BSONObjBuilder& operator<<( const BSONElement& e ){ - append( e ); - return *this; - } + void decouple() { + _b.decouple(); // post done() call version. be sure jsobj frees... + } - bool isArray() const { - return false; - } + void appendKeys(const BSONObj& keyPattern, const BSONObj& values); - /** @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; } + static std::string numStr(int i) { + if (i >= 0 && i < 100 && numStrsReady) + return numStrs[i]; + StringBuilder o; + o << i; + return o.str(); + } - BSONObjIterator iterator() const ; + /** Stream oriented way to add field names and values. */ + BSONObjBuilderValueStream& operator<<(StringData name) { + _s.endField(name); + return _s; + } - bool hasField( StringData name ) const ; + /** Stream oriented way to add field names and values. */ + BSONObjBuilder& operator<<(GENOIDLabeler) { + return genOID(); + } - int len() const { return _b.len(); } + Labeler operator<<(const Labeler::Label& l) { + massert(10336, "No subobject started", _s.subobjStarted()); + return _s << l; + } - BufBuilder& bb() { return _b; } + template <typename T> + BSONObjBuilderValueStream& operator<<(const BSONField<T>& f) { + _s.endField(f.name()); + return _s; + } - private: - char* _done() { - if ( _doneCalled ) - return _b.buf() + _offset; + template <typename T> + BSONObjBuilder& operator<<(const BSONFieldValue<T>& v) { + append(v.name(), v.value()); + return *this; + } - _doneCalled = true; + BSONObjBuilder& operator<<(const BSONElement& e) { + append(e); + return *this; + } - // TODO remove this or find some way to prevent it from failing. Since this is intended - // for use with BSON() literal queries, it is less likely to result in oversized BSON. - _s.endField(); + bool isArray() const { + return false; + } - _b.claimReservedBytes(1); // Prevents adding EOO from failing. - _b.appendNum((char) EOO); + /** @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; + } - char *data = _b.buf() + _offset; - int size = _b.len() - _offset; - DataView(data).write(tagLittleEndian(size)); - if ( _tracker ) - _tracker->got( size ); - return data; - } + BSONObjIterator iterator() const; - BufBuilder &_b; - BufBuilder _buf; - int _offset; - BSONObjBuilderValueStream _s; - BSONSizeTracker * _tracker; - bool _doneCalled; - - static const std::string numStrs[100]; // cache of 0 to 99 inclusive - static bool numStrsReady; // for static init safety - }; - - class BSONArrayBuilder { - MONGO_DISALLOW_COPYING(BSONArrayBuilder); - 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; - } + bool hasField(StringData name) const; - BSONArrayBuilder& append(const BSONElement& e) { - _b.appendAs(e, num()); - return *this; - } + int len() const { + return _b.len(); + } - BSONArrayBuilder& operator<<(const BSONElement& e) { - return append(e); - } + BufBuilder& bb() { + return _b; + } - template <typename T> - BSONArrayBuilder& operator<<(const T& x) { - _b << num().c_str() << x; - return *this; - } +private: + char* _done() { + if (_doneCalled) + return _b.buf() + _offset; - void appendNull() { - _b.appendNull(num()); - } + _doneCalled = true; - void appendUndefined() { - _b.appendUndefined(num()); - } + // TODO remove this or find some way to prevent it from failing. Since this is intended + // for use with BSON() literal queries, it is less likely to result in oversized BSON. + _s.endField(); - /** - * destructive - ownership moves to returned BSONArray - * @return owned BSONArray - */ - BSONArray arr() { return BSONArray(_b.obj()); } - BSONObj obj() { return _b.obj(); } + _b.claimReservedBytes(1); // Prevents adding EOO from failing. + _b.appendNum((char)EOO); - BSONObj done() { return _b.done(); } + char* data = _b.buf() + _offset; + int size = _b.len() - _offset; + DataView(data).write(tagLittleEndian(size)); + if (_tracker) + _tracker->got(size); + return data; + } - void doneFast() { _b.doneFast(); } + BufBuilder& _b; + BufBuilder _buf; + int _offset; + BSONObjBuilderValueStream _s; + BSONSizeTracker* _tracker; + bool _doneCalled; - template < class T > - BSONArrayBuilder& append( const std::list< T >& vals ); + static const std::string numStrs[100]; // cache of 0 to 99 inclusive + static bool numStrsReady; // for static init safety +}; - template < class T > - BSONArrayBuilder& append( const std::set< T >& vals ); +class BSONArrayBuilder { + MONGO_DISALLOW_COPYING(BSONArrayBuilder); - // These two just use next position - BufBuilder &subobjStart() { return _b.subobjStart( num() ); } - BufBuilder &subarrayStart() { return _b.subarrayStart( num() ); } +public: + BSONArrayBuilder() : _i(0), _b() {} + BSONArrayBuilder(BufBuilder& _b) : _i(0), _b(_b) {} + BSONArrayBuilder(int initialSize) : _i(0), _b(initialSize) {} - BSONArrayBuilder& appendRegex(StringData regex, StringData options = "") { - _b.appendRegex(num(), regex, options); - return *this; - } + template <typename T> + BSONArrayBuilder& append(const T& x) { + _b.append(num(), x); + return *this; + } - BSONArrayBuilder& appendBinData(int len, BinDataType type, const void* data) { - _b.appendBinData(num(), len, type, data); - return *this; - } + BSONArrayBuilder& append(const BSONElement& e) { + _b.appendAs(e, num()); + return *this; + } - BSONArrayBuilder& appendCode(StringData code) { - _b.appendCode(num(), code); - return *this; - } + BSONArrayBuilder& operator<<(const BSONElement& e) { + return append(e); + } - BSONArrayBuilder& appendCodeWScope(StringData code, const BSONObj& scope) { - _b.appendCodeWScope(num(), code, scope); - return *this; - } + template <typename T> + BSONArrayBuilder& operator<<(const T& x) { + _b << num().c_str() << x; + return *this; + } - BSONArrayBuilder& appendTimeT(time_t dt) { - _b.appendTimeT(num(), dt); - return *this; - } + void appendNull() { + _b.appendNull(num()); + } - BSONArrayBuilder& appendDate(Date_t dt) { - _b.appendDate(num(), dt); - return *this; - } + void appendUndefined() { + _b.appendUndefined(num()); + } - BSONArrayBuilder& appendBool(bool val) { - _b.appendBool(num(), val); - return *this; - } + /** + * destructive - ownership moves to returned BSONArray + * @return owned BSONArray + */ + BSONArray arr() { + return BSONArray(_b.obj()); + } + BSONObj obj() { + return _b.obj(); + } - BSONArrayBuilder& appendTimestamp(unsigned long long ts) { - _b.appendTimestamp(num(), ts); - return *this; - } + BSONObj done() { + return _b.done(); + } - bool isArray() const { - return true; - } + void doneFast() { + _b.doneFast(); + } - int len() const { return _b.len(); } - int arrSize() const { return _i; } + template <class T> + BSONArrayBuilder& append(const std::list<T>& vals); - BufBuilder& bb() { return _b.bb(); } + template <class T> + BSONArrayBuilder& append(const std::set<T>& vals); - private: + // These two just use next position + BufBuilder& subobjStart() { + return _b.subobjStart(num()); + } + BufBuilder& subarrayStart() { + return _b.subarrayStart(num()); + } - std::string num() { return _b.numStr(_i++); } - int _i; - BSONObjBuilder _b; - }; + BSONArrayBuilder& appendRegex(StringData regex, StringData options = "") { + _b.appendRegex(num(), regex, options); + return *this; + } - template < class T > - inline BSONObjBuilder& BSONObjBuilder::append( StringData fieldName, const std::vector< T >& vals ) { - BSONObjBuilder arrBuilder; - for ( unsigned int i = 0; i < vals.size(); ++i ) - arrBuilder.append( numStr( i ), vals[ i ] ); - appendArray( fieldName, arrBuilder.done() ); + BSONArrayBuilder& appendBinData(int len, BinDataType type, const void* data) { + _b.appendBinData(num(), len, type, data); return *this; } - template < class L > - inline BSONObjBuilder& _appendIt( BSONObjBuilder& _this, 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; + BSONArrayBuilder& appendCode(StringData code) { + _b.appendCode(num(), code); + return *this; } - template < class T > - inline BSONObjBuilder& BSONObjBuilder::append( StringData fieldName, const std::list< T >& vals ) { - return _appendIt< std::list< T > >( *this, fieldName, vals ); + BSONArrayBuilder& appendCodeWScope(StringData code, const BSONObj& scope) { + _b.appendCodeWScope(num(), code, scope); + return *this; } - template < class T > - inline BSONObjBuilder& BSONObjBuilder::append( StringData fieldName, const std::set< T >& vals ) { - return _appendIt< std::set< T > >( *this, fieldName, vals ); + BSONArrayBuilder& appendTimeT(time_t dt) { + _b.appendTimeT(num(), dt); + return *this; } - template < class K, class T > - inline BSONObjBuilder& BSONObjBuilder::append( StringData fieldName, const std::map< K, T >& vals ) { - BSONObjBuilder bob; - for( typename std::map<K,T>::const_iterator i = vals.begin(); i != vals.end(); ++i ){ - bob.append(i->first, i->second); - } - append(fieldName, bob.obj()); + BSONArrayBuilder& appendDate(Date_t dt) { + _b.appendDate(num(), dt); return *this; } + BSONArrayBuilder& appendBool(bool val) { + _b.appendBool(num(), val); + return *this; + } - template < class L > - inline BSONArrayBuilder& _appendArrayIt( BSONArrayBuilder& _this, const L& vals ) { - for( typename L::const_iterator i = vals.begin(); i != vals.end(); i++ ) - _this.append( *i ); - return _this; + BSONArrayBuilder& appendTimestamp(unsigned long long ts) { + _b.appendTimestamp(num(), ts); + return *this; } - template < class T > - inline BSONArrayBuilder& BSONArrayBuilder::append( const std::list< T >& vals ) { - return _appendArrayIt< std::list< T > >( *this, vals ); + bool isArray() const { + return true; } - template < class T > - inline BSONArrayBuilder& BSONArrayBuilder::append( const std::set< T >& vals ) { - return _appendArrayIt< std::set< T > >( *this, vals ); + int len() const { + return _b.len(); } - - 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() ); + int arrSize() const { + return _i; } - - // $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) ); } - - inline BSONObjBuilder& BSONObjBuilderValueStream::operator<<(const DateNowLabeler& id) { - _builder->appendDate(_fieldName, jsTime()); - _fieldName = StringData(); - return *_builder; + BufBuilder& bb() { + return _b.bb(); } - inline BSONObjBuilder& BSONObjBuilderValueStream::operator<<(const NullLabeler& id) { - _builder->appendNull(_fieldName); - _fieldName = StringData(); - return *_builder; +private: + std::string num() { + return _b.numStr(_i++); } + int _i; + BSONObjBuilder _b; +}; + +template <class T> +inline BSONObjBuilder& BSONObjBuilder::append(StringData fieldName, const std::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; +} - inline BSONObjBuilder& BSONObjBuilderValueStream::operator<<(const UndefinedLabeler& id) { - _builder->appendUndefined(_fieldName); - _fieldName = StringData(); - return *_builder; - } +template <class L> +inline BSONObjBuilder& _appendIt(BSONObjBuilder& _this, 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(StringData fieldName, const std::list<T>& vals) { + return _appendIt<std::list<T>>(*this, fieldName, vals); +} - inline BSONObjBuilder& BSONObjBuilderValueStream::operator<<(const MinKeyLabeler& id) { - _builder->appendMinKey(_fieldName); - _fieldName = StringData(); - return *_builder; - } +template <class T> +inline BSONObjBuilder& BSONObjBuilder::append(StringData fieldName, const std::set<T>& vals) { + return _appendIt<std::set<T>>(*this, fieldName, vals); +} - inline BSONObjBuilder& BSONObjBuilderValueStream::operator<<(const MaxKeyLabeler& id) { - _builder->appendMaxKey(_fieldName); - _fieldName = StringData(); - return *_builder; +template <class K, class T> +inline BSONObjBuilder& BSONObjBuilder::append(StringData fieldName, const std::map<K, T>& vals) { + BSONObjBuilder bob; + for (typename std::map<K, T>::const_iterator i = vals.begin(); i != vals.end(); ++i) { + bob.append(i->first, i->second); } + append(fieldName, bob.obj()); + return *this; +} - template<class T> inline - BSONObjBuilder& BSONObjBuilderValueStream::operator<<( T value ) { - _builder->append(_fieldName, value); - _fieldName = StringData(); - return *_builder; - } - template<class T> - BSONObjBuilder& Labeler::operator<<( T value ) { - s_->subobj()->append( l_.l_, value ); - return *s_->_builder; - } +template <class L> +inline BSONArrayBuilder& _appendArrayIt(BSONArrayBuilder& _this, const L& vals) { + for (typename L::const_iterator i = vals.begin(); i != vals.end(); i++) + _this.append(*i); + return _this; +} - inline BSONObjBuilder& BSONObjBuilder::append(StringData fieldName, Timestamp optime) { - optime.append(_b, fieldName); - return *this; - } +template <class T> +inline BSONArrayBuilder& BSONArrayBuilder::append(const std::list<T>& vals) { + return _appendArrayIt<std::list<T>>(*this, vals); +} - inline BSONObjBuilder& BSONObjBuilder::appendTimestamp( StringData fieldName ) { - return append(fieldName, Timestamp()); - } +template <class T> +inline BSONArrayBuilder& BSONArrayBuilder::append(const std::set<T>& vals) { + return _appendArrayIt<std::set<T>>(*this, vals); +} - inline BSONObjBuilder& BSONObjBuilder::appendTimestamp( StringData fieldName, - unsigned long long val ) { - return append(fieldName, Timestamp(val)); - } +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()); +} + + +// $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)); +} + +inline BSONObjBuilder& BSONObjBuilderValueStream::operator<<(const DateNowLabeler& id) { + _builder->appendDate(_fieldName, jsTime()); + _fieldName = StringData(); + return *_builder; +} + +inline BSONObjBuilder& BSONObjBuilderValueStream::operator<<(const NullLabeler& id) { + _builder->appendNull(_fieldName); + _fieldName = StringData(); + return *_builder; +} +inline BSONObjBuilder& BSONObjBuilderValueStream::operator<<(const UndefinedLabeler& id) { + _builder->appendUndefined(_fieldName); + _fieldName = StringData(); + return *_builder; +} + + +inline BSONObjBuilder& BSONObjBuilderValueStream::operator<<(const MinKeyLabeler& id) { + _builder->appendMinKey(_fieldName); + _fieldName = StringData(); + return *_builder; +} + +inline BSONObjBuilder& BSONObjBuilderValueStream::operator<<(const MaxKeyLabeler& id) { + _builder->appendMaxKey(_fieldName); + _fieldName = StringData(); + return *_builder; +} + +template <class T> +inline BSONObjBuilder& BSONObjBuilderValueStream::operator<<(T value) { + _builder->append(_fieldName, value); + _fieldName = StringData(); + return *_builder; +} + +template <class T> +BSONObjBuilder& Labeler::operator<<(T value) { + s_->subobj()->append(l_.l_, value); + return *s_->_builder; +} + +inline BSONObjBuilder& BSONObjBuilder::append(StringData fieldName, Timestamp optime) { + optime.append(_b, fieldName); + return *this; +} + +inline BSONObjBuilder& BSONObjBuilder::appendTimestamp(StringData fieldName) { + return append(fieldName, Timestamp()); +} + +inline BSONObjBuilder& BSONObjBuilder::appendTimestamp(StringData fieldName, + unsigned long long val) { + return append(fieldName, Timestamp(val)); +} } |