MongoDB  2.5.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  void msgasserted(int msgid, const char *msg);
61 
62  template <typename Allocator>
64 
66  public:
67  void* Malloc(size_t sz) { return malloc(sz); }
68  void* Realloc(void *p, size_t sz) { return realloc(p, sz); }
69  void Free(void *p) { free(p); }
70  };
71 
73  public:
74  enum { SZ = 512 };
75  void* Malloc(size_t sz) {
76  if( sz <= SZ ) return buf;
77  return malloc(sz);
78  }
79  void* Realloc(void *p, size_t sz) {
80  if( p == buf ) {
81  if( sz <= SZ ) return buf;
82  void *d = malloc(sz);
83  if ( d == 0 )
84  msgasserted( 15912 , "out of memory StackAllocator::Realloc" );
85  memcpy(d, p, SZ);
86  return d;
87  }
88  return realloc(p, sz);
89  }
90  void Free(void *p) {
91  if( p != buf )
92  free(p);
93  }
94  private:
95  char buf[SZ];
96  };
97 
98  template< class Allocator >
99  class _BufBuilder {
100  // non-copyable, non-assignable
101  _BufBuilder( const _BufBuilder& );
102  _BufBuilder& operator=( const _BufBuilder& );
103  Allocator al;
104  public:
105  _BufBuilder(int initsize = 512) : size(initsize) {
106  if ( size > 0 ) {
107  data = (char *) al.Malloc(size);
108  if( data == 0 )
109  msgasserted(10000, "out of memory BufBuilder");
110  }
111  else {
112  data = 0;
113  }
114  l = 0;
115  }
116  ~_BufBuilder() { kill(); }
117 
118  void kill() {
119  if ( data ) {
120  al.Free(data);
121  data = 0;
122  }
123  }
124 
125  void reset() {
126  l = 0;
127  }
128  void reset( int maxSize ) {
129  l = 0;
130  if ( maxSize && size > maxSize ) {
131  al.Free(data);
132  data = (char*)al.Malloc(maxSize);
133  if ( data == 0 )
134  msgasserted( 15913 , "out of memory BufBuilder::reset" );
135  size = maxSize;
136  }
137  }
138 
142  char* skip(int n) { return grow(n); }
143 
144  /* note this may be deallocated (realloced) if you keep writing. */
145  char* buf() { return data; }
146  const char* buf() const { return data; }
147 
148  /* assume ownership of the buffer - you must then free() it */
149  void decouple() { data = 0; }
150 
151  void appendUChar(unsigned char j) {
152  *((unsigned char*)grow(sizeof(unsigned char))) = j;
153  }
154  void appendChar(char j) {
155  *((char*)grow(sizeof(char))) = j;
156  }
157  void appendNum(char j) {
158  *((char*)grow(sizeof(char))) = j;
159  }
160  void appendNum(short j) {
161  *((short*)grow(sizeof(short))) = j;
162  }
163  void appendNum(int j) {
164  *((int*)grow(sizeof(int))) = j;
165  }
166  void appendNum(unsigned j) {
167  *((unsigned*)grow(sizeof(unsigned))) = j;
168  }
169  void appendNum(bool j) {
170  *((bool*)grow(sizeof(bool))) = j;
171  }
172  void appendNum(double j) {
173  (reinterpret_cast< PackedDouble* >(grow(sizeof(double))))->d = j;
174  }
175  void appendNum(long long j) {
176  *((long long*)grow(sizeof(long long))) = j;
177  }
178  void appendNum(unsigned long long j) {
179  *((unsigned long long*)grow(sizeof(unsigned long long))) = j;
180  }
181 
182  void appendBuf(const void *src, size_t len) {
183  memcpy(grow((int) len), src, len);
184  }
185 
186  template<class T>
187  void appendStruct(const T& s) {
188  appendBuf(&s, sizeof(T));
189  }
190 
191  void appendStr(const StringData &str , bool includeEndingNull = true ) {
192  const int len = str.size() + ( includeEndingNull ? 1 : 0 );
193  str.copyTo( grow(len), includeEndingNull );
194  }
195 
197  int len() const { return l; }
198  void setlen( int newLen ) { l = newLen; }
200  int getSize() const { return size; }
201 
202  /* returns the pre-grow write position */
203  inline char* grow(int by) {
204  int oldlen = l;
205  int newLen = l + by;
206  if ( newLen > size ) {
207  grow_reallocate(newLen);
208  }
209  l = newLen;
210  return data + oldlen;
211  }
212 
213  private:
214  /* "slow" portion of 'grow()' */
215  void NOINLINE_DECL grow_reallocate(int newLen) {
216  int a = 64;
217  while( a < newLen )
218  a = a * 2;
219  if ( a > BufferMaxSize ) {
220  std::stringstream ss;
221  ss << "BufBuilder attempted to grow() to " << a << " bytes, past the 64MB limit.";
222  msgasserted(13548, ss.str().c_str());
223  }
224  data = (char *) al.Realloc(data, a);
225  if ( data == NULL )
226  msgasserted( 16070 , "out of memory BufBuilder::grow_reallocate" );
227  size = a;
228  }
229 
230  char *data;
231  int l;
232  int size;
233 
234  friend class StringBuilderImpl<Allocator>;
235  };
236 
237  typedef _BufBuilder<TrivialAllocator> BufBuilder;
238 
246  class StackBufBuilder : public _BufBuilder<StackAllocator> {
247  public:
248  StackBufBuilder() : _BufBuilder<StackAllocator>(StackAllocator::SZ) { }
249  void decouple(); // not allowed. not implemented.
250  };
251 
252 #if defined(_WIN32)
253 #pragma push_macro("snprintf")
254 #define snprintf _snprintf
255 #endif
256 
258  template <typename Allocator>
259  class StringBuilderImpl {
260  public:
261  static const size_t MONGO_DBL_SIZE = 3 + DBL_MANT_DIG - DBL_MIN_EXP;
262  static const size_t MONGO_S32_SIZE = 12;
263  static const size_t MONGO_U32_SIZE = 11;
264  static const size_t MONGO_S64_SIZE = 23;
265  static const size_t MONGO_U64_SIZE = 22;
266  static const size_t MONGO_S16_SIZE = 7;
267 
268  StringBuilderImpl() { }
269 
270  StringBuilderImpl& operator<<( double x ) {
271  return SBNUM( x , MONGO_DBL_SIZE , "%g" );
272  }
273  StringBuilderImpl& operator<<( int x ) {
274  return SBNUM( x , MONGO_S32_SIZE , "%d" );
275  }
276  StringBuilderImpl& operator<<( unsigned x ) {
277  return SBNUM( x , MONGO_U32_SIZE , "%u" );
278  }
279  StringBuilderImpl& operator<<( long x ) {
280  return SBNUM( x , MONGO_S64_SIZE , "%ld" );
281  }
282  StringBuilderImpl& operator<<( unsigned long x ) {
283  return SBNUM( x , MONGO_U64_SIZE , "%lu" );
284  }
285  StringBuilderImpl& operator<<( long long x ) {
286  return SBNUM( x , MONGO_S64_SIZE , "%lld" );
287  }
288  StringBuilderImpl& operator<<( unsigned long long x ) {
289  return SBNUM( x , MONGO_U64_SIZE , "%llu" );
290  }
291  StringBuilderImpl& operator<<( short x ) {
292  return SBNUM( x , MONGO_S16_SIZE , "%hd" );
293  }
294  StringBuilderImpl& operator<<( char c ) {
295  _buf.grow( 1 )[0] = c;
296  return *this;
297  }
298 
299  void appendDoubleNice( double x ) {
300  const int prev = _buf.l;
301  const int maxSize = 32;
302  char * start = _buf.grow( maxSize );
303  int z = snprintf( start , maxSize , "%.16g" , x );
304  verify( z >= 0 );
305  verify( z < maxSize );
306  _buf.l = prev + z;
307  if( strchr(start, '.') == 0 && strchr(start, 'E') == 0 && strchr(start, 'N') == 0 ) {
308  write( ".0" , 2 );
309  }
310  }
311 
312  void write( const char* buf, int len) { memcpy( _buf.grow( len ) , buf , len ); }
313 
314  void append( const StringData& str ) { str.copyTo( _buf.grow( str.size() ), false ); }
315 
316  StringBuilderImpl& operator<<( const StringData& str ) {
317  append( str );
318  return *this;
319  }
320 
321  void reset( int maxSize = 0 ) { _buf.reset( maxSize ); }
322 
323  std::string str() const { return std::string(_buf.data, _buf.l); }
324 
326  int len() const { return _buf.l; }
327 
328  private:
330 
331  // non-copyable, non-assignable
333  StringBuilderImpl& operator=( const StringBuilderImpl& );
334 
335  template <typename T>
336  StringBuilderImpl& SBNUM(T val,int maxSize,const char *macro) {
337  int prev = _buf.l;
338  int z = snprintf( _buf.grow(maxSize) , maxSize , macro , (val) );
339  verify( z >= 0 );
340  verify( z < maxSize );
341  _buf.l = prev + z;
342  return *this;
343  }
344  };
345 
346  typedef StringBuilderImpl<TrivialAllocator> StringBuilder;
347  typedef StringBuilderImpl<StackAllocator> StackStringBuilder;
348 
349 #if defined(_WIN32)
350 #undef snprintf
351 #pragma pop_macro("snprintf")
352 #endif
353 } // namespace mongo