MongoDB  2.0.3
builder.h
00001 /* 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 #include <string>
00021 #include <string.h>
00022 #include <stdio.h>
00023 #include "../inline_decls.h"
00024 #include "../stringdata.h"
00025 
00026 namespace mongo {
00027 
00028     /* Note the limit here is rather arbitrary and is simply a standard. generally the code works
00029        with any object that fits in ram.
00030 
00031        Also note that the server has some basic checks to enforce this limit but those checks are not exhaustive
00032        for example need to check for size too big after
00033          update $push (append) operation
00034          various db.eval() type operations
00035     */
00036     const int BSONObjMaxUserSize = 16 * 1024 * 1024;
00037 
00038     /*
00039        Sometimeswe we need objects slightly larger - an object in the replication local.oplog
00040        is slightly larger than a user object for example.
00041     */
00042     const int BSONObjMaxInternalSize = BSONObjMaxUserSize + ( 16 * 1024 );
00043 
00044     const int BufferMaxSize = 64 * 1024 * 1024;
00045 
00046     class StringBuilder;
00047 
00048     void msgasserted(int msgid, const char *msg);
00049 
00050     class TrivialAllocator { 
00051     public:
00052         void* Malloc(size_t sz) { return malloc(sz); }
00053         void* Realloc(void *p, size_t sz) { return realloc(p, sz); }
00054         void Free(void *p) { free(p); }
00055     };
00056 
00057     class StackAllocator {
00058     public:
00059         enum { SZ = 512 };
00060         void* Malloc(size_t sz) {
00061             if( sz <= SZ ) return buf;
00062             return malloc(sz); 
00063         }
00064         void* Realloc(void *p, size_t sz) { 
00065             if( p == buf ) {
00066                 if( sz <= SZ ) return buf;
00067                 void *d = malloc(sz);
00068                 if ( d == 0 )
00069                     msgasserted( 15912 , "out of memory StackAllocator::Realloc" );
00070                 memcpy(d, p, SZ);
00071                 return d;
00072             }
00073             return realloc(p, sz); 
00074         }
00075         void Free(void *p) { 
00076             if( p != buf )
00077                 free(p); 
00078         }
00079     private:
00080         char buf[SZ];
00081     };
00082 
00083     template< class Allocator >
00084     class _BufBuilder {
00085         // non-copyable, non-assignable
00086         _BufBuilder( const _BufBuilder& );
00087         _BufBuilder& operator=( const _BufBuilder& );
00088         Allocator al;
00089     public:
00090         _BufBuilder(int initsize = 512) : size(initsize) {
00091             if ( size > 0 ) {
00092                 data = (char *) al.Malloc(size);
00093                 if( data == 0 )
00094                     msgasserted(10000, "out of memory BufBuilder");
00095             }
00096             else {
00097                 data = 0;
00098             }
00099             l = 0;
00100         }
00101         ~_BufBuilder() { kill(); }
00102 
00103         void kill() {
00104             if ( data ) {
00105                 al.Free(data);
00106                 data = 0;
00107             }
00108         }
00109 
00110         void reset() {
00111             l = 0;
00112         }
00113         void reset( int maxSize ) {
00114             l = 0;
00115             if ( maxSize && size > maxSize ) {
00116                 al.Free(data);
00117                 data = (char*)al.Malloc(maxSize);
00118                 if ( data == 0 )
00119                     msgasserted( 15913 , "out of memory BufBuilder::reset" );
00120                 size = maxSize;
00121             }
00122         }
00123 
00127         char* skip(int n) { return grow(n); }
00128 
00129         /* note this may be deallocated (realloced) if you keep writing. */
00130         char* buf() { return data; }
00131         const char* buf() const { return data; }
00132 
00133         /* assume ownership of the buffer - you must then free() it */
00134         void decouple() { data = 0; }
00135 
00136         void appendUChar(unsigned char j) {
00137             *((unsigned char*)grow(sizeof(unsigned char))) = j;
00138         }
00139         void appendChar(char j) {
00140             *((char*)grow(sizeof(char))) = j;
00141         }
00142         void appendNum(char j) {
00143             *((char*)grow(sizeof(char))) = j;
00144         }
00145         void appendNum(short j) {
00146             *((short*)grow(sizeof(short))) = j;
00147         }
00148         void appendNum(int j) {
00149             *((int*)grow(sizeof(int))) = j;
00150         }
00151         void appendNum(unsigned j) {
00152             *((unsigned*)grow(sizeof(unsigned))) = j;
00153         }
00154         void appendNum(bool j) {
00155             *((bool*)grow(sizeof(bool))) = j;
00156         }
00157         void appendNum(double j) {
00158             *((double*)grow(sizeof(double))) = j;
00159         }
00160         void appendNum(long long j) {
00161             *((long long*)grow(sizeof(long long))) = j;
00162         }
00163         void appendNum(unsigned long long j) {
00164             *((unsigned long long*)grow(sizeof(unsigned long long))) = j;
00165         }
00166 
00167         void appendBuf(const void *src, size_t len) {
00168             memcpy(grow((int) len), src, len);
00169         }
00170 
00171         template<class T>
00172         void appendStruct(const T& s) {
00173             appendBuf(&s, sizeof(T));
00174         }
00175 
00176         void appendStr(const StringData &str , bool includeEndingNull = true ) {
00177             const int len = str.size() + ( includeEndingNull ? 1 : 0 );
00178             memcpy(grow(len), str.data(), len);
00179         }
00180 
00182         int len() const { return l; }
00183         void setlen( int newLen ) { l = newLen; }
00185         int getSize() const { return size; }
00186 
00187         /* returns the pre-grow write position */
00188         inline char* grow(int by) {
00189             int oldlen = l;
00190             l += by;
00191             if ( l > size ) {
00192                 grow_reallocate();
00193             }
00194             return data + oldlen;
00195         }
00196 
00197     private:
00198         /* "slow" portion of 'grow()'  */
00199         void NOINLINE_DECL grow_reallocate() {
00200             int a = size * 2;
00201             if ( a == 0 )
00202                 a = 512;
00203             if ( l > a )
00204                 a = l + 16 * 1024;
00205             if ( a > BufferMaxSize )
00206                 msgasserted(13548, "BufBuilder grow() > 64MB");
00207             data = (char *) al.Realloc(data, a);
00208             size= a;
00209         }
00210 
00211         char *data;
00212         int l;
00213         int size;
00214 
00215         friend class StringBuilder;
00216     };
00217 
00218     typedef _BufBuilder<TrivialAllocator> BufBuilder;
00219 
00227     class StackBufBuilder : public _BufBuilder<StackAllocator> { 
00228     public:
00229         StackBufBuilder() : _BufBuilder<StackAllocator>(StackAllocator::SZ) { }
00230         void decouple(); // not allowed. not implemented.
00231     };
00232 
00233 #if defined(_WIN32)
00234 #pragma warning( push )
00235 // warning C4996: 'sprintf': This function or variable may be unsafe. Consider using sprintf_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS.
00236 #pragma warning( disable : 4996 )
00237 #endif
00238 
00240     class StringBuilder {
00241     public:
00242         StringBuilder( int initsize=256 )
00243             : _buf( initsize ) {
00244         }
00245 
00246         StringBuilder& operator<<( double x ) {
00247             return SBNUM( x , 25 , "%g" );
00248         }
00249         StringBuilder& operator<<( int x ) {
00250             return SBNUM( x , 11 , "%d" );
00251         }
00252         StringBuilder& operator<<( unsigned x ) {
00253             return SBNUM( x , 11 , "%u" );
00254         }
00255         StringBuilder& operator<<( long x ) {
00256             return SBNUM( x , 22 , "%ld" );
00257         }
00258         StringBuilder& operator<<( unsigned long x ) {
00259             return SBNUM( x , 22 , "%lu" );
00260         }
00261         StringBuilder& operator<<( long long x ) {
00262             return SBNUM( x , 22 , "%lld" );
00263         }
00264         StringBuilder& operator<<( unsigned long long x ) {
00265             return SBNUM( x , 22 , "%llu" );
00266         }
00267         StringBuilder& operator<<( short x ) {
00268             return SBNUM( x , 8 , "%hd" );
00269         }
00270         StringBuilder& operator<<( char c ) {
00271             _buf.grow( 1 )[0] = c;
00272             return *this;
00273         }
00274 
00275         void appendDoubleNice( double x ) {
00276             int prev = _buf.l;
00277             char * start = _buf.grow( 32 );
00278             int z = sprintf( start , "%.16g" , x );
00279             assert( z >= 0 );
00280             _buf.l = prev + z;
00281             if( strchr(start, '.') == 0 && strchr(start, 'E') == 0 && strchr(start, 'N') == 0 ) {
00282                 write( ".0" , 2 );
00283             }
00284         }
00285 
00286         void write( const char* buf, int len) { memcpy( _buf.grow( len ) , buf , len ); }
00287 
00288         void append( const StringData& str ) { memcpy( _buf.grow( str.size() ) , str.data() , str.size() ); }
00289 
00290         StringBuilder& operator<<( const StringData& str ) {
00291             append( str );
00292             return *this;
00293         }
00294 
00295         void reset( int maxSize = 0 ) { _buf.reset( maxSize ); }
00296 
00297         std::string str() const { return std::string(_buf.data, _buf.l); }
00298         
00299         int len() const { return _buf.l; }
00300 
00301     private:
00302         BufBuilder _buf;
00303 
00304         // non-copyable, non-assignable
00305         StringBuilder( const StringBuilder& );
00306         StringBuilder& operator=( const StringBuilder& );
00307 
00308         template <typename T>
00309         StringBuilder& SBNUM(T val,int maxSize,const char *macro)  {
00310             int prev = _buf.l;
00311             int z = sprintf( _buf.grow(maxSize) , macro , (val) );
00312             assert( z >= 0 );
00313             _buf.l = prev + z;
00314             return *this;
00315         }
00316     };
00317 
00318 #if defined(_WIN32)
00319 #pragma warning( pop )
00320 #endif
00321 
00322 } // namespace mongo