MongoDB  1.8.5
embedded_builder.h
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