MongoDB C++ Driver  legacy-1.0.5
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
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 <sstream>
22 #include <stdio.h>
23 #include <string>
24 
25 #include <boost/static_assert.hpp>
26 
27 #include "mongo/base/data_view.h"
28 #include "mongo/base/string_data.h"
29 #include "mongo/bson/inline_decls.h"
30 #include "mongo/util/assert_util.h"
31 
32 namespace mongo {
33 
34  /* Note the limit here is rather arbitrary and is simply a standard. generally the code works
35  with any object that fits in ram.
36 
37  Also note that the server has some basic checks to enforce this limit but those checks are not exhaustive
38  for example need to check for size too big after
39  update $push (append) operation
40  various db.eval() type operations
41  */
42  const int BSONObjMaxUserSize = 16 * 1024 * 1024;
43 
44  /*
45  Sometimes we need objects slightly larger - an object in the replication local.oplog
46  is slightly larger than a user object for example.
47  */
48  const int BSONObjMaxInternalSize = BSONObjMaxUserSize + ( 16 * 1024 );
49 
50  const int BufferMaxSize = 64 * 1024 * 1024;
51 
52  template <typename Allocator>
54 
56  public:
57  void* Malloc(size_t sz) { return malloc(sz); }
58  void* Realloc(void *p, size_t sz) { return realloc(p, sz); }
59  void Free(void *p) { free(p); }
60  };
61 
63  public:
64  enum { SZ = 512 };
65  void* Malloc(size_t sz) {
66  if( sz <= SZ ) return buf;
67  return malloc(sz);
68  }
69  void* Realloc(void *p, size_t sz) {
70  if( p == buf ) {
71  if( sz <= SZ ) return buf;
72  void *d = malloc(sz);
73  if ( d == 0 )
74  msgasserted( 15912 , "out of memory StackAllocator::Realloc" );
75  memcpy(d, p, SZ);
76  return d;
77  }
78  return realloc(p, sz);
79  }
80  void Free(void *p) {
81  if( p != buf )
82  free(p);
83  }
84  private:
85  char buf[SZ];
86  };
87 
88  template< class Allocator >
89  class _BufBuilder {
90  // non-copyable, non-assignable
91  _BufBuilder( const _BufBuilder& );
92  _BufBuilder& operator=( const _BufBuilder& );
93  Allocator al;
94  public:
95  _BufBuilder(int initsize = 512) : size(initsize) {
96  if ( size > 0 ) {
97  data = (char *) al.Malloc(size);
98  if( data == 0 )
99  msgasserted(10000, "out of memory BufBuilder");
100  }
101  else {
102  data = 0;
103  }
104  l = 0;
105  reservedBytes = 0;
106  }
107  ~_BufBuilder() { kill(); }
108 
109  void kill() {
110  if ( data ) {
111  al.Free(data);
112  data = 0;
113  }
114  }
115 
116  void reset() {
117  l = 0;
118  reservedBytes = 0;
119  }
120  void reset( int maxSize ) {
121  l = 0;
122  reservedBytes = 0;
123  if ( maxSize && size > maxSize ) {
124  al.Free(data);
125  data = (char*)al.Malloc(maxSize);
126  if ( data == 0 )
127  msgasserted( 15913 , "out of memory BufBuilder::reset" );
128  size = maxSize;
129  }
130  }
131 
135  char* skip(int n) { return grow(n); }
136 
137  /* note this may be deallocated (realloced) if you keep writing. */
138  char* buf() { return data; }
139  const char* buf() const { return data; }
140 
141  /* assume ownership of the buffer - you must then free() it */
142  void decouple() { data = 0; }
143 
144  void appendUChar(unsigned char j) {
145  BOOST_STATIC_ASSERT(CHAR_BIT == 8);
146  appendNumImpl(j);
147  }
148  void appendChar(char j) {
149  appendNumImpl(j);
150  }
151  void appendNum(char j) {
152  appendNumImpl(j);
153  }
154  void appendNum(short j) {
155  BOOST_STATIC_ASSERT(sizeof(short) == 2);
156  appendNumImpl(j);
157  }
158  void appendNum(int j) {
159  BOOST_STATIC_ASSERT(sizeof(int) == 4);
160  appendNumImpl(j);
161  }
162  void appendNum(unsigned j) {
163  appendNumImpl(j);
164  }
165 
166  // Bool does not have a well defined encoding.
167 #if __cplusplus >= 201103L
168  void appendNum(bool j) = delete;
169 #else
170  void appendNum(bool j) {
171  invariant(false);
172  }
173 #endif
174 
175  void appendNum(double j) {
176  BOOST_STATIC_ASSERT(sizeof(double) == 8);
177  appendNumImpl(j);
178  }
179  void appendNum(long long j) {
180  BOOST_STATIC_ASSERT(sizeof(long long) == 8);
181  appendNumImpl(j);
182  }
183  void appendNum(unsigned long long j) {
184  appendNumImpl(j);
185  }
186 
187  void appendBuf(const void *src, size_t len) {
188  memcpy(grow((int) len), src, len);
189  }
190 
191  template<class T>
192  void appendStruct(const T& s) {
193  appendBuf(&s, sizeof(T));
194  }
195 
196  void appendStr(const StringData &str , bool includeEndingNull = true ) {
197  const int len = str.size() + ( includeEndingNull ? 1 : 0 );
198  str.copyTo( grow(len), includeEndingNull );
199  }
200 
202  int len() const { return l; }
203  void setlen( int newLen ) { l = newLen; }
205  int getSize() const { return size; }
206 
207  /* returns the pre-grow write position */
208  inline char* grow(int by) {
209  int oldlen = l;
210  int newLen = l + by;
211  int minSize = newLen + reservedBytes;
212  if ( minSize > size ) {
213  grow_reallocate(minSize);
214  }
215  l = newLen;
216  return data + oldlen;
217  }
218 
222  void reserveBytes(int bytes) {
223  int minSize = l + reservedBytes + bytes;
224  if (minSize > size)
225  grow_reallocate(minSize);
226 
227  // This must happen *after* any attempt to grow.
228  reservedBytes += bytes;
229  }
230 
236  void claimReservedBytes(int bytes) {
237  invariant(reservedBytes >= bytes);
238  reservedBytes -= bytes;
239  }
240 
241  private:
242  template<typename T>
243  void appendNumImpl(T t) {
244  // NOTE: For now, we assume that all things written
245  // by a BufBuilder are intended for external use: either written to disk
246  // or to the wire. Since all of our encoding formats are little endian,
247  // we bake that assumption in here. This decision should be revisited soon.
248  DataView(grow(sizeof(t))).writeLE(t);
249  }
250 
251 
252  /* "slow" portion of 'grow()' */
253  void NOINLINE_DECL grow_reallocate(int minSize) {
254  int a = 64;
255  while (a < minSize)
256  a = a * 2;
257 
258  if ( a > BufferMaxSize ) {
259  std::stringstream ss;
260  ss << "BufBuilder attempted to grow() to " << a << " bytes, past the 64MB limit.";
261  msgasserted(13548, ss.str().c_str());
262  }
263  data = (char *) al.Realloc(data, a);
264  if ( data == NULL )
265  msgasserted( 16070 , "out of memory BufBuilder::grow_reallocate" );
266  size = a;
267  }
268 
269  char *data;
270  int l;
271  int size;
272  int reservedBytes; // eagerly grow_reallocate to keep this many bytes of spare room.
273 
274  friend class StringBuilderImpl<Allocator>;
275  };
276 
277  typedef _BufBuilder<TrivialAllocator> BufBuilder;
278 
286  class StackBufBuilder : public _BufBuilder<StackAllocator> {
287  public:
288  StackBufBuilder() : _BufBuilder<StackAllocator>(StackAllocator::SZ) { }
289  void decouple(); // not allowed. not implemented.
290  };
291 
292 #if defined(_WIN32)
293 #pragma push_macro("snprintf")
294 #define snprintf _snprintf
295 #endif
296 
298  template <typename Allocator>
299  class StringBuilderImpl {
300  public:
301  // Sizes are determined based on the number of characters in 64-bit + the trailing '\0'
302  static const size_t MONGO_DBL_SIZE = 3 + DBL_MANT_DIG - DBL_MIN_EXP + 1;
303  static const size_t MONGO_S32_SIZE = 12;
304  static const size_t MONGO_U32_SIZE = 11;
305  static const size_t MONGO_S64_SIZE = 23;
306  static const size_t MONGO_U64_SIZE = 22;
307  static const size_t MONGO_S16_SIZE = 7;
308  static const size_t MONGO_PTR_SIZE = 19; // Accounts for the 0x prefix
309 
310  StringBuilderImpl() { }
311 
312  StringBuilderImpl& operator<<( double x ) {
313  return SBNUM( x , MONGO_DBL_SIZE , "%g" );
314  }
315  StringBuilderImpl& operator<<( int x ) {
316  return SBNUM( x , MONGO_S32_SIZE , "%d" );
317  }
318  StringBuilderImpl& operator<<( unsigned x ) {
319  return SBNUM( x , MONGO_U32_SIZE , "%u" );
320  }
321  StringBuilderImpl& operator<<( long x ) {
322  return SBNUM( x , MONGO_S64_SIZE , "%ld" );
323  }
324  StringBuilderImpl& operator<<( unsigned long x ) {
325  return SBNUM( x , MONGO_U64_SIZE , "%lu" );
326  }
327  StringBuilderImpl& operator<<( long long x ) {
328  return SBNUM( x , MONGO_S64_SIZE , "%lld" );
329  }
330  StringBuilderImpl& operator<<( unsigned long long x ) {
331  return SBNUM( x , MONGO_U64_SIZE , "%llu" );
332  }
333  StringBuilderImpl& operator<<( short x ) {
334  return SBNUM( x , MONGO_S16_SIZE , "%hd" );
335  }
336  StringBuilderImpl& operator<<(const void* x) {
337  if (sizeof(x) == 8) {
338  return SBNUM(x, MONGO_PTR_SIZE, "0x%llX");
339  }
340  else {
341  return SBNUM(x, MONGO_PTR_SIZE, "0x%lX");
342  }
343  }
344  StringBuilderImpl& operator<<( char c ) {
345  _buf.grow( 1 )[0] = c;
346  return *this;
347  }
348  StringBuilderImpl& operator<<(const char* str) {
349  return *this << StringData(str);
350  }
351  StringBuilderImpl& operator<<(const StringData& str) {
352  append(str);
353  return *this;
354  }
355 
356  void appendDoubleNice( double x ) {
357  const int prev = _buf.l;
358  const int maxSize = 32;
359  char * start = _buf.grow( maxSize );
360  int z = snprintf( start , maxSize , "%.16g" , x );
361  verify( z >= 0 );
362  verify( z < maxSize );
363  _buf.l = prev + z;
364  if( strchr(start, '.') == 0 && strchr(start, 'E') == 0 && strchr(start, 'N') == 0 ) {
365  write( ".0" , 2 );
366  }
367  }
368 
369  void write( const char* buf, int len) { memcpy( _buf.grow( len ) , buf , len ); }
370 
371  void append( const StringData& str ) { str.copyTo( _buf.grow( str.size() ), false ); }
372 
373  void reset( int maxSize = 0 ) { _buf.reset( maxSize ); }
374 
375  std::string str() const { return std::string(_buf.data, _buf.l); }
376 
378  int len() const { return _buf.l; }
379 
380  private:
382 
383  // non-copyable, non-assignable
385  StringBuilderImpl& operator=( const StringBuilderImpl& );
386 
387  template <typename T>
388  StringBuilderImpl& SBNUM(T val,int maxSize,const char *macro) {
389  int prev = _buf.l;
390  int z = snprintf( _buf.grow(maxSize) , maxSize , macro , (val) );
391  verify( z >= 0 );
392  verify( z < maxSize );
393  _buf.l = prev + z;
394  return *this;
395  }
396  };
397 
398  typedef StringBuilderImpl<TrivialAllocator> StringBuilder;
399  typedef StringBuilderImpl<StackAllocator> StackStringBuilder;
400 
401 #if defined(_WIN32)
402 #undef snprintf
403 #pragma pop_macro("snprintf")
404 #endif
405 } // namespace mongo
std::stringstream deals with locale so this is a lot faster than std::stringstream for UTF8 ...
Definition: builder.h:53
the main MongoDB namespace
Definition: bulk_operation_builder.h:24
void claimReservedBytes(int bytes)
Claim an earlier reservation of some number of bytes.
Definition: builder.h:236
void reserveBytes(int bytes)
Reserve room for some number of bytes to be claimed at a later time.
Definition: builder.h:222
char * skip(int n)
leave room for some stuff later
Definition: builder.h:135
Definition: builder.h:62
int getSize() const
Definition: builder.h:205
Definition: builder.h:89
int len() const
size of current string
Definition: builder.h:378
int len() const
Definition: builder.h:202
The StackBufBuilder builds smaller datasets on the stack instead of using malloc. ...
Definition: builder.h:286
Definition: builder.h:55