00001 // embedded_builder.h 00002 00003 /* Copyright 2009 10gen Inc. 00004 * 00005 * Licensed under the Apache License, Version 2.0 (the "License"); 00006 * you may not use this file except in compliance with the License. 00007 * You may obtain a copy of the License at 00008 * 00009 * http://www.apache.org/licenses/LICENSE-2.0 00010 * 00011 * Unless required by applicable law or agreed to in writing, software 00012 * distributed under the License is distributed on an "AS IS" BASIS, 00013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00014 * See the License for the specific language governing permissions and 00015 * limitations under the License. 00016 */ 00017 00018 #pragma once 00019 00020 namespace mongo { 00021 00022 // utility class for assembling hierarchical objects 00023 class EmbeddedBuilder { 00024 public: 00025 EmbeddedBuilder( BSONObjBuilder *b ) { 00026 _builders.push_back( make_pair( "", b ) ); 00027 } 00028 // It is assumed that the calls to prepareContext will be made with the 'name' 00029 // parameter in lex ascending order. 00030 void prepareContext( string &name ) { 00031 int i = 1, n = _builders.size(); 00032 while( i < n && 00033 name.substr( 0, _builders[ i ].first.length() ) == _builders[ i ].first && 00034 ( name[ _builders[i].first.length() ] == '.' || name[ _builders[i].first.length() ] == 0 ) 00035 ) { 00036 name = name.substr( _builders[ i ].first.length() + 1 ); 00037 ++i; 00038 } 00039 for( int j = n - 1; j >= i; --j ) { 00040 popBuilder(); 00041 } 00042 for( string next = splitDot( name ); !next.empty(); next = splitDot( name ) ) { 00043 addBuilder( next ); 00044 } 00045 } 00046 void appendAs( const BSONElement &e, string name ) { 00047 if ( e.type() == Object && e.valuesize() == 5 ) { // empty object -- this way we can add to it later 00048 string dummyName = name + ".foo"; 00049 prepareContext( dummyName ); 00050 return; 00051 } 00052 prepareContext( name ); 00053 back()->appendAs( e, name ); 00054 } 00055 BufBuilder &subarrayStartAs( string name ) { 00056 prepareContext( name ); 00057 return back()->subarrayStart( name ); 00058 } 00059 void done() { 00060 while( ! _builderStorage.empty() ) 00061 popBuilder(); 00062 } 00063 00064 static string splitDot( string & str ) { 00065 size_t pos = str.find( '.' ); 00066 if ( pos == string::npos ) 00067 return ""; 00068 string ret = str.substr( 0, pos ); 00069 str = str.substr( pos + 1 ); 00070 return ret; 00071 } 00072 00073 private: 00074 void addBuilder( const string &name ) { 00075 shared_ptr< BSONObjBuilder > newBuilder( new BSONObjBuilder( back()->subobjStart( name ) ) ); 00076 _builders.push_back( make_pair( name, newBuilder.get() ) ); 00077 _builderStorage.push_back( newBuilder ); 00078 } 00079 void popBuilder() { 00080 back()->done(); 00081 _builders.pop_back(); 00082 _builderStorage.pop_back(); 00083 } 00084 00085 BSONObjBuilder *back() { return _builders.back().second; } 00086 00087 vector< pair< string, BSONObjBuilder * > > _builders; 00088 vector< shared_ptr< BSONObjBuilder > > _builderStorage; 00089 00090 }; 00091 00092 } //namespace mongo