MongoDB C++ Driver  legacy-1.0.0
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  }
106  ~_BufBuilder() { kill(); }
107 
108  void kill() {
109  if ( data ) {
110  al.Free(data);
111  data = 0;
112  }
113  }
114 
115  void reset() {
116  l = 0;
117  }
118  void reset( int maxSize ) {
119  l = 0;
120  if ( maxSize && size > maxSize ) {
121  al.Free(data);
122  data = (char*)al.Malloc(maxSize);
123  if ( data == 0 )
124  msgasserted( 15913 , "out of memory BufBuilder::reset" );
125  size = maxSize;
126  }
127  }
128 
132  char* skip(int n) { return grow(n); }
133 
134  /* note this may be deallocated (realloced) if you keep writing. */
135  char* buf() { return data; }
136  const char* buf() const { return data; }
137 
138  /* assume ownership of the buffer - you must then free() it */
139  void decouple() { data = 0; }
140 
141  void appendUChar(unsigned char j) {
142  BOOST_STATIC_ASSERT(CHAR_BIT == 8);
143  appendNumImpl(j);
144  }
145  void appendChar(char j) {
146  appendNumImpl(j);
147  }
148  void appendNum(char j) {
149  appendNumImpl(j);
150  }
151  void appendNum(short j) {
152  BOOST_STATIC_ASSERT(sizeof(short) == 2);
153  appendNumImpl(j);
154  }
155  void appendNum(int j) {
156  BOOST_STATIC_ASSERT(sizeof(int) == 4);
157  appendNumImpl(j);
158  }
159  void appendNum(unsigned j) {
160  appendNumImpl(j);
161  }
162 
163  // Bool does not have a well defined encoding.
164 #if __cplusplus >= 201103L
165  void appendNum(bool j) = delete;
166 #else
167  void appendNum(bool j) {
168  invariant(false);
169  }
170 #endif
171 
172  void appendNum(double j) {
173  BOOST_STATIC_ASSERT(sizeof(double) == 8);
174  appendNumImpl(j);
175  }
176  void appendNum(long long j) {
177  BOOST_STATIC_ASSERT(sizeof(long long) == 8);
178  appendNumImpl(j);
179  }
180  void appendNum(unsigned long long j) {
181  appendNumImpl(j);
182  }
183 
184  void appendBuf(const void *src, size_t len) {
185  memcpy(grow((int) len), src, len);
186  }
187 
188  template<class T>
189  void appendStruct(const T& s) {
190  appendBuf(&s, sizeof(T));
191  }
192 
193  void appendStr(const StringData &str , bool includeEndingNull = true ) {
194  const int len = str.size() + ( includeEndingNull ? 1 : 0 );
195  str.copyTo( grow(len), includeEndingNull );
196  }
197 
199  int len() const { return l; }
200  void setlen( int newLen ) { l = newLen; }
202  int getSize() const { return size; }
203 
204  /* returns the pre-grow write position */
205  inline char* grow(int by) {
206  int oldlen = l;
207  int newLen = l + by;
208  if ( newLen > size ) {
209  grow_reallocate(newLen);
210  }
211  l = newLen;
212  return data + oldlen;
213  }
214 
215  private:
216  template<typename T>
217  void appendNumImpl(T t) {
218  // NOTE: For now, we assume that all things written
219  // by a BufBuilder are intended for external use: either written to disk
220  // or to the wire. Since all of our encoding formats are little endian,
221  // we bake that assumption in here. This decision should be revisited soon.
222  DataView(grow(sizeof(t))).writeLE(t);
223  }
224 
225 
226  /* "slow" portion of 'grow()' */
227  void NOINLINE_DECL grow_reallocate(int newLen) {
228  int a = 64;
229  while( a < newLen )
230  a = a * 2;
231  if ( a > BufferMaxSize ) {
232  std::stringstream ss;
233  ss << "BufBuilder attempted to grow() to " << a << " bytes, past the 64MB limit.";
234  msgasserted(13548, ss.str().c_str());
235  }
236  data = (char *) al.Realloc(data, a);
237  if ( data == NULL )
238  msgasserted( 16070 , "out of memory BufBuilder::grow_reallocate" );
239  size = a;
240  }
241 
242  char *data;
243  int l;
244  int size;
245 
246  friend class StringBuilderImpl<Allocator>;
247  };
248 
249  typedef _BufBuilder<TrivialAllocator> BufBuilder;
250 
258  class StackBufBuilder : public _BufBuilder<StackAllocator> {
259  public:
260  StackBufBuilder() : _BufBuilder<StackAllocator>(StackAllocator::SZ) { }
261  void decouple(); // not allowed. not implemented.
262  };
263 
264 #if defined(_WIN32)
265 #pragma push_macro("snprintf")
266 #define snprintf _snprintf
267 #endif
268 
270  template <typename Allocator>
271  class StringBuilderImpl {
272  public:
273  // Sizes are determined based on the number of characters in 64-bit + the trailing '\0'
274  static const size_t MONGO_DBL_SIZE = 3 + DBL_MANT_DIG - DBL_MIN_EXP + 1;
275  static const size_t MONGO_S32_SIZE = 12;
276  static const size_t MONGO_U32_SIZE = 11;
277  static const size_t MONGO_S64_SIZE = 23;
278  static const size_t MONGO_U64_SIZE = 22;
279  static const size_t MONGO_S16_SIZE = 7;
280  static const size_t MONGO_PTR_SIZE = 19; // Accounts for the 0x prefix
281 
282  StringBuilderImpl() { }
283 
284  StringBuilderImpl& operator<<( double x ) {
285  return SBNUM( x , MONGO_DBL_SIZE , "%g" );
286  }
287  StringBuilderImpl& operator<<( int x ) {
288  return SBNUM( x , MONGO_S32_SIZE , "%d" );
289  }
290  StringBuilderImpl& operator<<( unsigned x ) {
291  return SBNUM( x , MONGO_U32_SIZE , "%u" );
292  }
293  StringBuilderImpl& operator<<( long x ) {
294  return SBNUM( x , MONGO_S64_SIZE , "%ld" );
295  }
296  StringBuilderImpl& operator<<( unsigned long x ) {
297  return SBNUM( x , MONGO_U64_SIZE , "%lu" );
298  }
299  StringBuilderImpl& operator<<( long long x ) {
300  return SBNUM( x , MONGO_S64_SIZE , "%lld" );
301  }
302  StringBuilderImpl& operator<<( unsigned long long x ) {
303  return SBNUM( x , MONGO_U64_SIZE , "%llu" );
304  }
305  StringBuilderImpl& operator<<( short x ) {
306  return SBNUM( x , MONGO_S16_SIZE , "%hd" );
307  }
308  StringBuilderImpl& operator<<(const void* x) {
309  if (sizeof(x) == 8) {
310  return SBNUM(x, MONGO_PTR_SIZE, "0x%llX");
311  }
312  else {
313  return SBNUM(x, MONGO_PTR_SIZE, "0x%lX");
314  }
315  }
316  StringBuilderImpl& operator<<( char c ) {
317  _buf.grow( 1 )[0] = c;
318  return *this;
319  }
320  StringBuilderImpl& operator<<(const char* str) {
321  return *this << StringData(str);
322  }
323  StringBuilderImpl& operator<<(const StringData& str) {
324  append(str);
325  return *this;
326  }
327 
328  void appendDoubleNice( double x ) {
329  const int prev = _buf.l;
330  const int maxSize = 32;
331  char * start = _buf.grow( maxSize );
332  int z = snprintf( start , maxSize , "%.16g" , x );
333  verify( z >= 0 );
334  verify( z < maxSize );
335  _buf.l = prev + z;
336  if( strchr(start, '.') == 0 && strchr(start, 'E') == 0 && strchr(start, 'N') == 0 ) {
337  write( ".0" , 2 );
338  }
339  }
340 
341  void write( const char* buf, int len) { memcpy( _buf.grow( len ) , buf , len ); }
342 
343  void append( const StringData& str ) { str.copyTo( _buf.grow( str.size() ), false ); }
344 
345  void reset( int maxSize = 0 ) { _buf.reset( maxSize ); }
346 
347  std::string str() const { return std::string(_buf.data, _buf.l); }
348 
350  int len() const { return _buf.l; }
351 
352  private:
354 
355  // non-copyable, non-assignable
357  StringBuilderImpl& operator=( const StringBuilderImpl& );
358 
359  template <typename T>
360  StringBuilderImpl& SBNUM(T val,int maxSize,const char *macro) {
361  int prev = _buf.l;
362  int z = snprintf( _buf.grow(maxSize) , maxSize , macro , (val) );
363  verify( z >= 0 );
364  verify( z < maxSize );
365  _buf.l = prev + z;
366  return *this;
367  }
368  };
369 
370  typedef StringBuilderImpl<TrivialAllocator> StringBuilder;
371  typedef StringBuilderImpl<StackAllocator> StackStringBuilder;
372 
373 #if defined(_WIN32)
374 #undef snprintf
375 #pragma pop_macro("snprintf")
376 #endif
377 } // 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
char * skip(int n)
leave room for some stuff later
Definition: builder.h:132
Definition: builder.h:62
int getSize() const
Definition: builder.h:202
Definition: builder.h:89
int len() const
size of current string
Definition: builder.h:350
int len() const
Definition: builder.h:199
The StackBufBuilder builds smaller datasets on the stack instead of using malloc. ...
Definition: builder.h:258
Definition: builder.h:55