From e5a43008fd7d030d7ca97d427de8a731228a2aa8 Mon Sep 17 00:00:00 2001 From: Aaron Date: Wed, 25 Mar 2009 18:24:22 -0400 Subject: [PATCH] Build a subobject without recopying the contents --- db/jsobj.h | 22 +++++++++++++++++----- dbtests/jsobjtests.cpp | 28 ++++++++++++++++++++++++++++ util/builder.h | 12 +++++++++--- 3 files changed, 54 insertions(+), 8 deletions(-) diff --git a/db/jsobj.h b/db/jsobj.h index b64535e3ee5..f3399655c63 100644 --- a/db/jsobj.h +++ b/db/jsobj.h @@ -807,13 +807,17 @@ namespace mongo { /** utility for creating a BSONObj */ - class BSONObjBuilder { + 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(initsize), s_( this ) { + BSONObjBuilder(int initsize=512) : b(buf_), buf_(initsize), offset_( 0 ), s_( this ) { b.skip(4); /*leave room for size field*/ } + BSONObjBuilder( BufBuilder &baseBuilder ) : b( baseBuilder ), offset_( baseBuilder.len() ), s_( this ) { + b.skip( 4 ); + } + /** add all the fields from the object specified to this object */ BSONObjBuilder& appendElements(BSONObj x); @@ -837,6 +841,12 @@ namespace mongo { b.append((void *) subObj.objdata(), subObj.objsize()); } + BufBuilder &subobjStart(const char *fieldName) { + b.append((char) Object); + b.append(fieldName); + return b; + } + /** add a subobject as a member with type Array. Thus arr object should have "0", "1", ... style fields in it. */ @@ -1099,12 +1109,14 @@ namespace mongo { char* _done() { s_.endField(); b.append((char) EOO); - char *data = b.buf(); - *((int*)data) = b.len(); + char *data = b.buf() + offset_; + *((int*)data) = b.len() - offset_; return data; } - BufBuilder b; + BufBuilder &b; + BufBuilder buf_; + int offset_; BSONObjBuilderValueStream s_; }; diff --git a/dbtests/jsobjtests.cpp b/dbtests/jsobjtests.cpp index fad6a181e69..39b5c18eacd 100644 --- a/dbtests/jsobjtests.cpp +++ b/dbtests/jsobjtests.cpp @@ -25,6 +25,16 @@ #include "dbtests.h" namespace JsobjTests { + class BufBuilderBasic { + public: + void run() { + BufBuilder b( 0 ); + b.append( "foo" ); + ASSERT_EQUALS( 4, b.len() ); + ASSERT( strcmp( "foo", b.buf() ) == 0 ); + } + }; + class BSONElementBasic { public: void run() { @@ -571,9 +581,26 @@ namespace JsobjTests { } // namespace ValueStreamTests + class SubObjectBuilder { + public: + void run() { + BSONObjBuilder b1; + b1.append( "a", "bcd" ); + BSONObjBuilder b2( b1.subobjStart( "foo" ) ); + b2.append( "ggg", 44.0 ); + b2.done(); + b1.append( "f", 10.0 ); + BSONObj ret = b1.done(); + out() << "ret: " << ret << endl; + ASSERT( ret.valid() ); + ASSERT( ret.woCompare( fromjson( "{a:'bcd',foo:{ggg:44},f:10}" ) ) == 0 ); + } + }; + class All : public UnitTest::Suite { public: All() { + add< BufBuilderBasic >(); add< BSONElementBasic >(); add< BSONObjTests::Create >(); add< BSONObjTests::WoCompareBasic >(); @@ -626,6 +653,7 @@ namespace JsobjTests { add< ValueStreamTests::LabelDoubleShares >(); add< ValueStreamTests::LabelMulti >(); add< ValueStreamTests::Unallowed >(); + add< SubObjectBuilder >(); } }; diff --git a/util/builder.h b/util/builder.h index 85e1c3639e5..08b3237c42c 100644 --- a/util/builder.h +++ b/util/builder.h @@ -27,8 +27,12 @@ namespace mongo { class BufBuilder { public: BufBuilder(int initsize = 512) : size(initsize) { - data = (char *) malloc(size); - assert(data); + if ( size > 0 ) { + data = (char *) malloc(size); + assert(data); + } else { + data = 0; + } l = 0; } ~BufBuilder() { @@ -88,7 +92,7 @@ namespace mongo { append( (void *)str.c_str(), str.length() + 1 ); } - int len() { + int len() const { return l; } @@ -99,6 +103,8 @@ namespace mongo { l += by; if ( l > size ) { int a = size * 2; + if ( a == 0 ) + a = 512; if ( l > a ) a = l + 16 * 1024; assert( a < 64 * 1024 * 1024 );