MongoDB  2.6.0
builder.h
1 /* builder.h */
2 
3 /* Copyright 2009 10gen Inc.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 #pragma once
19 
20 #include <cfloat>
21 #include <iostream>
22 #include <sstream>
23 #include <stdio.h>
24 #include <string>
25 #include <string.h>
26 
27 #include "mongo/bson/inline_decls.h"
28 #include "mongo/base/string_data.h"
29 #include "mongo/util/assert_util.h"
30 
31 namespace mongo {
32  /* Accessing unaligned doubles on ARM generates an alignment trap and aborts with SIGBUS on Linux.
33  Wrapping the double in a packed struct forces gcc to generate code that works with unaligned values too.
34  The generated code for other architectures (which already allow unaligned accesses) is the same as if
35  there was a direct pointer access.
36  */
37  struct PackedDouble {
38  double d;
39  } PACKED_DECL;
40 
41 
42  /* Note the limit here is rather arbitrary and is simply a standard. generally the code works
43  with any object that fits in ram.
44 
45  Also note that the server has some basic checks to enforce this limit but those checks are not exhaustive
46  for example need to check for size too big after
47  update $push (append) operation
48  various db.eval() type operations
49  */
50  const int BSONObjMaxUserSize = 16 * 1024 * 1024;
51 
52  /*
53  Sometimes we need objects slightly larger - an object in the replication local.oplog
54  is slightly larger than a user object for example.
55  */
56  const int BSONObjMaxInternalSize = BSONObjMaxUserSize + ( 16 * 1024 );
57 
58  const int BufferMaxSize = 64 * 1024 * 1024;
59 
60  template <typename Allocator>
62 
64  public:
65  void* Malloc(size_t sz) { return malloc(sz); }
66  void* Realloc(void *p, size_t sz) { return realloc(p, sz); }
67  void Free(void *p) { free(p); }
68  };
69 
71  public:
72  enum { SZ = 512 };
73  void* Malloc(size_t sz) {
74  if( sz <= SZ ) return buf;
75  return malloc(sz);
76  }
77  void* Realloc(void *p, size_t sz) {
78  if( p == buf ) {
79  if( sz <= SZ ) return buf;
80  void *d = malloc(sz);
81  if ( d == 0 )
82  msgasserted( 15912 , "out of memory StackAllocator::Realloc" );
83  memcpy(d, p, SZ);
84  return d;
85  }
86  return realloc(p, sz);
87  }
88  void Free(void *p) {
89  if( p != buf )
90  free(p);
91  }
92  private:
93  char buf[SZ];
94  };
95 
96  template< class Allocator >
97  class _BufBuilder {
98  // non-copyable, non-assignable
99  _BufBuilder( const _BufBuilder& );
100  _BufBuilder& operator=( const _BufBuilder& );
101  Allocator al;
102  public:
103  _BufBuilder(int initsize = 512) : size(initsize) {
104  if ( size > 0 ) {
105  data = (char *) al.Malloc(size);
106  if( data == 0 )
107  msgasserted(10000, "out of memory BufBuilder");
108  }
109  else {
110  data = 0;
111  }
112  l = 0;
113  }
114  ~_BufBuilder() { kill(); }
115 
116  void kill() {
117  if ( data ) {
118  al.Free(data);
119  data = 0;
120  }
121  }
122 
123  void reset() {
124  l = 0;
125  }
126  void reset( int maxSize ) {
127  l = 0;
128  if ( maxSize && size > maxSize ) {
129  al.Free(data);
130  data = (char*)al.Malloc(maxSize);
131  if ( data == 0 )
132  msgasserted( 15913 , "out of memory BufBuilder::reset" );
133  size = maxSize;
134  }
135  }
136 
140  char* skip(int n) { return grow(n); }
141 
142  /* note this may be deallocated (realloced) if you keep writing. */
143  char* buf() { return data; }
144  const char* buf() const { return data; }
145 
146  /* assume ownership of the buffer - you must then free() it */
147  void decouple() { data = 0; }
148 
149  void appendUChar(unsigned char j) {
150  *((unsigned char*)grow(sizeof(unsigned char))) = j;
151  }
152  void appendChar(char j) {
153  *((char*)grow(sizeof(char))) = j;
154  }
155  void appendNum(char j) {
156  *((char*)grow(sizeof(char))) = j;
157  }
158  void appendNum(short j) {
159  *((short*)grow(sizeof(short))) = j;
160  }
161  void appendNum(int j) {
162  *((int*)grow(sizeof(int))) = j;
163  }
164  void appendNum(unsigned j) {
165  *((unsigned*)grow(sizeof(unsigned))) = j;
166  }
167  void appendNum(bool j) {
168  *((bool*)grow(sizeof(bool))) = j;
169  }
170  void appendNum(double j) {
171  (reinterpret_cast< PackedDouble* >(grow(sizeof(double))))->d = j;
172  }
173  void appendNum(long long j) {
174  *((long long*)grow(sizeof(long long))) = j;
175  }
176  void appendNum(unsigned long long j) {
177  *((unsigned long long*)grow(sizeof(unsigned long long))) = j;
178  }
179 
180  void appendBuf(const void *src, size_t len) {
181  memcpy(grow((int) len), src, len);
182  }
183 
184  template<class T>
185  void appendStruct(const T& s) {
186  appendBuf(&s, sizeof(T));
187  }
188 
189  void appendStr(const StringData &str , bool includeEndingNull = true ) {
190  const int len = str.size() + ( includeEndingNull ? 1 : 0 );
191  str.copyTo( grow(len), includeEndingNull );
192  }
193 
195  int len() const { return l; }
196  void setlen( int newLen ) { l = newLen; }
198  int getSize() const { return size; }
199 
200  /* returns the pre-grow write position */
201  inline char* grow(int by) {
202  int oldlen = l;
203  int newLen = l + by;
204  if ( newLen > size ) {
205  grow_reallocate(newLen);
206  }
207  l = newLen;
208  return data + oldlen;
209  }
210 
211  private:
212  /* "slow" portion of 'grow()' */
213  void NOINLINE_DECL grow_reallocate(int newLen) {
214  int a = 64;
215  while( a < newLen )
216  a = a * 2;
217  if ( a > BufferMaxSize ) {
218  std::stringstream ss;
219  ss << "BufBuilder attempted to grow() to " << a << " bytes, past the 64MB limit.";
220  msgasserted(13548, ss.str().c_str());
221  }
222  data = (char *) al.Realloc(data, a);
223  if ( data == NULL )
224  msgasserted( 16070 , "out of memory BufBuilder::grow_reallocate" );
225  size = a;
226  }
227 
228  char *data;
229  int l;
230  int size;
231 
232  friend class StringBuilderImpl<Allocator>;
233  };
234 
235  typedef _BufBuilder<TrivialAllocator> BufBuilder;
236 
244  class StackBufBuilder : public _BufBuilder<StackAllocator> {
245  public:
246  StackBufBuilder() : _BufBuilder<StackAllocator>(StackAllocator::SZ) { }
247  void decouple(); // not allowed. not implemented.
248  };
249 
250 #if defined(_WIN32)
251 #pragma push_macro("snprintf")
252 #define snprintf _snprintf
253 #endif
254 
256  template <typename Allocator>
257  class StringBuilderImpl {
258  public:
259  static const size_t MONGO_DBL_SIZE = 3 + DBL_MANT_DIG - DBL_MIN_EXP;
260  static const size_t MONGO_S32_SIZE = 12;
261  static const size_t MONGO_U32_SIZE = 11;
262  static const size_t MONGO_S64_SIZE = 23;
263  static const size_t MONGO_U64_SIZE = 22;
264  static const size_t MONGO_S16_SIZE = 7;
265 
266  StringBuilderImpl() { }
267 
268  StringBuilderImpl& operator<<( double x ) {
269  return SBNUM( x , MONGO_DBL_SIZE , "%g" );
270  }
271  StringBuilderImpl& operator<<( int x ) {
272  return SBNUM( x , MONGO_S32_SIZE , "%d" );
273  }
274  StringBuilderImpl& operator<<( unsigned x ) {
275  return SBNUM( x , MONGO_U32_SIZE , "%u" );
276  }
277  StringBuilderImpl& operator<<( long x ) {
278  return SBNUM( x , MONGO_S64_SIZE , "%ld" );
279  }
280  StringBuilderImpl& operator<<( unsigned long x ) {
281  return SBNUM( x , MONGO_U64_SIZE , "%lu" );
282  }
283  StringBuilderImpl& operator<<( long long x ) {
284  return SBNUM( x , MONGO_S64_SIZE , "%lld" );
285  }
286  StringBuilderImpl& operator<<( unsigned long long x ) {
287  return SBNUM( x , MONGO_U64_SIZE , "%llu" );
288  }
289  StringBuilderImpl& operator<<( short x ) {
290  return SBNUM( x , MONGO_S16_SIZE , "%hd" );
291  }
292  StringBuilderImpl& operator<<( char c ) {
293  _buf.grow( 1 )[0] = c;
294  return *this;
295  }
296 
297  void appendDoubleNice( double x ) {
298  const int prev = _buf.l;
299  const int maxSize = 32;
300  char * start = _buf.grow( maxSize );
301  int z = snprintf( start , maxSize , "%.16g" , x );
302  verify( z >= 0 );
303  verify( z < maxSize );
304  _buf.l = prev + z;
305  if( strchr(start, '.') == 0 && strchr(start, 'E') == 0 && strchr(start, 'N') == 0 ) {
306  write( ".0" , 2 );
307  }
308  }
309 
310  void write( const char* buf, int len) { memcpy( _buf.grow( len ) , buf , len ); }
311 
312  void append( const StringData& str ) { str.copyTo( _buf.grow( str.size() ), false ); }
313 
314  StringBuilderImpl& operator<<( const StringData& str ) {
315  append( str );
316  return *this;
317  }
318 
319  void reset( int maxSize = 0 ) { _buf.reset( maxSize ); }
320 
321  std::string str() const { return std::string(_buf.data, _buf.l); }
322 
324  int len() const { return _buf.l; }
325 
326  private:
328 
329  // non-copyable, non-assignable
331  StringBuilderImpl& operator=( const StringBuilderImpl& );
332 
333  template <typename T>
334  StringBuilderImpl& SBNUM(T val,int maxSize,const char *macro) {
335  int prev = _buf.l;
336  int z = snprintf( _buf.grow(maxSize) , maxSize , macro , (val) );
337  verify( z >= 0 );
338  verify( z < maxSize );
339  _buf.l = prev + z;
340  return *this;
341  }
342  };
343 
344  typedef StringBuilderImpl<TrivialAllocator> StringBuilder;
345  typedef StringBuilderImpl<StackAllocator> StackStringBuilder;
346 
347 #if defined(_WIN32)
348 #undef snprintf
349 #pragma pop_macro("snprintf")
350 #endif
351 } // namespace mongo
int len() const
Definition: builder.h:195
char * skip(int n)
leave room for some stuff later
Definition: builder.h:140
Definition: builder.h:63
Definition: builder.h:37
int getSize() const
Definition: builder.h:198
The StackBufBuilder builds smaller datasets on the stack instead of using malloc. ...
Definition: builder.h:244
Definition: builder.h:97
stringstream deals with locale so this is a lot faster than std::stringstream for UTF8 ...
Definition: builder.h:61
Definition: builder.h:70
int len() const
size of current string
Definition: builder.h:324