MongoDB C++ Driver  legacy-1.1.2
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
38  exhaustive 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) {
58  return malloc(sz);
59  }
60  void* Realloc(void* p, size_t sz) {
61  return realloc(p, sz);
62  }
63  void Free(void* p) {
64  free(p);
65  }
66 };
67 
69 public:
70  enum { SZ = 512 };
71  void* Malloc(size_t sz) {
72  if (sz <= SZ)
73  return buf;
74  return malloc(sz);
75  }
76  void* Realloc(void* p, size_t sz) {
77  if (p == buf) {
78  if (sz <= SZ)
79  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 
93 private:
94  char buf[SZ];
95 };
96 
97 template <class Allocator>
98 class _BufBuilder {
99  // non-copyable, non-assignable
100  _BufBuilder(const _BufBuilder&);
101  _BufBuilder& operator=(const _BufBuilder&);
102  Allocator al;
103 
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  } else {
111  data = 0;
112  }
113  l = 0;
114  reservedBytes = 0;
115  }
116  ~_BufBuilder() {
117  kill();
118  }
119 
120  void kill() {
121  if (data) {
122  al.Free(data);
123  data = 0;
124  }
125  }
126 
127  void reset() {
128  l = 0;
129  reservedBytes = 0;
130  }
131  void reset(int maxSize) {
132  l = 0;
133  reservedBytes = 0;
134  if (maxSize && size > maxSize) {
135  al.Free(data);
136  data = (char*)al.Malloc(maxSize);
137  if (data == 0)
138  msgasserted(15913, "out of memory BufBuilder::reset");
139  size = maxSize;
140  }
141  }
142 
147  char* skip(int n) {
148  return grow(n);
149  }
150 
151  /* note this may be deallocated (realloced) if you keep writing. */
152  char* buf() {
153  return data;
154  }
155  const char* buf() const {
156  return data;
157  }
158 
159  /* assume ownership of the buffer - you must then free() it */
160  void decouple() {
161  data = 0;
162  }
163 
164  void appendUChar(unsigned char j) {
165  BOOST_STATIC_ASSERT(CHAR_BIT == 8);
166  appendNumImpl(j);
167  }
168  void appendChar(char j) {
169  appendNumImpl(j);
170  }
171  void appendNum(char j) {
172  appendNumImpl(j);
173  }
174  void appendNum(short j) {
175  BOOST_STATIC_ASSERT(sizeof(short) == 2);
176  appendNumImpl(j);
177  }
178  void appendNum(int j) {
179  BOOST_STATIC_ASSERT(sizeof(int) == 4);
180  appendNumImpl(j);
181  }
182  void appendNum(unsigned j) {
183  appendNumImpl(j);
184  }
185 
186 // Bool does not have a well defined encoding.
187 #if __cplusplus >= 201103L
188  void appendNum(bool j) = delete;
189 #else
190  void appendNum(bool j) {
191  invariant(false);
192  }
193 #endif
194 
195  void appendNum(double j) {
196  BOOST_STATIC_ASSERT(sizeof(double) == 8);
197  appendNumImpl(j);
198  }
199  void appendNum(long long j) {
200  BOOST_STATIC_ASSERT(sizeof(long long) == 8);
201  appendNumImpl(j);
202  }
203  void appendNum(unsigned long long j) {
204  appendNumImpl(j);
205  }
206 
207  void appendBuf(const void* src, size_t len) {
208  memcpy(grow((int)len), src, len);
209  }
210 
211  template <class T>
212  void appendStruct(const T& s) {
213  appendBuf(&s, sizeof(T));
214  }
215 
216  void appendStr(const StringData& str, bool includeEndingNull = true) {
217  const int len = str.size() + (includeEndingNull ? 1 : 0);
218  str.copyTo(grow(len), includeEndingNull);
219  }
220 
222  int len() const {
223  return l;
224  }
225  void setlen(int newLen) {
226  l = newLen;
227  }
229  int getSize() const {
230  return size;
231  }
232 
233  /* returns the pre-grow write position */
234  inline char* grow(int by) {
235  int oldlen = l;
236  int newLen = l + by;
237  int minSize = newLen + reservedBytes;
238  if (minSize > size) {
239  grow_reallocate(minSize);
240  }
241  l = newLen;
242  return data + oldlen;
243  }
244 
248  void reserveBytes(int bytes) {
249  int minSize = l + reservedBytes + bytes;
250  if (minSize > size)
251  grow_reallocate(minSize);
252 
253  // This must happen *after* any attempt to grow.
254  reservedBytes += bytes;
255  }
256 
262  void claimReservedBytes(int bytes) {
263  invariant(reservedBytes >= bytes);
264  reservedBytes -= bytes;
265  }
266 
267 private:
268  template <typename T>
269  void appendNumImpl(T t) {
270  // NOTE: For now, we assume that all things written
271  // by a BufBuilder are intended for external use: either written to disk
272  // or to the wire. Since all of our encoding formats are little endian,
273  // we bake that assumption in here. This decision should be revisited soon.
274  DataView(grow(sizeof(t))).writeLE(t);
275  }
276 
277 
278  /* "slow" portion of 'grow()' */
279  void NOINLINE_DECL grow_reallocate(int minSize) {
280  int a = 64;
281  while (a < minSize)
282  a = a * 2;
283 
284  if (a > BufferMaxSize) {
285  std::stringstream ss;
286  ss << "BufBuilder attempted to grow() to " << a << " bytes, past the 64MB limit.";
287  msgasserted(13548, ss.str().c_str());
288  }
289  data = (char*)al.Realloc(data, a);
290  if (data == NULL)
291  msgasserted(16070, "out of memory BufBuilder::grow_reallocate");
292  size = a;
293  }
294 
295  char* data;
296  int l;
297  int size;
298  int reservedBytes; // eagerly grow_reallocate to keep this many bytes of spare room.
299 
300  friend class StringBuilderImpl<Allocator>;
301 };
302 
303 typedef _BufBuilder<TrivialAllocator> BufBuilder;
304 
312 class StackBufBuilder : public _BufBuilder<StackAllocator> {
313 public:
314  StackBufBuilder() : _BufBuilder<StackAllocator>(StackAllocator::SZ) {}
315  void decouple(); // not allowed. not implemented.
316 };
317 
318 #if defined(_WIN32)
319 #pragma push_macro("snprintf")
320 #define snprintf _snprintf
321 #endif
322 
324 template <typename Allocator>
325 class StringBuilderImpl {
326 public:
327  // Sizes are determined based on the number of characters in 64-bit + the trailing '\0'
328  static const size_t MONGO_DBL_SIZE = 3 + DBL_MANT_DIG - DBL_MIN_EXP + 1;
329  static const size_t MONGO_S32_SIZE = 12;
330  static const size_t MONGO_U32_SIZE = 11;
331  static const size_t MONGO_S64_SIZE = 23;
332  static const size_t MONGO_U64_SIZE = 22;
333  static const size_t MONGO_S16_SIZE = 7;
334  static const size_t MONGO_PTR_SIZE = 19; // Accounts for the 0x prefix
335 
336  StringBuilderImpl() {}
337 
338  StringBuilderImpl& operator<<(double x) {
339  return SBNUM(x, MONGO_DBL_SIZE, "%g");
340  }
341  StringBuilderImpl& operator<<(int x) {
342  return SBNUM(x, MONGO_S32_SIZE, "%d");
343  }
344  StringBuilderImpl& operator<<(unsigned x) {
345  return SBNUM(x, MONGO_U32_SIZE, "%u");
346  }
347  StringBuilderImpl& operator<<(long x) {
348  return SBNUM(x, MONGO_S64_SIZE, "%ld");
349  }
350  StringBuilderImpl& operator<<(unsigned long x) {
351  return SBNUM(x, MONGO_U64_SIZE, "%lu");
352  }
353  StringBuilderImpl& operator<<(long long x) {
354  return SBNUM(x, MONGO_S64_SIZE, "%lld");
355  }
356  StringBuilderImpl& operator<<(unsigned long long x) {
357  return SBNUM(x, MONGO_U64_SIZE, "%llu");
358  }
359  StringBuilderImpl& operator<<(short x) {
360  return SBNUM(x, MONGO_S16_SIZE, "%hd");
361  }
362  StringBuilderImpl& operator<<(const void* x) {
363  if (sizeof(x) == 8) {
364  return SBNUM(x, MONGO_PTR_SIZE, "0x%llX");
365  } else {
366  return SBNUM(x, MONGO_PTR_SIZE, "0x%lX");
367  }
368  }
369  StringBuilderImpl& operator<<(char c) {
370  _buf.grow(1)[0] = c;
371  return *this;
372  }
373  StringBuilderImpl& operator<<(const char* str) {
374  return *this << StringData(str);
375  }
376  StringBuilderImpl& operator<<(const StringData& str) {
377  append(str);
378  return *this;
379  }
380 
381  void appendDoubleNice(double x) {
382  const int prev = _buf.l;
383  const int maxSize = 32;
384  char* start = _buf.grow(maxSize);
385  int z = snprintf(start, maxSize, "%.16g", x);
386  verify(z >= 0);
387  verify(z < maxSize);
388  _buf.l = prev + z;
389  if (strchr(start, '.') == 0 && strchr(start, 'E') == 0 && strchr(start, 'N') == 0) {
390  write(".0", 2);
391  }
392  }
393 
394  void write(const char* buf, int len) {
395  memcpy(_buf.grow(len), buf, len);
396  }
397 
398  void append(const StringData& str) {
399  str.copyTo(_buf.grow(str.size()), false);
400  }
401 
402  void reset(int maxSize = 0) {
403  _buf.reset(maxSize);
404  }
405 
406  std::string str() const {
407  return std::string(_buf.data, _buf.l);
408  }
409 
411  int len() const {
412  return _buf.l;
413  }
414 
415 private:
417 
418  // non-copyable, non-assignable
420  StringBuilderImpl& operator=(const StringBuilderImpl&);
421 
422  template <typename T>
423  StringBuilderImpl& SBNUM(T val, int maxSize, const char* macro) {
424  int prev = _buf.l;
425  int z = snprintf(_buf.grow(maxSize), maxSize, macro, (val));
426  verify(z >= 0);
427  verify(z < maxSize);
428  _buf.l = prev + z;
429  return *this;
430  }
431 };
432 
433 typedef StringBuilderImpl<TrivialAllocator> StringBuilder;
434 typedef StringBuilderImpl<StackAllocator> StackStringBuilder;
435 
436 #if defined(_WIN32)
437 #undef snprintf
438 #pragma pop_macro("snprintf")
439 #endif
440 } // namespace mongo
std::stringstream deals with locale so this is a lot faster than std::stringstream for UTF8 ...
Definition: builder.h:53
Utility functions for parsing numbers from strings.
Definition: compare_numbers.h:20
void claimReservedBytes(int bytes)
Claim an earlier reservation of some number of bytes.
Definition: builder.h:262
void reserveBytes(int bytes)
Reserve room for some number of bytes to be claimed at a later time.
Definition: builder.h:248
char * skip(int n)
leave room for some stuff later
Definition: builder.h:147
Definition: builder.h:68
int getSize() const
Definition: builder.h:229
Definition: builder.h:98
int len() const
size of current string
Definition: builder.h:411
int len() const
Definition: builder.h:222
Definition: data_view.h:71
The StackBufBuilder builds smaller datasets on the stack instead of using malloc. ...
Definition: builder.h:312
Definition: builder.h:55